2014-02-21 90 views
1

我正在填充一個ListView與從在線服務提取的數據,它提供頁面中的數據。當用戶在頁面底部附近滾動時,我試圖自動加載下一頁數據,而不是提供「下一頁」按鈕。無盡的滾動ListView

取數據時使用的AsyncTask:

class RecentTracksTask extends AsyncTask<Integer, Void, Void> { 

    ArrayList<Track> recentTracks; 

    @Override 
    protected Void doInBackground(Integer... page) { 
     try { 
      // Get a page of 15 tracks 
      // Simplified - getPage accepts 'page' and 'limit' parameters and returns a Collection<Track> 
      recentTracks = new ArrayList<Track>(getPage(page[0], 15)); 

     } catch() {} 

     return null; 
    } 

    @Override 
    protected void onPostExecute(Void result) { 
      TracksAdapter mTracksAdapter = new TracksAdapter(getActivity(), 
        recentTracks); 

      ListView listView = (ListView) getActivity().findViewById(R.id.listview); 
      listView.setAdapter(mTracksAdapter); 
      listView.setOnScrollListener(new EndlessScrollListener()); 

    } 
} 

和適配器:

class TracksAdapter extends ArrayAdapter<Track> { 
    private final Context context; 
    private final ArrayList<Track> tracks; 

    public TracksAdapter(Context context, 
         ArrayList<Track> recentTrackArrayList) { 
     super(context, 0, recentTrackArrayList); 
     this.context = context; 
     this.tracks = recentTrackArrayList; 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     if (convertView == null) { 
      LayoutInflater inflater = (LayoutInflater) context 
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      convertView = inflater.inflate(R.layout.list_item, 
        parent, false); 
     } 

     final Track track = tracks.get(position); 

     final TextView tv = (TextView) convertView 
       .findViewById(R.id.tv); 
     // Repeat for other views 

     tv.setText(track.getName()); 
     // Repeat for other views 

     return convertView; 
    } 
} 

here,我已經試過這EndlessScrollListener:

class EndlessScrollListener implements AbsListView.OnScrollListener { 

    private int visibleThreshold = 5; 
    private int currentPage = 0; 
    private int previousTotal = 0; 
    private boolean loading = true; 

    public EndlessScrollListener() { 
    } 

    public EndlessScrollListener(int visibleThreshold) { 
     this.visibleThreshold = visibleThreshold; 
    } 

    @Override 
    public void onScroll(AbsListView view, int firstVisibleItem, 
         int visibleItemCount, int totalItemCount) { 
     if (loading) { 
      if (totalItemCount > previousTotal) { 
       loading = false; 
       previousTotal = totalItemCount; 
       currentPage++; 
      } 
     } 
     if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) { 
      // I load the next page of gigs using a background task, 
      // but you can call any function here. 
      new RecentTracksTask().execute(currentPage + 1); 
      loading = true; 
     } 
    } 

    @Override 
    public void onScrollStateChanged(AbsListView view, int scrollState) { 
    } 
} 

我試圖簡化代碼儘可能沒有刪除任何有用的東西,但我知道它仍然是有點長,可以通讀。

在片段的onCreateView中,我調用new RecentTracksTask().execute(1);,它將前15個項目成功加載到ListView中。當在ListView底部附近滾動時,整個內容將被替換爲第二頁,並且視圖返回到列表頂部。重複這只是將我移動到列表的頂部,仍然顯示第二頁。

  • 如何獲取它,以便第n頁的項目插入列表底部而不是替換列表?
  • 如何阻止它將視圖移動到列表頂部?

在此先感謝!

+0

你爲什麼不創建自定義AbstractWindowedCursor和使用SimpleCursorAdapter? – pskink

+0

我對遊標瞭解不多。使用它而不是我的方法的優點是什麼? – Ellis

+0

你不需要AbsListView.OnScrollListener,你只需要實現點播數據 – pskink

回答

5

首先,擺脫EndlessScrollListener。然後,更新您的AsyncTask以獲取數據,將其附加到已在使用的適配器,並通知適配器數據集更改。最後,在您的適配器中,添加一個檢查是否到達列表的末尾並請求下一頁。然而,我應該警告你,如果你在最後一個視圖加載的時候滾動到最後一個視圖,你需要跟蹤你的異步任務,並防止它重新創建。

的AsyncTask

class RecentTracksTask extends AsyncTask<Integer, Void, Void> { 

    ArrayList<Track> recentTracks; 

    @Override 
    protected Void doInBackground(Integer... page) { 
     try { 
      // Get a page of 15 tracks 
      // Simplified - getPage accepts 'page' and 'limit' parameters and returns a Collection<Track> 
      recentTracks = new ArrayList<Track>(getPage(page[0], 15)); 

     } catch() {} 

     return null; 
    } 

    @Override 
    protected void onPostExecute(Void result) { 
     ListView listView = (ListView) getActivity().findViewById(R.id.listview); 
     ArrayAdapter adapter = (ArrayAdapter) listView.getAdapter(); 
     if(adapter == null) { 
      adapter = new TracksAdapter(getActivity(), recentTracks); 
      listView.setAdapter(adapter); 
     } else { 
      adapter.addAll(recentTracks); 
      adapter.notifyDataSetChanged(); 
     } 
    } 
} 

適配器:

class TracksAdapter extends ArrayAdapter<Track> { 
    private final Context context; 
    private final ArrayList<Track> tracks; 
    private int currentPage = 0; 

    public TracksAdapter(Context context, 
         ArrayList<Track> recentTrackArrayList) { 
     super(context, 0, recentTrackArrayList); 
     this.context = context; 
     this.tracks = recentTrackArrayList; 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     if (convertView == null) { 
      LayoutInflater inflater = (LayoutInflater) context 
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      convertView = inflater.inflate(R.layout.list_item, 
        parent, false); 
     } 

     final Track track = tracks.get(position); 

     final TextView tv = (TextView) convertView 
       .findViewById(R.id.tv); 
     // Repeat for other views 

     tv.setText(track.getName()); 
     // Repeat for other views 

     //Check if we're at the end of the list 
     if(position == getCount() - 1) { 
      currentPage++; 
      new RecentTracksTask().execute(currentPage); 
     } 

     return convertView; 
    } 
} 
+0

這行:'ArrayAdapter adapter =(ArrayAdapter)listView.getAdapter();'返回null,所以調用:'adapter.addAll(recentTracks);'產生一個NPE:'java.lang.NullPointerException:嘗試調用虛擬方法'無效的對象引用上的android.widget.ArrayAdapter.addAll(java.util.Collection)' – Ellis

+0

當你在代碼的其他地方創建列表時,你將不得不添加一個適配器。如果你不想這樣做,只需檢查空情況。我會相應地更新答案。 –

+1

啊哈!我認爲你的方式似乎比在其他地方添加適配器更好。另外,'currentPage'需要在適配器中被指定爲1而不是0,否則頁面1被加載兩次。不過,我很困惑你說我需要跟蹤AsyncTask。我的理解是'onPostExecute'總是在'doInBackground'之後執行,更新適配器的代碼全部在'onPostExecute'中。所以,無論何時我可以看到項目,AsyncTask已經完成加載所有數據。當我嘗試滾動得太快時,我似乎無法注意到任何問題。無論如何,感謝您的幫助! – Ellis