Android之ListView原理学习与优化总结

  1. public MyCustomAdapter() {

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

  3. }

  4. public void addItem(final String item) {

  5. mData.add(item);

  6. notifyDataSetChanged();

  7. }

  8. @Override

  9. public int getCount() {

  10. return mData.size();

  11. }

  12. @Override

  13. public String getItem(int position) {

  14. return mData.get(position);

  15. }

  16. @Override

  17. public long getItemId(int position) {

  18. return position;

  19. }

  20. @Override

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

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

  23. ViewHolder holder = null;

  24. if (convertView == null) {

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

  26. holder = new ViewHolder();

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

  28. convertView.setTag(holder);

  29. } else {

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

  31. }

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

  33. return convertView;

  34. }

  35. }

  36. public static class ViewHolder {

  37. public TextView textView;

  38. }

  39. }

执行程序,查看日志:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

此时的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);

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

说一千道一万,不如自己去行动。要想在移动互联网的下半场是自己占有一席之地,那就得从现在开始,从今天开始,马上严格要求自己,既重视业务实现能力,也重视基础和原理。基础夯实好了,高楼才能够平地而起,稳如泰山。

最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的24套腾讯、字节跳动、阿里、百度2020-2021面试真题解析,我把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节

还有 高级架构技术进阶脑图、Android开发面试专题资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

一线互联网面试专题

379页的Android进阶知识大全

379页的Android进阶知识大全

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

转存中…(img-C3CaR3XW-1712546812769)]

[外链图片转存中…(img-MgWqd89e-1712546812769)]

[外链图片转存中…(img-oTI2QUXO-1712546812769)]

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值