在listview中嵌入viewpager帶來的卡頓問題及解決
現在許多應用中都有用到listview和viewpager共存的介面,像知乎日報這樣
當下方的listview滾動時,上面的圖片也會跟著滾動,簡單的來說就是在listview中巢狀一個viewpager,並且將viewpager放在第一個item裡面。
容易遇到的問題
自己第一次嘗試寫這種介面的時候變遇到了一個bug,在我多次對listview進行上下滾動之後(讓viewpager出現,再消失,再出現,迴圈),viewpager的切換出現卡頓,甚至不響應切換的動作,系統也沒有報錯,但這樣是遠遠不能拿來實用的。
問題分析
Listview的中的第一行viewpager因為多次每一次都出現需要重新生成匯入,記憶體不足,而導致出現卡頓的現象。
解決這問題,需要了解listview的原理,網上有張圖很能說明問題
(圖為網上查詢)
從圖中可以看出,listview保持了一個回收器,不可見的檢視會被放在回收器裡面,並不會直接銷燬,當另一個不可見的檢視變成可見的時候,便會從回收期裡將檢視匯出,再次使用。像圖中的例子,整個列表的顯示過程中,我們只需要同時維持7個listitem便可以了,即使有成千上萬個需要顯示。對listview的效能優化也是依據的這個。(listview的優化是充分利用回收機制,和靈活的Holder的使用,這個網上很多,就不細說了)
原理圖中只使用了一種檢視,如果在一個列表中包含多種不同檢視怎麼辦。其實這也是解決我這次問題的關鍵,在Recycler中對回收的檢視都是有按照Type儲存的,在重寫的ListView的介面卡中,我們可以重寫一個方法,getViewTypeCount(),用它來設定Recycler中的Type數量。然後再重寫getItemViewType(int position)來為每個position位置上的item設定自己的檢視type。然後再讓我們來走一下滾動時,檢視轉換流程,向上滾動時消失的檢視將按照type儲存在Recycler的相應位置,然後下方剛出現的item8的convertView便是根據item8的type在Recycler取出的。這樣就能通過按照type區分,實現多種檢視共同快取。
解決方法
將第一行的viewpager和下面的listitem都通過Recycler實現快取,這樣對於viewpager,不是造成每一次都需要重新穿建。
核心程式碼主要是在ListView的重新寫的介面卡中
按照這樣的修改之後,實現的下圖所示的效果,執行起來超級流暢,bug問題完美解決掉了package com.example.listviewtest; import java.util.List; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; public class MyListAdapter extends BaseAdapter{ private static final int TYPE_LISTVIEW = 0; private static final int TYPE_VIEWPAGER = 1; private static final int TYPE_COUNT = 2; private Context mContext; private List<String> list; private View viewPager; public MyListAdapter(Context mContext, List<String> list) { super(); this.mContext = mContext; this.list=list; } @Override public int getCount() { // TODO Auto-generated method stub return list.size()+1; } @Override public Object getItem(int position) { // TODO Auto-generated method stub if (position==0) { return viewPager; } else { return list.get(position-1); } } @Override public long getItemId(int position) { // TODO Auto-generated method stub return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub Holder holder = null; switch(getItemViewType(position)){ case TYPE_LISTVIEW: if(convertView==null){ holder = new Holder(); convertView=LayoutInflater.from(mContext) .inflate(R.layout.list_item, null); holder.tv=(TextView)convertView.findViewById(R.id.tv); convertView.setTag(holder); }else{ holder = (Holder) convertView.getTag(); } break; case TYPE_VIEWPAGER: if(convertView==null){ convertView=viewPager; } return convertView; } if(viewPager!=null){ position--; } holder.tv.setText(list.get(position)); return convertView; } public void setViewPager(View view) { // TODO Auto-generated method stub viewPager=view; } @Override public int getItemViewType(int position) { // TODO Auto-generated method stub if(viewPager!=null){ return position > 0 ? TYPE_LISTVIEW : TYPE_VIEWPAGER; }else{ return TYPE_LISTVIEW; } } @Override public int getViewTypeCount() { // TODO Auto-generated method stub return TYPE_COUNT; } public class Holder { public TextView tv; } }
Demo下載地址http://download.csdn.net/detail/u012568402/8194703點選開啟連結
希望讀者能有所收穫