这两天一直在查listview 和ViewHolder和ConvertView,网上好多都是一篇文章转载n次,现今终于大致的明白一点,写下,待以后补充。
更新:今儿个我去请教了老师,哎呀,不得不说老师就是老师,就是厉害,想了两天也没怎么想明白的东西一下子就明白了,所以说啊,趁着上学,赶紧把不会的问了,希望这个老师不是下一个被我问烦了的人。我都问走了好几个老师了。。。。。唉。。。。。
这个是网上转载次数最多的那篇文章的配的原理图。
下面这个是老师给我画的:
独家原创,此图一出,谁与争锋!之前看了那么多的博客啊,网上的解释说一大堆什么view, convertview,出去的view,进来的view,其实呢,原理相当的简单了!太简单了,我说怎么谷歌的头脑也不至于逆天啊,整的那么复杂,原来是我自己想复杂了。
这是现在的解释:
每向上向下滑动一下,就会有出去的和进来的。你设置了几行信息(item)如果都能显示在屏幕上就正好,如果没有显示在屏幕上就会在你没有看见的那块继续创建,只不过创建的你没有看见而已,。当你往上滑动的时候显示的都是创建的,如果没创建下一条view就不需要创建了,只要复用被划出去的那个view就行,把之前view的值换成新的值。
代码如下:
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<ListView
android:id="@+id/listView1"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true" >
</ListView>
</RelativeLayout>
item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:text="TextView"
android:textColor="#ff0000"
android:textSize="20sp" />
</LinearLayout>
MainActivity.java
package com.example.baseadaptertest;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView=(ListView) findViewById(R.id.listView1);
listView.setAdapter(new myAdapter());
}
class myAdapter extends BaseAdapter{
int count=0;
String[] books=new String[]{"jsp","asp","c#","Embed","English","Math","Chiness"};
@Override
public int getCount() {
return books.length;
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return books[position];
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 第一种方法 每次都重新创建View,每创建一个view都很消耗资源
// View view=View.inflate(getApplicationContext(), R.layout.item,null);
// TextView bookname=(TextView) view.findViewById(R.id.textView1);
// bookname.setText(getItem(position).toString());
// Log.i("getView","create view :"+getItemId(position));
// return view;
//第二种方法 ,只会创建比手机界面种最多能显示的记录的个数多1个的view
//上下滑动之后显示的其它的view都可以复用之前滑出去的那些View,不需要重新创建
if(convertView==null){
View view=View.inflate(getApplicationContext(), R.layout.item,null);
TextView bookname=(TextView) view.findViewById(R.id.textView1);
bookname.setText(getItem(position).toString());
count++;
Log.i("getView","创建第"+count+" 个view :"+getItem(position));
view.setTag(count);//给view一个编号
return view;
}else {
TextView bookname=(TextView) convertView.findViewById(R.id.textView1);
bookname.setText(getItem(position).toString());
Log.i("getView","复用第"+convertView.getTag()+"个 view :"+getItem(position));
return convertView;
}
}
}
}
这个是结果图,动图我不会传,直接传截图。
可以看到复用的和所在的条数的位置是一样的,很显然,这是编译器在开的一个玩笑,其实复用那个view是随机的,这个是碰巧。
这是之前的解释:
现在来解释一下:一个手机屏幕上有第一列那1-7,只要你往上滑一下,1就没了,没了去哪了呢?就去了安卓给的recycle这个回收里了。这个回收是在ConvertView里的。也就是说Item1这个视图(View)已经变成旧的了,就如新袜子一样,穿过了隔一天就是旧的了,view就是新的,隔一天就变成ConvertView(这个旧的了),当然通过回收进行重新纺织还是能变成新的,这是后话 。
ConvertView:android SDK中这样讲参数 convertview :
the old view to reuse, if possible. Note: You should check that this view is non-null and of an appropriate type before using.
If it is not possible to convert this view to display the correct data, this method can create a new view.
翻译:
如果可以的话,这是旧View(视图)的重用。 建议:在用之前,你应该检查这个View是
不是非空,是不是一个合适的类型。
如果不可能让这个VIew去显示一个恰当的数据,这个方法会创建一个新的View。
也就是说这个ConvertView是一个能用就用的旧视图,我们通过往旧视图里添加item(信息)来实现不重复新建新视图。
后来的item8就是用的item1这个旧视图来填充新的数据进行显示的。
这涉及到ViewHolder
ViewHolder:是一个持有者的类,里面没有方法,只有属性,作用就是一个临时的储存器,把每次getView中每次返回的view储存起来,下次再用,不用再每次去布局文件中拿,从而提高了效率。也就是说ViewHolder是一个数据存储器,里面存的是要显示的数据,为的是listview滚动的时候快速设置值,而不必每次都重新创建很多对象,从而提升性能。
通过ConvertView.setTag(ViewHolder)=为视图绑定一个数据,来显示出来。
以上就是我这两天所学到的,可能有的地方理解有误,以后会进行更正和补充。
第一次解释的其实也没啥不对,不过理解不够到位,十分糊涂罢了,getView 返回的是一个view,这个十分的重要。
很感谢能在大学遇到这么好的老师,感谢上苍!
参考:
Android ViewHolder的作用与用法:https://zhidao.baidu.com/question/544207312.html
ListView中convertView和ViewHolder的工作原理:https://blog.youkuaiyun.com/Bill_Ming/article/details/8817172
Android ViewHolder的作用与用法 详解:https://blog.youkuaiyun.com/sky1466181491/article/details/48846985
android adapter中到converView机:https://hunankeda110.iteye.com/blog/1827691
[Android] ListView中getView的原理+如何在ListView中放置多个item:http://www.cnblogs.com/xiaowenji/archive/2010/12/08/1900579.html
convertView.setTag()这个api是不是使得viewholder与convertView同生命周期?:https://www.imooc.com/qadetail/74255
View.setTag()与View.getTag()的作用:http://www.cnblogs.com/qingblog/archive/2012/05/30/2526239.html
Android:ListView之ViewHolder:https://www.cnblogs.com/luoaz/p/3734999.html
Android必学之数据适配器BaseAdapter:https://www.cnblogs.com/caobotao/p/5061627.html