ListView性能优化及加载图片出现图片错位,闪朔等问题的解决
来源:互联网 发布:sql server 2012下载 编辑:程序博客网 时间:2024/05/16 04:56
在开发中ListView是一个用的比较的频繁组件,使用ListView来展示数据,我们一般需要做以下几个步骤:在主布局文件中写ListView组件,设置一些属性,编写一个布局文件用来做为ListView的item,最后写一个适配器来连接ListView和数据。我们对ListView的优化基本上都是在适配器中实现的。
先来说下自定义适配器中复写baseAdapter的几个方法。
//返回数据源中数据的个数,如果该方法的返回值为0,那么适配器就不用生成布局对象了,提高了程序性能 @Override public int getCount() { int count = 0; if(datas!=null) count = datas.size(); return count; } @Override public Object getItem(int position) { // TODO 根据位置返回数据项 return datas.get(position); } @Override public long getItemId(int position) { // TODO 返回数据项的位置 return position; } //返回用来显示每个数据项的布局对象 //参数parent接收的是容器视图对象(在本例中就是ListView对象) //参数position接收的是当前显示的数据项的位置 @Override public View getView(int position, View convertView, ViewGroup parent) { return convertView; }
其中的getView方法是最为重要的。
ListView的优化分为以下几个方面:
- 内存空间上的优化(ConvertView)
- 运行时间的优化(ViewHolder)
ListView的item多布局复用
内存空间上的优化(ConvertView) :
问题:ListView每加载一个item就会创建一个与之对应布局的实例,如果item达到一定的数量时就会出现应用消耗内存太大,使应用出现卡顿的现象。
实例代码:
@Override public View getView(int position, View convertView, ViewGroup parent) { //第一种方式:没有实现布局对象的复用 // TODO 生成显示数据项的布局对象 //根据布局的xml文件生成布局对象 //得到LayoutInflater对象 LayoutInflater inflater = ((Activity)context).getLayoutInflater(); //LayoutInflater对象可以根据布局的xml文件生成布局对象 //第二个参数必须是null,因为如果不是null,会去调用ListView的addView()方法,而ListView没有这个方法 View view = inflater.inflate(resourceId, null); //System.out.println("====="+view); //convertView接收的是可复用的布局对象,当没有可复用的布局对象时,接收的是null //System.out.println("====="+convertView); //把要显示的数据放到布局对象中的TextView上,得到TextView对象 //从整体的布局对象中获取TextView对象 TextView textView = (TextView) view.findViewById(R.id.textView); //给textView的text属性设置为当前显示的数据项 textView.setText(datas.get(position).toString()); return view; }
这样写代码,有多少个item就会创建多个对象。
解决:getview方法给我们提供了convertView参数,其实它就是一个可用的复用对象,如果加载第一屏的数据,没有可以复用的对象,那么这个convertView就是空的,如果它不是空的,那么我们就可以拿来复用,再也不需要创建那么多的布局实例。
实例代码:
//第二种方式: //convertView接收的是可复用的布局对象,当没有可复用的布局对象时,接收的是null //先判断是否有可复用的 if(convertView==null){ //convertView = LayoutInflater.from(context).inflate(resourceId, null); convertView = LayoutInflater.from(context).inflate(resourceId, parent, false); } //得到布局对象中的TextView对象 //每次都要findViewById,影响程序性能 TextView tv = (TextView) convertView.findViewById(R.id.textView); tv.setText(datas.get(position).toString()); return convertView;
运行空间的优化
问题:对于以上的写法,发现在不断的调用findviewbyid方法,这会是应用在运行时受到一定的影响,如果能把这个方法的调用减少,就能提高应用运行的速度。
解决:所以我们设计一个viewholder类来持有一个item布局中的控件,并将其实例化,作为convertview的tag值,用的时候直接在convertview中取就好了,省去了每次都要findviewbyid。
实例代码:
//第三种方式: ViewHolder holder = null; if(convertView ==null){ convertView = LayoutInflater.from(context).inflate(resourceId, parent, false); holder = new ViewHolder(); //让holder中的textView成员指向布局对象中的TextView对象 holder.textView = (TextView) convertView.findViewById(R.id.textView); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag();//当可复用时,直接获取holder } //操作holder中的textView就是操作布局对象中的TextView对象 holder.textView.setText(datas.get(position).toString()); return convertView; } //通过ViewHolder减少findViewById方法执行的次数 class ViewHolder { TextView textView; }
ListView的item多布局复用:
这个已经在上面实现了。
二,加载图片出现图片错位,闪朔等问题的解决
在listview中有大量的图片时,如果处理不好就会出现图片的错位和闪朔等问题,
问题来源分析:
为了优化listview我们复用了convertview,其实问题就出现在这个地方。当item中有图片是我们会异步去加载图片,并展示在相应的位置,但是由于某些原因,图片的加载的速度就不一样的,比如,当你要加载一个item里面有图片,这时你复用了上面的convertview,正好上面的那个item也有一张图片加载,你刚显示这个item时,上一张图片就加载好了,而你的图片却还在加载中,就会先在布局上显示上一张图片,等你的图片加载好后,就立马显示你的图片。这就出先了图片的快速切换,在我们看来就是闪朔。有时还会出现图片位置的错乱。
解决方案:
所以只要解决了,图片可以显示在它指定的那个imageview上面,就ok了。所以我们给imageview设置一个tag可以是图片的url,等图片加载完后就根据tag来找到相应的imageview并显示图片。如果这个imageview已经被复用了,在listview中就找不到了,就不加载图片。这样就解决了问题。
实例代码:
异步任务:
public class DownImageAsyncTask extends AsyncTask<String, Void, Bitmap> { private String path; public DownImageAsyncTask(DownBack mDownBack) { this.mDownBack = mDownBack; } @Override protected Bitmap doInBackground(String... params) { String url = null; if (params != null) { url = params[0]; path = url; try { byte[] bytes = HttpUtils.getByteFromPath(url); Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); return bitmap; } catch (Exception e) { e.printStackTrace(); } } return null; } @Override protected void onPostExecute(Bitmap bitmap) { if (bitmap != null) { if (mDownBack != null) { mDownBack.response(path, bitmap); } } } public interface DownBack { void response(String url, Bitmap bitmap); } private DownBack mDownBack;}
这里定义了个接口给适配器实现,在加载完图片后由异步任务来调用。
getview中的代码:
String imageUrl = Urls.BASE_IMAGE_URL + news.getCover(); iv_image.setTag(imageUrl); iv_image.setImageResource(R.mipmap.ic_launcher); if (imageUrl.length() <= 0) { iv_image.setVisibility(View.GONE); } else { iv_image.setVisibility(View.VISIBLE); SoftReference<Bitmap> soft = mBitmapCache.get(imageUrl); if (soft!=null){ Bitmap bitmap=soft.get(); if (bitmap!=null){ iv_image.setImageBitmap(bitmap); }else{ downImage(imageUrl); } }else { downImage(imageUrl); } }
在这个适配器中为了避免每次都发请求去下载图,我们就用了一个map来保存已经下载好的图片,map的key是图片的url,value是bitmap的一个软应用类型的实例。这样每次可以先判断map中有没有图片,如果有就直接显示,没有就去发请求下载图片。
- ListView性能优化及加载图片出现图片错位,闪朔等问题的解决
- android listview 异步加载图片时出现图片错位、刷新问题的简单解决
- Android ListView加载图片错位的问题
- listview 加载图片 的错位问题
- 【Android】ListView加载网络图片(解决图片错位问题)
- ListView图片加载错位问题
- ListView异步加载图片出现图片错位的解决方案
- listview解决图片错位问题
- android listview 异步加载图片并防止错位及解决ListView滚动后内容重复的问题
- listView异步加载图片导致图片错位、闪烁、重复的问题的解决
- Android ListView图片异步加载时,图片错位的问题
- android开发中解决ListView异步加载图片错位问题
- 解决Android ListView中图片异步加载错位问题
- -------------解决Android ListView中图片异步加载错位问题
- 个人记录1-解决listview异步加载图片错位,滑动listview错乱抖动的问题
- ListView异步加载图片时出现错位的解决方案
- Android ListView异步加载图片错位问题
- Android的ListView异步加载图片时,错位、重复、闪烁问题的分析及解决方法
- 交换机的基本命令
- 地宫取宝 dfs 记忆化搜索 简单dp
- Chrome最新版下载地址
- solr安装和启动
- Manthan, Codefest 16 -B. A Trivial Problem
- ListView性能优化及加载图片出现图片错位,闪朔等问题的解决
- LA 4728 对踵点对
- Struts2中Action接收参数的方法主要有以下三种:
- 学习的一点心得
- 后缀数组suffix模板
- JavaScript调用webservice
- c语言(菜鸟)家常必备(转)
- iOS 中的 NSoperation 多线程
- AppCompat v23.2 — DayNight