Android之ListView原理学习与优化总结,赶紧学起来

  1. setListAdapter(mAdapter);

  2. }

  3. private class MyCustomAdapter extends BaseAdapter {

  4. private ArrayList mData = new ArrayList();

  5. private LayoutInflater mInflater;

  6. public MyCustomAdapter() {

  7. mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);

  8. }

  9. public void addItem(final String item) {

  10. mData.add(item);

  11. notifyDataSetChanged();

  12. }

  13. @Override

  14. public int getCount() {

  15. return mData.size();

  16. }

  17. @Override

  18. public String getItem(int position) {

  19. return mData.get(position);

  20. }

  21. @Override

  22. public long getItemId(int position) {

  23. return position;

  24. }

  25. @Override

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

  27. System.out.println("getView " + position + " " + convertView);

  28. ViewHolder holder = null;

  29. if (convertView == null) {

  30. convertView = mInflater.inflate(R.layout.item1, null);

  31. holder = new ViewHolder();

  32. holder.textView = (TextView)convertView.findViewById(R.id.text);

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

浏览器打开:qq.cn.hn/FTe 开源分享

convertView.setTag(holder);

  1. } else {

  2. holder = (ViewHolder)convertView.getTag();

  3. }

  4. holder.textView.setText(mData.get(position));

  5. return convertView;

  6. }

  7. }

  8. public static class ViewHolder {

  9. public TextView textView;

  10. }

  11. }

执行程序,查看日志:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ATRajP5p-1637385300911)(http://img1.51cto.com/attachment/201206/103104354.png “Android之ListView原理学习与优化总结”)]

getView 被调用 9 次 ,convertView 对于所有的可见项目是空值(如下):

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DpjMCvnW-1637385300947)(http://img1.51cto.com/attachment/201206/103133723.jpg “Android之ListView原理学习与优化总结”)]

然后稍微向下滚动List,直到item10出现:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GDo2QsSe-1637385300948)(http://img1.51cto.com/attachment/201206/103211137.png “Android之ListView原理学习与优化总结”)]

convertView仍然是空值,因为recycler中没有视图(item1的边缘仍然可见,在顶端)再滚动列表,继续滚动:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DCNqqli8-1637385300949)(http://img1.51cto.com/attachment/201206/103243344.png “Android之ListView原理学习与优化总结”)]

convertView不是空值了!item1离开屏幕到Recycler中去了,然后item11被创建,再滚动下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JzXdtyG0-1637385300950)(http://img1.51cto.com/attachment/201206/103322896.jpg “Android之ListView原理学习与优化总结”)]

此时的convertView非空了,在item11离开屏幕之后,它的视图(…0f8)作为convertView容纳item12了,好啦,结合以上原理,下面来看看今天最主要的话题,主角ListView的优化:

首先,这个地方先记两个ListView优化的一个小点:

1. ExpandableListView 与 ListActivity 由官方提供的,里面要使用到的ListView是已经经过优化的ListView,如果大家的需求可以用Google自带的ListView满足的的话尽量用官方的,绝对没错!

2.其次,像小马前面讲的,说ListView优化,其实并不是指其它的优化,就是内存是的优化,提到内存…(想到OOM,折腾了我不少时间),很多很多,先来写下,如果我们的ListView中的选项仅仅是一些简单的TextView的话,就好办啦,消耗不了多少的,但如果你的Item是自定义的Item的话,例如你的自定义Item布局ViewGroup中包含:按钮、图片、flash、CheckBox、RadioButton等一系列你能想到的控件的话, 你要在getView中单单使用文章开头提到的ViewHolder是远远不够的,如果数据过多,加载的图片过多过大,你BitmapFactory.decode的猛多的话,OOM搞死你,这个地方再警告下大家,是警告……….也提醒下自己:

小马碰到的问题大家应该也都碰到过的,自定义的ListView项乱序问题,我很天真的在getView()中强制清除了下ListView的缓存数据convertView,也就是convertView = null了,虽然当时是解决了这个问题让其它每次重绘,但是犯了大错了,如果数据太多的话,出现最最恶心的错,手机卡死或强制关机,关机啊哥哥们……O_O,客户杀了我都有可能,但大家以后别犯这样的错了,单单使用清除缓存convertView是解决不了实际问题的,继续……

下面是小记:图片用完了正确的释放…

  1. if(!bmp.isRecycle() ){

  2. bmp.recycle()   //回收图片所占的内存

  3. system.gc()  //提醒系统及时回收

  4. }

下面来列举下真正意义上的优化吧:


  1. ViewHolder   Tag 必不可少,这个不多说!

  2. **如果自定义Item中有涉及到图片等等的,一定要狠狠的处理图片,图片占的内存是ListView项中最恶心的,处理图片的方法大致有以下几种:

2.1:不要直接拿个路径就去循环decodeFile();这是找死….用Option保存图片大小、不要加载图片到内存去;

2.2:  拿到的图片一定要经过边界压缩

2.3:在ListView中取图片时也不要直接拿个路径去取图片,而是以WeakReference(使用WeakReference代替强引用。比如可以使        用WeakReference mContextRef)、SoftReference、WeakHashMap等的来存储图片信息,是图片信息不是图片哦!

2.4:在getView中做图片转换时,产生的中间变量一定及时释放,用以下形式:**

  1. 尽量避免在BaseAdapter中使用static 来定义全局静态变量,我以为这个没影响 ,这个影响很大,static是Java中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。所以用static修饰的变量,它的生命周期是很长的,如果用它来引用一些资源耗费过多的实例(比如Context的情况最多),这时就要尽量避免使用了…

  2. 如果为了满足需求下必须使用Context的话:Context尽量使用Application Context,因为Application的Context的生命周期比较长,引用它不会出现内存泄露的问题

  3. 尽量避免在ListView适配器中使用线程,因为线程产生内存泄露的主要原因在于线程生命周期的不可控制

  4. **记下小马自己的错误:

之前使用的自定义ListView中适配数据时使用AsyncTask自行开启线程的,这个比用Thread更危险,因为Thread只有在run函数不 结束时才出现这种内存泄露问题,然而AsyncTask内部的实现机制是运用了线程执行池(ThreadPoolExcutor,要想了解这个类的话大家加下我们的Android开发群五号,因为其它群的存储空间快满了,所以只上传到五群里了,看下小马上传的Gallery源码,你会对线程执行池、软、弱、强引用有个更深入的认识),这个类产生的Thread对象的生命周期是不确定的,是应用程序无法控制的,因此如果AsyncTask作为Activity的内部类,就更容易出现内存泄露的问题。这个问题的解决办法小马当时网上查到了记在txt里了,如下:

6.1:将线程的内部类,改为静态内部类。

6.2:在线程内部采用弱引用保存Context引用

示例代码如下:**

    1. public abstract class WeakAsyncTask extends
  1. AsyncTask {

  2. protected WeakReference mTarget;

  3. public WeakAsyncTask(WeakTarget target) {

  4. mTarget = new WeakReference(target);

  5. }

  6. @Override

  7. protected final void onPreExecute() {

  8. final WeakTarget target = mTarget.get();

  9. if (target != null) {

  10. this.onPreExecute(target);

  11. }

  12. }

  13. @Override

  14. protected final Result doInBackground(Params… params) {

  15. final WeakTarget target = mTarget.get();

  16. if (target != null) {

  17. return this.doInBackground(target, params);

  18. } else {

  19. return null;

  20. }

  21. }

  22. @Override

  23. protected final void onPostExecute(Result result) {

  24. final WeakTarget target = mTarget.get();

  25. if (target != null) {

  26. this.onPostExecute(target, result);

  27. }

  28. }

  1. @Override

  2. protected final void onPostExecute(Result result) {

  3. final WeakTarget target = mTarget.get();

  4. if (target != null) {

  5. this.onPostExecute(target, result);

  6. }

  7. }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值