关于adapter中getView()的复用

z_涯 2014-03-28 04:01:12
我现在在做一个聊天软件,这两天遇到个纠结的问题,我的聊天页面是一个ListView,item布局是左右的那种,来消息是在左边,type为2,发出在右边,type为1,如果不复用convertView就时不时的出现OOM,可是现在代码如下,麻烦各位看看是不是我的方法有问题,我在geView的时候有时候可能即使type为1却显示在左边,下面贴出主要的getView代码,中间省略了一些资源设置:
	public View getView(int position, View convertView, ViewGroup parent){

MessageBean mb = mbList.get(position);
ViewHolder holder = null;
View convertView1,convertView2;
if(mb.getType().equalsIgnoreCase("1")){
convertView1 = convertView;
if(convertView1 == null){
convertView1 = vi.inflate(R.layout.list_say_me_item, null);
holder=new ViewHolder();
holder.tvTime = (TextView) convertView1.findViewById(R.id.tv_sendtime);
holder.tvText = (TextView) convertView1.findViewById(R.id.messagedetail_row_text);
holder.layout = (LinearLayout) convertView1.findViewById(R.id.layout_bj);
convertView1.setTag(holder);
}else{
holder = (ViewHolder) convertView1.getTag();
}
convertView = convertView1;
}else if(mb.getType().equalsIgnoreCase("2")){
convertView2 = convertView;
if(convertView2 == null){
convertView2 = vi.inflate(R.layout.list_say_he_item, null);
holder = new ViewHolder();
holder.tvTime = (TextView) convertView2.findViewById(R.id.tv_sendtime);
holder.tvText = (TextView) convertView2.findViewById(R.id.messagedetail_row_text);
holder.layout = (LinearLayout) convertView2.findViewById(R.id.layout_bj);
convertView2.setTag(holder);
}else{
holder = (ViewHolder) convertView2.getTag();
}
convertView = convertView2;
}

return convertView;
}
...全文
313 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
z_涯 2014-03-28
  • 打赏
  • 举报
回复
引用 9 楼 zgt7080 的回复:
 
package com.chat.demo.activity;

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.ImageView;
import android.widget.TextView;

import com.chat.demo.R;

public class ChatMsgViewAdapter extends BaseAdapter {

	public static interface IMsgViewType {
		int IMVT_COM_MSG = 0;
		int IMVT_TO_MSG = 1;
	}

	private static final String TAG = ChatMsgViewAdapter.class.getSimpleName();

	private List<ChatMsgEntity> coll;

	private Context ctx;

	private LayoutInflater mInflater;

	public ChatMsgViewAdapter(Context context, List<ChatMsgEntity> coll) {
		ctx = context;
		this.coll = coll;
		mInflater = LayoutInflater.from(context);
	}

	public int getCount() {
		return coll.size();
	}

	public Object getItem(int position) {
		return coll.get(position);
	}

	public long getItemId(int position) {
		return position;
	}

	public int getItemViewType(int position) {
		// TODO Auto-generated method stub
		ChatMsgEntity entity = coll.get(position);

		if (entity.getMsgType()) {
			return IMsgViewType.IMVT_COM_MSG;
		} else {
			return IMsgViewType.IMVT_TO_MSG;
		}

	}

	public int getViewTypeCount() {
		// TODO Auto-generated method stub
		return 2;
	}

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

		ChatMsgEntity entity = coll.get(position);
		boolean isComMsg = entity.getMsgType();

		ViewHolder viewHolder = null;
		if (convertView == null) {
			if (isComMsg) {
				convertView = mInflater.inflate(
						R.layout.chatting_item_msg_text_left, null);
			} else {
				convertView = mInflater.inflate(
						R.layout.chatting_item_msg_text_right, null);
			}

			viewHolder = new ViewHolder();
			viewHolder.tvSendTime = (TextView) convertView
					.findViewById(R.id.tv_sendtime);
			viewHolder.tvUserName = (TextView) convertView
					.findViewById(R.id.tv_username);
			viewHolder.tvContent = (TextView) convertView
					.findViewById(R.id.tv_chatcontent);
			if (!isComMsg) {
				viewHolder.ivSuc = (ImageView) convertView
						.findViewById(R.id.iv_succ);

			}
			viewHolder.isComMsg = isComMsg;

			convertView.setTag(viewHolder);
		} else {
			viewHolder = (ViewHolder) convertView.getTag();
		}

		viewHolder.tvSendTime.setText(entity.getDate());
		viewHolder.tvUserName.setText(entity.getName());
		viewHolder.tvContent.setText(entity.getText());
		if (!isComMsg) {
			if (!entity.getSucMeg()) {
				viewHolder.ivSuc.setVisibility(View.VISIBLE);
			} else {
				viewHolder.ivSuc.setVisibility(View.GONE);
			}
		}

		return convertView;
	}

	static class ViewHolder {
		public TextView tvSendTime;
		public TextView tvUserName;
		public TextView tvContent;
		public ImageView ivSuc;
		public boolean isComMsg = true;
	}

}



我是这样处理的 希望可以帮助到你
我之前在网上好像又看到过类似的,不知道是不是我用法不对,我这样做拖动快一点还是会OOM,现在已经用了1楼的方法,全写在一个Item里面,暂时好像没什么问题...
  • 打赏
  • 举报
回复
 
package com.chat.demo.activity;

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.ImageView;
import android.widget.TextView;

import com.chat.demo.R;

public class ChatMsgViewAdapter extends BaseAdapter {

	public static interface IMsgViewType {
		int IMVT_COM_MSG = 0;
		int IMVT_TO_MSG = 1;
	}

	private static final String TAG = ChatMsgViewAdapter.class.getSimpleName();

	private List<ChatMsgEntity> coll;

	private Context ctx;

	private LayoutInflater mInflater;

	public ChatMsgViewAdapter(Context context, List<ChatMsgEntity> coll) {
		ctx = context;
		this.coll = coll;
		mInflater = LayoutInflater.from(context);
	}

	public int getCount() {
		return coll.size();
	}

	public Object getItem(int position) {
		return coll.get(position);
	}

	public long getItemId(int position) {
		return position;
	}

	public int getItemViewType(int position) {
		// TODO Auto-generated method stub
		ChatMsgEntity entity = coll.get(position);

		if (entity.getMsgType()) {
			return IMsgViewType.IMVT_COM_MSG;
		} else {
			return IMsgViewType.IMVT_TO_MSG;
		}

	}

	public int getViewTypeCount() {
		// TODO Auto-generated method stub
		return 2;
	}

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

		ChatMsgEntity entity = coll.get(position);
		boolean isComMsg = entity.getMsgType();

		ViewHolder viewHolder = null;
		if (convertView == null) {
			if (isComMsg) {
				convertView = mInflater.inflate(
						R.layout.chatting_item_msg_text_left, null);
			} else {
				convertView = mInflater.inflate(
						R.layout.chatting_item_msg_text_right, null);
			}

			viewHolder = new ViewHolder();
			viewHolder.tvSendTime = (TextView) convertView
					.findViewById(R.id.tv_sendtime);
			viewHolder.tvUserName = (TextView) convertView
					.findViewById(R.id.tv_username);
			viewHolder.tvContent = (TextView) convertView
					.findViewById(R.id.tv_chatcontent);
			if (!isComMsg) {
				viewHolder.ivSuc = (ImageView) convertView
						.findViewById(R.id.iv_succ);

			}
			viewHolder.isComMsg = isComMsg;

			convertView.setTag(viewHolder);
		} else {
			viewHolder = (ViewHolder) convertView.getTag();
		}

		viewHolder.tvSendTime.setText(entity.getDate());
		viewHolder.tvUserName.setText(entity.getName());
		viewHolder.tvContent.setText(entity.getText());
		if (!isComMsg) {
			if (!entity.getSucMeg()) {
				viewHolder.ivSuc.setVisibility(View.VISIBLE);
			} else {
				viewHolder.ivSuc.setVisibility(View.GONE);
			}
		}

		return convertView;
	}

	static class ViewHolder {
		public TextView tvSendTime;
		public TextView tvUserName;
		public TextView tvContent;
		public ImageView ivSuc;
		public boolean isComMsg = true;
	}

}



我是这样处理的 希望可以帮助到你
z_涯 2014-03-28
  • 打赏
  • 举报
回复
引用 7 楼 heaimnmn 的回复:
[quote=引用 6 楼 u012365618 的回复:] [quote=引用 2 楼 cclovescw 的回复:] 看不出这有在复用convertView,convertView是参数传进来的,每次getView都是一个指针不一样的对象,又不是全局变量。 我觉得可以不用View convertView1,convertView2啊,你这么搞的关键点在哪里
汗,发现去掉的效果是一样的,现在得到的ListView滚动一下就变一下,都不知道哪里出问题了[/quote]所以你可以换我种思路呗,我是实现过的,,,[/quote] 好吧,那我现在的item变成三行了,我的时间也是写成一行隐藏起来的
哎,真难 2014-03-28
  • 打赏
  • 举报
回复
引用 6 楼 u012365618 的回复:
[quote=引用 2 楼 cclovescw 的回复:] 看不出这有在复用convertView,convertView是参数传进来的,每次getView都是一个指针不一样的对象,又不是全局变量。 我觉得可以不用View convertView1,convertView2啊,你这么搞的关键点在哪里
汗,发现去掉的效果是一样的,现在得到的ListView滚动一下就变一下,都不知道哪里出问题了[/quote]所以你可以换我种思路呗,我是实现过的,,,
z_涯 2014-03-28
  • 打赏
  • 举报
回复
引用 2 楼 cclovescw 的回复:
看不出这有在复用convertView,convertView是参数传进来的,每次getView都是一个指针不一样的对象,又不是全局变量。 我觉得可以不用View convertView1,convertView2啊,你这么搞的关键点在哪里
汗,发现去掉的效果是一样的,现在得到的ListView滚动一下就变一下,都不知道哪里出问题了
哎,真难 2014-03-28
  • 打赏
  • 举报
回复
引用 4 楼 cclovescw 的回复:
[quote=引用 3 楼 heaimnmn 的回复:] [quote=引用 2 楼 cclovescw 的回复:] 看不出这有在复用convertView,convertView是参数传进来的,每次getView都是一个指针不一样的对象,又不是全局变量。 我觉得可以不用View convertView1,convertView2啊,你这么搞的关键点在哪里
(⊙o⊙)哦,敢问,尊者,什么时候变的版主,,,[/quote] 前几天申请了一下,就过了,你要不也申请个?还有一个名额哦[/quote]我试试,不过我是入门级菜鸟,不一定可以通过
  • 打赏
  • 举报
回复
引用 3 楼 heaimnmn 的回复:
[quote=引用 2 楼 cclovescw 的回复:] 看不出这有在复用convertView,convertView是参数传进来的,每次getView都是一个指针不一样的对象,又不是全局变量。 我觉得可以不用View convertView1,convertView2啊,你这么搞的关键点在哪里
(⊙o⊙)哦,敢问,尊者,什么时候变的版主,,,[/quote] 前几天申请了一下,就过了,你要不也申请个?还有一个名额哦
哎,真难 2014-03-28
  • 打赏
  • 举报
回复
引用 2 楼 cclovescw 的回复:
看不出这有在复用convertView,convertView是参数传进来的,每次getView都是一个指针不一样的对象,又不是全局变量。 我觉得可以不用View convertView1,convertView2啊,你这么搞的关键点在哪里
(⊙o⊙)哦,敢问,尊者,什么时候变的版主,,,
  • 打赏
  • 举报
回复
看不出这有在复用convertView,convertView是参数传进来的,每次getView都是一个指针不一样的对象,又不是全局变量。 我觉得可以不用View convertView1,convertView2啊,你这么搞的关键点在哪里
哎,真难 2014-03-28
  • 打赏
  • 举报
回复
提供一种思路哈,左右并不是根据判断1,2去画的,而是根据1,2,去具体显示,item包含两行,为1的时候,第一行显示,第二行gone,为2的时候,第一行为gone,第二行显示,这就可以了,何必重新getview了
通过封装BaseAdapter和RecyclerView.Adapter得到的通用的,简易的Adapter。项目地址:https://github.com/tianzhijiexian/CommonAdapter 效果图:已解决的问题 提升item的独立性,完美支持item被多处复用 item会根据type来做自动复用 支持多种类型的item 一个item仅会调用一次setViews(),避免重复建立监听器 一个item仅会触发一次绑定视图的操作,提示效率 支持dataBinding和其他第三方注入框架 提供了getView()方法来简化findViewById 支持通过item的构造方法来传入Activity对象 支持通过item的构造方法来传入item事件的回调 提供了getConvertedData(data, type)方法来对item传入的数据做转换,方便拆包和提升item的复用性 支持viewpager的正常加载模式和懒加载 支持快速将listview的适配器切换为recyclerView的适配器 viewpager的notifyDataSetChanged可以正常更新界面 支持recyclerView的添加头部和底部 支持适配器的数据自动绑定,只用操作数据便可,adapter会自动notify界面零、重要接口adapter的item必须实现此接口,接口源码如下:public interface AdapterItem {     /**      * @return item布局文件的layoutId      */     @LayoutRes     int getLayoutResId();     /**      * 初始化views      */     void bindViews(final View root);     /**      * 设置view的参数      */     void setViews();     /**      * 根据数据来设置item的内部views      *      * @param model    数据list内部的model      * @param position 当前adapter调用item的位置      */     void handleData(T model, int position); }例子:public class TextItem implements AdapterItem {     @Override     public int getLayoutResId() {         return R.layout.demo_item_text;     }     TextView textView;     @Override     public void bindViews(View root) {         textView = (TextView) root.findViewById(R.id.textView);     }     @Override     public void setViews() { }     @Override     public void handleData(DemoModel model, int position) {         textView.setText(model.content);     } }一、ListView GridView的通用适配器——CommonAdapter只需继承CommonAdapter便可实现适配器:listView.setAdapter(new CommonAdapter(data, 1) {     public AdapterItem createItem(Object type) {         return new TextItem();     } });二、RecyclerView的通用适配器——CommonRcvAdapter通过继承CommonRcvAdapter来实现适配器:mAdapter = new CommonRcvAdapter(data) {  public AdapterItem createItem(Object type) {         return new TextItem();   } };三、ViewPager的通用适配器——CommonPagerAdapter通过继承CommonPagerAdapter来实现适配器:viewPager.setAdapter(new CommonPagerAdapter() {     public AdapterItem createItem(Object type) {         return new TextItem();     } });设计思路1. Adapter如果用adapter常规写法,你会发现代码量很大,可读性低。如果adapter有多个类型的Item,我们还得在getView()写很多if-else语句,很乱。 而现在我让adapter的代码量减少到一个8行的内部类,如果你需要更换item只需要动一行代码,真正实现了可插拔化。最关键的是item现在作为了一个独立的对象,可以方便的进行复用。2. AdapterItem和原来方式最为不同的一点就是我把adapter的item作为了一个实体,这种方式借鉴了RecyclerViewViewHolder的设计。把item作为实体的好处有很多,比如复用啊,封装啊,其余的就不细说了。3. 分层在使用过程,我发现如果adapter放在view层,那就会影响到view层的独立性。此外adapter经常有很多数据处理的操作,比如通过type选择item,数据的拆包、转换等操作。于是我还是推荐把adapter放在mvp的p层,或者是mvvm的m层。通过在实际的项目使用来看,放在m或p层的效果较好,view复用也比较好做。

80,351

社区成员

发帖
与我相关
我的任务
社区描述
移动平台 Android
androidandroid-studioandroidx 技术论坛(原bbs)
社区管理员
  • Android
  • yechaoa
  • 失落夏天
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧