2013-06-03 11 views
6

Lassen Sie mich damit beginnen, dass dies keine Frage zum Scrollen von ListViews ist. Ich möchte nicht wissen, wie ich feststellen kann, wenn ein Benutzer zum Ende einer Liste scrollt. Geben Sie mir also keine Antworten auf diese Frage oder markieren Sie diese als Duplikat.Sagen Sie Android AsyncTaskLoader, um mehr Daten zu erhalten

Ich verwende eine Klasse, die AsyncTaskLoader erweitert, um ein ListView mit Daten aus einem Webdienst zu füllen.

Zunächst lade ich 50 Artikel und alles funktioniert super. Ich muss wissen, wie ich dem Loader sagen kann, dass er die nächsten 50 Elemente schrittweise laden soll. Ich verstehe, wo dies im ListView-Code zu tun, aber Ich kann nicht herausfinden, die beste Möglichkeit, den Loader, dass ich mehr Daten laden will, ohne es neu zu setzen und alles wieder zu laden.

Noch einmal, um zu verdeutlichen, das Problem, das ich hier zu lösen versuche, ist nur der Loader, dass mehr Daten geladen werden müssen. Es weiß bereits, wie man mehr Daten lädt, wenn loadInBackground() ein zweites Mal aufgerufen wird und der ListView bereits weiß, wo/wann der Loader benachrichtigt werden soll, die Frage ist nur wie.

Einige der entsprechende Code:

@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 Bitte lesen Sie diese Frage. Sie werden feststellen, dass es sich NICHT um ein Duplikat der von Ihnen aufgelisteten Frage handelt. – drewhannay

+0

Weitere Daten müssen für dieselbe Abfragezeichenfolge geladen werden? Jedenfalls würde ich den 'Loader' fallen lassen und eine' AsyncTask' oder einen normalen Thread verwenden, um zusätzliche Daten zu laden. – Luksprog

+1

Aber ist ein Loader nicht der empfohlene Weg zur Bereitstellung von Daten zur Unterstützung eines ListView? Eine AsyncTask verarbeitet keine Konfigurationsänderungen und Loader tun dies. – drewhannay

Antwort

3

dachte ich, einen Ausweg, die funktioniert. In meiner SearchAdapter#getView() Methode habe ich den folgenden Code:

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(); 
     // ... 
    } 
} 

Ich würde noch gerne wissen, ob dies die „best practice“ ist Art und Weise, es zu tun, aber es scheint mein Problem jetzt zu lösen.

+0

Wie erhalten SieLoaderManager() von Ihrem Adapter? – raybaybay

+0

Mein Adapter ist eine innere Klasse in meinem Fragment – drewhannay

+0

Die besten Lösungen sind die einfachsten – Bwire

0

In Ihrem Szenario empfehle ich Ihnen, ForceLoadContentObserver zu verwenden, die Sie mit einem URI an den ContentResolver binden können. Wie folgt aus:

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); 
    } 

    ... 
} 

So können Sie Ihre Änderung überall benachrichtigen, indem Sie:

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

Selbst wenn die Aktivität Halten der Lader im Hintergrund ist oder nicht möglich deliverResult. Und Sie brauchen keine Instanzen von Ladegeräten zu bekommen.

Die ganze Benachrichtigung ist um Uri Objekt. Uri ist eine leistungsstarke Darstellung von Daten in Android.

Aber ich habe auch meine Verwirrung. In diesem Szenario gehen sowohl Ihr Ansatz als auch mein Ansatz davon aus, dass eine Inhaltsänderung bedeutet, dass mehr Daten geladen werden. Aber was, wenn Sie alle Daten neu laden müssen? Welche Art von Benachrichtigung werden Sie verwenden?