2013-06-03 11 views
6

ListViewのスクロールに関する質問ではありません。ユーザーがリストの一番下にスクロールしたときの表示方法を知りたくないので、その質問の回答を私に与えたり、重複していないようにしてください。Android AsyncTaskLoaderにより多くのデータを取得するように教えてください

私はAsyncTaskLoaderを拡張してWebサービスからのデータでListViewを生成するクラスを使用しています。

最初は50個のアイテムを読み込み、すべてがうまく機能しています。ローダーに次の50項目を段階的にロードするように指示する方法を知る必要があります。私はListViewコードでこれを行うには分かりますが、ローダーに、より多くのデータをロードしたいと言う最も良い方法を見つけ出すことはできません。リセットしてすべてを再度ロードする必要はありません。

私がここで解決しようとしている問題は、もっと多くのデータをロードする必要があることをローダーに通知することです。 loadInBackground()が2回目に呼び出されたときにさらにデータをロードする方法を既に知っていて、ListViewはローダに通知する場所と場所をすでに知っています。質問はhowです。

関連するコードの一部:

@Override 
public void onActivityCreated(Bundle savedInstanceState) 
{ 
    super.onActivityCreated(savedInstanceState); 

    m_adapter = new SearchAdapter(getActivity()); 
    setListAdapter(m_adapter); 

    // if the loader doesn't already exist, one will be created 
    // otherwise the existing loader is reused so we don't have 
    // to worry about orientation and other configuration changes 
    getLoaderManager().initLoader(SEARCH_LOADER_ID, null, this); 
} 

@Override 
public Loader<List<Result>> onCreateLoader(int id, Bundle args) 
{ 
    String query = args != null ? args.getString(QUERY_KEY) : ""; 
    return new SearchLoader(getActivity(), query); 
} 

private class SearchAdapter extends ArrayAdapter<Result> 
{ 
    // ... 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) 
    { 

     // ... 

     if (position == getCount() - 2) 
      // TODO: Need to notify Loader here 

     // ... 
    } 
} 

private static class SearchLoader extends OurAsyncTaskLoader<List<Result>> 
{ 
    public SearchLoader(Context context, String query) 
    { 
     super(context); 

     m_query = query; 
     m_data = Lists.newArrayList(); 
     m_loadedAllResults = false; 
    } 

    @Override 
    public List<Result> loadInBackground() 
    { 
     if (m_loadedAllResults) 
      return m_data; 

     // the Loader implementation does a == check rather than a .equals() check 
     // on the data, so we need this to be a new List so that it will know we have 
     // new data 
     m_data = Lists.newArrayList(m_data); 

     MyWebService service = new MyWebService(); 
     List<Result> results = service.getResults(m_query, m_data.size(), COUNT); 
     service.close(); 

     if (results == null) 
      return null; 

     if (results.size() < COUNT) 
      m_loadedAllResults = true; 

     for (Result result : results) 
      m_data.add(result) 

     return m_data; 
    } 

    private static final int COUNT = 50; 

    private final String m_query; 

    private boolean m_loadedAllResults; 
    private List<Result> m_data; 
} 
+0

@GeorgeStockerこの質問をお読みください。それはあなたがリストした質問の重複ではないことがわかります。 – drewhannay

+0

同じクエリ文字列に対して、さらに多くのデータをロードする必要がありますか?とにかく、私は 'Loader'を落として、' AsyncTask'または通常のスレッドを使って追加のデータをロードします。 – Luksprog

+1

しかし、リストビューを戻すためのデータを提供するための推奨方法はありませんか? AsyncTaskは構成の変更を処理せず、ローダーも処理しません。 – drewhannay

答えて

3

私が動作する方法を考え出しました。私のSearchAdapter#getView()方法では、私は次のコードを持っている:

private class SearchAdapter extends ArrayAdapter<Result> 
{ 
    // ... 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) 
    { 

     // ... 

     if (position == getCount() - 2) 
      getLoaderManager().getLoader(SEARCH_LOADER_ID).onContentChanged(); 
     // ... 
    } 
} 

を私はまだ、これはそれを行うための「ベストプラクティス」の方法であるかどうかを知りたいと思い、今の私の問題を解決しているようです。

+0

どのようにアダプタからgetLoaderManager()を行いますか? – raybaybay

+0

私のアダプタは、私のフラグメントの内部クラスです – drewhannay

+0

最も良い解決策は最も簡単です – Bwire

0

あなたのシナリオでは、URIをContentResolverにバインドできるForceLoadContentObserverを使用することをお勧めします。このように:

context.getContentResolver().notifyChanged(Result.BASE_URI, null); 

をローダーを保持する活動がdeliverResultに背景や可能でないにある場合でも:

class SearchLoader .... 
    ForceLoadContentObserver contentObserver = new ForceLoadContentObserver(); 
    .... 

    @Override 
    public void onStartLoading() { 
     if (cacheResult == null || takeContentChanged()) { // This will see if there's a change notification to observer and take it. 
      onForceLoad(); 
     } else { 
      deliverResult(cacheResult); 
     } 
    } 

    @Override 
    public Result loadInBackground() { 
     Result result = loadResult(); 
     // notification uri built upon Result.BASE_URI so it receives all notifications to BASE_URI. 
     getContext().getContentResolver().registerContentObserver(result.getNotificationUri(), true, contentObserver); 
    } 

    @Override 
    public void onReset() { 
     // ... Do your clean stuff... 
     getContext().getContentResolver().unregisterContentObserver(contentObserver); 
    } 

    ... 
} 

だからあなたが使ってどこでも、あなたの変更を通知することができます。また、ローダーのインスタンスを取得する必要はありません。

通知はすべてオブジェクトのウリです。 UriはAndroidの強力なデータ表現です。

しかし、私も混乱しています。このシナリオでは、あなたのアプローチと私のアプローチの両方で、はコンテンツの変更がより多くのデータをロードすることを意味します。しかし、すべてのデータをリロードする必要がある場合はどうすればよいでしょうか?どのような通知を使用しますか?

関連する問題