安卓listView不得不说的那些细节

来源:互联网 发布:网站排名seo 编辑:程序博客网 时间:2024/05/27 01:17

众所周知,ListView是一个在垂直滚动的列表中显示条目的控件,我们在开发ListView中,我们只需要按照如下步骤来操作即可实现ListView

  1. 在xml布局中添加listView控件
  2. 实例化这个控件,
  3. 实现ListAdapter接口给ListView提供数据,绝大多数情况下(说所有的也不过分)只需要继承Android系统提供好的BaseAdapter这个抽象类,并且实现其中的四个抽象方法即可,四个抽象方法分别为:
    a) getCount():返回值代表在ListView中显示的条目数
    b) getItem(int i):返回在i位置上的条目的javaBean对象
    c) getItemId(int i):返回某条目的id
    d)getView(int position, View convertView, ViewGroup viewGroup):告诉listview条目上显示的内容;返回一个View对象作为条目上的内容展示,该方法返回什么样的view,Listview的条目上就显示什么样的view。必须实现。屏幕上每显示一个条目getview方法就会被调用一次;convertView:曾经使用过的view对象,可以被重复使用,使用前要判断。

至于ListView的具体使用,不想赘述,不清楚的同学请自行网补,今天要说的主要是getView方法的一些细节。

首先,正如上文我们提到的一样,getView方法放回一个View对象作为ListView上显示的条目,这个方法返回什么View,那么ListView上就显示什么View,我们不妨先写一个例子

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">        <ListView            android:id="@+id/lv_simple"            android:layout_width="match_parent"            android:layout_height="match_parent">        </ListView></LinearLayout>

很简单,布局中只放了一个ListView控件,布局高度和布局宽度充满父窗口,在看我们的java代码

/** * Created by xdq on 2016/8/23. */public class GetViewActivity extends AppCompatActivity {    private final static String TAG = "TAG";    private Context mContext;    @BindView(R.id.lv_simple)    ListView lvSimple;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_getview);        ButterKnife.bind(this);        mContext = this;        MyAdapter adapter = new MyAdapter();        lvSimple.setAdapter(adapter);    }    class MyAdapter extends BaseAdapter{        private Map<Object,Object> map = new HashMap<>();        @Override        public int getCount() {            return 20;        }        @Override        public Object getItem(int i) {            return null;        }        @Override        public long getItemId(int i) {            return 0;        }        @Override        public View getView(int postion, View covertView, ViewGroup viewGroup) {            TextView view = new TextView(mContext);            map.put(view.hashCode(),"");            Log.i(TAG,"总共创建了:"+map.size()+"个View对象");            view.setText("postion:"+(postion+1));            view.setTextSize(30);            return view;        }    }}

我们在adapter中使用了一个map对象来存放我们getView方法创建的View对象的hashcode,更具map的key的唯一性来获知我们创建了多少个View对象,我们看一下,activity刚启动的时候的结果,
这里写图片描述
可以看到,整个屏幕总共显示出来了13个条目。
接下来我们再看一看log打印
这里写图片描述
我们发现此时一共创建了13个View对象,跟我们屏幕上显示的View条目数一致。(需要注意的是:位置13的条目虽然只显示了一部分,但是这个View对象已经创建了 。不然你又怎么能看到他的一部分呢?。。。。废话。。。)
接下来,我们拖动listView上下滚动,再来看看日志打印的效果。。。
这里写图片描述
omg~~随着我们不断的滚动ListView,我们呢发现getView方法也跟随者被执行,并且在不断的创建新的对象,很显然,这个方式是不科学的,
那么有什么办法改进呢?
文章一开始我们在说getview方法的时候,我们着重强调了convertView这个参数股,google也为我们考虑到了这个问题,所以他给出这个参数用来缓存上一个被隐藏的View对象。
我们修改一下java代码如下:

/** * Created by xdq on 2016/8/23. */public class GetViewActivity extends AppCompatActivity {    private final static String TAG = "TAG";    private Context mContext;    @BindView(R.id.lv_simple)    ListView lvSimple;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_getview);        ButterKnife.bind(this);        mContext = this;        MyAdapter adapter = new MyAdapter();        lvSimple.setAdapter(adapter);    }    class MyAdapter extends BaseAdapter{        private Map<Object,Object> map = new HashMap<>();        @Override        public int getCount() {            return 20;        }        @Override        public Object getItem(int i) {            return null;        }        @Override        public long getItemId(int i) {            return 0;        }        @Override        public View getView(int postion, View covertView, ViewGroup viewGroup) {            TextView view = null;            if (covertView!=null){                view = (TextView) covertView;            }else {                view = new TextView(mContext);            }            map.put(view.hashCode(),"");            Log.i(TAG,"总共创建了:"+map.size()+"个View对象");            Iterator i = map.entrySet().iterator();            while(i.hasNext()){                Object o = i.next();                String key = o.toString();                Log.i(TAG,"键值为"+key);            }            view.setText("postion:"+(postion+1));            view.setTextSize(90);            return view;        }    }}

这里我们复用一下covertView,当然使用前需要做一下非空判断。
我们把textsize设置为90,使得一屏幕显示的条目减少,省得打印太多看不清楚。。。
这个activity刚开始启动时,效果跟上面一样这里不再重复
,接下来我们把listview往下滑动到第一个未显示出来的条目,如下
这里写图片描述
第四个位置的条目已经创建好了。我们看log:
这里写图片描述
红色箭头标识的即为我们第四个条目显示出来的view对象的hashcode同时我们呢看到,此时我们一共创建了四个View对象,接下来我们再滚到到第五个条目,再看log:
这里写图片描述
此时,我们发现getView并没有创建新的View对象,而是开始复用了,看第五个条目的对象的hashcode值正好是与刚刚滚出的第一个条目的hashcode值是一抹一样的,那么也正是我们第五个条目复用了刚刚隐藏的第一个条目的View对象,之后我们无论在怎么滚动ListView我们发现系统维护的对象只有四个了,
这里写图片描述
结论就是当我们采用这个方式复用View的时候,我们只需要维护屏幕显示的条目个数+1个View对象即可,并且每次调用getview的时候,复用的正是刚刚被隐藏的那个view对象,不知道机智的你是否已经看明白了,,那么再让你写个viewholder是否小菜一碟了呢?

ok,就扯这点儿 老鸟勿喷。。。。。

0 0
原创粉丝点击