android listview settag,Android View中setTag的二三事

每一个APP,都离不开View的使用,小到一个登陆注册页面,大到复杂的网上商城,都是View使用的具体体现。

往往我们使用View,其实就是为了向用户展示一定的数据,因此,view的使用又总是离不开数据的。基本很多人的做法都会把数据以及view分开,但是其实在Android开发的view中已经有api接口可以完成一定量数据的存储了,这就是——View.setTag()以及View.getTag()

### 什么是setTag

setTag()是做什么的呢?SDK的解释为:Unlike IDs, tags are not used to identify views. Tags are essentially an extra piece of information that can be associated with a view. They are most often used as a convenience to store data related to views in the views themselves rather than by putting them in a separate structure.

Tag从本质上来讲是就是相关联的view的额外的信息。它们经常用来存储一些view的数据,这样做非常方便而不用存入另外的单独结构。

###setTag的一些使用场景

setTag的这个api其实隐藏的比较的深,甚至在笔者之前学习的基础教程中是完全没有提到过的(好吧,也有可能是我的基础教材选的不好)。我第一次接触这一个api是在自己在尝试的完成自己的课程设计项目时,在项目中使用了**ListView**展示一系列的数据,当时的数据量是比较的大,同时每一个listItem中的view也是比较的复杂,不仅有头像,有用户名,有标题,有内容,甚至是有图片等等。

复杂的view的创建是会比较消耗机器的性能的,大量复杂的view就不用说了。因此我便在寻找方法优化list的时候,接触了setTag().在接触Android开发以来,setTag()使用的最多的场景基本就是ListView,GridView,RecycleView,ViewPage,Gallery啊等等一系列类似用于展示大量重复的View的控件上。*因为这些控件的数据量一般会比较多,例如在夜夜项目中照片瀑布流中,一页就是30张照片,加载十几页就是几百张的图片,如果不对资源加以回收的话,即使是刘威的一加3有6G内存也都不够用~*

因此,这一些控件基本都会对视图判断是否在可视的范围,从而决定回不回收资源。**那么,问题就来了,当被回收的view再一次出现在世人的眼前的时候,机器是不是需要重新绑定数据,重新加载资源,重新绘制view?**问题的答案是肯定的,**当然要!**(都已经被回收了)那么明明已经使用过的view再来一次也要重新开始绘制,那样不是一直在重复同样的动作?**特别是在一些列表或是网格的视图中,明明每一个item都是长得一样的,也是要重复创建?**同样的事,重复的做,那就是在无谓的消耗机器性能了。**因此,我们要做的是让同样的事,只做一次就好!**

通过观察,我们可以发现,其实无论是ListView,GridView,RecycleView,ViewPage,还是Gallery,它们的使用都是离不开adapter,每一个子item的创建也是在adapter中的getView()中完成的,因此,我们**要开刀的就是adapter的getView()**.

在夜夜项目中的经理列表,如下:

61b732f59e3d?mType=Group

![](/content/images/2016/07/726155124686308457.jpg)

每一个itemView的布局都是一样的,都包括了经理头像,名字,常去酒吧,性别,热度,驻场,以及三张小的现场图片。那么,该经理listView的adapter中getView()最正常的写法如下:

61b732f59e3d?mType=Group

![](/content/images/2016/07/----_20160722011238.png)

其实,在itemView相同的情况下,每一次创建itemView的时候都要重复的去绑定控件,须知,项目中R文件中的id可是非常very多的,这样重复的findViewById是很消耗性能的,特别在控件还很多,一个list中的itemView也很多的情况下。那么,我们就要对绑定控件这一部分进行优化。

首先我们通过查询setTag()的源码就可以知道

61b732f59e3d?mType=Group

![](/content/images/2016/07/----_20160722011826.png)

setTag()是把Object对象作为参数对view进行存储的。也就是说,我们要把一个itemView中的控件抽取成一个Object,在此,我们创建了一个ViewHolder

61b732f59e3d?mType=Group

![](/content/images/2016/07/----_20160722012050.png)

然后修改getView()

61b732f59e3d?mType=Group

![](/content/images/2016/07/----_20160722012234.png)

在第一次创建itemView的时候,完成对控件的绑定,同时吧控件作为一个object--holder,把它通过setTag()存到itemView中,再第二次使用的时候就可以通过getTag()把holder取出来直接使用,也就是说,在list中itemView相同的情况下,我们只进行了一次的控件资源绑定。是不是就省了很多?

**这样的方式是适合用所有类似的控件的。包括上文提及的GridView,RecycleView,ViewPage,Gallery等,具体可以自己发挥**

### 那么,问题又来了!

在夜夜项目中开发在线聊天IM的时候,**聊天界面的消息也是由listView实现的,但是,ItemView长得不一样啊???itemView有文本消息的,有图片消息的,也有分享的名片、酒水套餐等,一个ViewHolder根本hold不住了喂!有可能上一次创建的文本消息itemView,这一次却是要图片消息的itemView了!**

其实,这个问题根本**不用担心!!!**我们翻一翻源码又发现,还有这个东西:setTag(key,object)

61b732f59e3d?mType=Group

![](/content/images/2016/07/----_20160722013426.png)

也就说,其实一个view中是可以setTag多个object的,我们只需要在setTag的时候指定key,只有再通过getTag(key)就可以取出相对应的object了,界面再多类型的itemView,再多不同的holder也不怕了呢~

那么我为什么又要拿出来单独说呢?因为**这里面有坑!**

假如你这样子使用:> `converView.setTag("text",textHolder);`

`converView.setTag("pic",picHolder);`

`converView.setTag(100,shareHolder);`

>

那么,恭喜你,你的项目要开始Crash了,开始抛出IllegalArgumentException的问题了~因为在SDK中有这样子说过:>*“ The specified key should be an id declared in the resources of the application to ensure it is unique (see the ID resource type). Keys identified as belonging to the Android framework or not associated with any package will cause an IllegalArgumentExceptionto be thrown.”*

**也就是说你的key必须是唯一的!!!**

那么我们要怎么实现唯一的key呢?其实我们可以把key定义在资源文件中,再由编译器生成对应的,唯一的id!因此我们可以这样写在项目的资源res/values/string.xml中:

61b732f59e3d?mType=Group

![](/content/images/2016/07/----_20160722014903.png)

然后直接:`converView.setTag(R.id.tag_text,textHolder);`

就可以了,取值的时候:`textHolder = converView.getTag(R.id.tag_text);`

然后,你就可以愉快的撸代码啦~

###### 至此,全文基本完!

*edit by: 陈育生*

如果这篇文章又帮到你的话,请点一下‘喜欢’,我会更努力的创作的

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
动态展示数据的ListViewAndroid开发非常常见,以下是一个简单的实现步骤: 1.创建一个ListView控件,可以在xml文件进行创建或者在Java代码动态创建。 2.创建一个适配器,将数据与ListView绑定。适配器需要继承BaseAdapter类,并重写以下四个方法: - getCount():返回ListView的数据项个数。 - getItem():返回指定位置的数据项。 - getItemId():返回指定位置的数据项ID。 - getView():返回指定位置的数据项视图。 3.将适配器设置给ListView控件,调用setAdapter()方法。 4.在适配器getView()方法,可以使用LayoutInflater来加载数据项的布局文件,并将数据填充到布局。 5.在Activity,通过获取数据源并更新适配器来动态展示数据。 下面是一个示例代码: MainActivity.java ``` public class MainActivity extends AppCompatActivity { private ListView mListView; private MyAdapter mAdapter; private List<String> mDataList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initData(); initView(); } private void initData() { mDataList = new ArrayList<>(); for (int i = 0; i < 20; i++) { mDataList.add("Item " + i); } } private void initView() { mListView = findViewById(R.id.list_view); mAdapter = new MyAdapter(); mListView.setAdapter(mAdapter); } private class MyAdapter extends BaseAdapter { @Override public int getCount() { return mDataList.size(); } @Override public Object getItem(int position) { return mDataList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder; if (convertView == null) { convertView = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_list_view, null); viewHolder = new ViewHolder(); viewHolder.mTextView = convertView.findViewById(R.id.text_view); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } String data = mDataList.get(position); viewHolder.mTextView.setText(data); return convertView; } private class ViewHolder { private TextView mTextView; } } } ``` activity_main.xml ``` <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:id="@+id/list_view" android:layout_width="match_parent" android:layout_height="match_parent"/> </RelativeLayout> ``` item_list_view.xml ``` <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" android:textSize="16sp"/> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值