在listview中嵌入viewpager带来的卡顿问题及解决

现在许多应用中都有用到listviewviewpager共存的界面,像知乎日报这样

                                   

当下方的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的重新写的适配器中

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;
	}
}
按照这样的修改之后,实现的下图所示的效果,运行起来超级流畅,bug问题完美解决掉了

Demo下载地址http://download.csdn.net/detail/u012568402/8194703点击打开链接

希望读者能有所收获

                                                    



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值