一、绪论
相信大家在Android开发中肯定会经常用到ListView吧,那么怎么优化ListView呢?尤其是每个item里面中还有图片需要加载,数据源比较多,如果处理不好的话,在滑动ListView的过程中肯定会遇到卡顿的现象,做了这么久的开发,自己多少也摸索到了一些规律,接下来就给大家详细的介绍一下ListView的性能优化。
二、思路:
1.利用ViewHolder
我们自己定义一个ViewHolder,存放我们item中的组件,减少不必要的findViewById(),把我们的控件引用存在里面,利用view.setTag()存放在view里面,下次就可以直接取了。说一下setTag()是干什么用的吧,就是给View一个标签,下次getView()的时候我们可以根据标签获取这个View,如果标签存在了,就不需要再创建了,也就不再需要重新初始化那些组件了。
2.异步加载图片
我们在ListView中异步加载图片,可以使用一些第三方API来加载图片,比较好用的是ImageLoader,Xutils里面的BitmapUtils也可以。
3.设置LitView滑动时禁止加载图片
如果我们在滑动ListView的时候也要加载图片,那么滑动时肯定会卡顿
三、详解:
1.定义ListView
我们先看一下布局,item的每一项内容
- <span style="font-size:14px;"><span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingBottom="@dimen/middler_space"
- android:background="#fff"
- android:id="@+id/llImage"
- >
- <RelativeLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- <ImageView
- android:id="@+id/image"
- android:layout_width="40dp"
- android:layout_height="40dp"
- android:background="#cccccc"
- android:layout_marginLeft="15dp"
- android:adjustViewBounds="true"
- android:scaleType="fitXY"
- android:focusable="false"
- android:layout_marginTop="@dimen/middler_space"
- />
- <ImageView
- android:layout_marginTop="@dimen/middler_space"
- android:id="@+id/iv_filelist_vedio"
- android:src="@drawable/luxiangji"
- android:layout_gravity="left"
- android:visibility="gone"
- android:layout_marginLeft="15dp"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
- </RelativeLayout>
- <LinearLayout
- android:layout_marginTop="@dimen/middler_space"
- android:layout_weight="1"
- android:orientation="vertical"
- android:layout_marginRight="10dp"
- android:layout_width="0dp"
- android:layout_height="wrap_content">
- <TextView
- android:id="@+id/txtText"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="title"
- android:textSize="15dp"
- android:singleLine="true"
- android:textColor="#000"
- android:layout_marginLeft="10dp"
- />
- <LinearLayout
- android:orientation="horizontal"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="content"
- android:textSize="11dp"
- android:layout_marginLeft="10dp"
- android:layout_marginTop="7dp"
- android:textColor="@color/deep_gray"/>
- </LinearLayout>
- </LinearLayout>
- </LinearLayout></span></span>
很简单就是一个titile,一个content,一张图片
2.然后我们自定义Adapter
- <span style="font-size:14px;"><span style="font-size:14px;">package com.yzx.youneed.adapter;
- import android.content.Context;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.BaseAdapter;
- import android.widget.ImageView;
- import android.widget.LinearLayout;
- import android.widget.TextView;
- import com.nostra13.universalimageloader.core.ImageLoader;
- import com.yzx.youneed.R;
- import com.yzx.youneed.model.AppItem_file;
- import java.util.List;
- /**
- * Created by Hankkin on 2015/1/30.
- * imagelist类型适配器
- */
- public class AppImageListAdapter extends BaseAdapter {
- private Context context;
- private List<AppItem_file> data;
- private LayoutInflater inflater;
- public AppImageListAdapter(Context context,List<AppItem_file> data){
- this.data = data;
- this.context = context;
- inflater = LayoutInflater.from(context);
- }
- @Override
- public int getCount() {
- return data.size();
- }
- /**
- * 修改listview首项
- * by Hankkin at:2015-2-15
- * @param i
- * @return
- */
- @Override
- public AppItem_file getItem(int i) {
- if (i<0){
- return null;
- }
- return data.get(i);
- }
- @Override
- public long getItemId(int i) {
- return i;
- }
- @Override
- public View getView(int i, View view, ViewGroup viewGroup) {
- ViewHolder holder = null;
- if (view == null){
- holder= new ViewHolder();
- view = inflater.inflate(R.layout.listview_imagelist,null);
- holder.txtTitle = (TextView) view.findViewById(R.id.txtText);
- holder.image = (ImageView) view.findViewById(R.id.image);
- holder.txtContent = (TextView) view.findViewById(R.id.txtSC);
- view.setTag(holder);
- }else {
- holder = (ViewHolder) view.getTag();
- holder.clean();
- }
- AppItem_file af = data.get(i);
- if (i % 2 == 1) {
- view.setBackgroundResource(R.drawable.list_gray_item1);
- } else {
- view.setBackgroundResource(R.drawable.list_gray_item2);
- }
- holder.txtTitle.setText(af.getTitle());
- holder.txtContent.setText(af.getCreate_time());
- ImageLoader.getInstance().displayImage(af.getThumbnail(),holder.image);
- return view;
- }
- public final class ViewHolder{
- public TextView txtTitle,txtContent;
- public ImageView image;
- void clean(){
- txtTitle.setText(null);
- txtContent.setText(null);
- image.setImageBitmap(null);
- }
- }
- }</span></span>
加载图片我们用的是
服务器获取数据之后添加到List中更新我们的适配器就ok了,这时候我们的ListView就已经有数据了。
只需要简单的这么一句话就搞定,是不是很方便?
这里面有加载图片失败的设置,默认图片的设置,延迟加载设置,以及缓存陌路设置等等,这里就不详细介绍了,一般这个方法基本的配置都有了,大家可以直接拷到你的项目中直接用,可以在application里面初始化Imageloader。如果大家想要详细的了解Imageloader框架的话可以看看
这句话也就是ImageLoader的异步加载图片,只需要传进去两个参数,第一个是图片url,第二个是ImageView控件,ImageLoader会自动给我们缓存图片的,如果之前加载过了是不会再次下载图片,直接加载本地缓存好的图片。至于ImageLoader的一些配置信息,包括默认图片,缓存地址等会在下面介绍。
- <span style="font-size:14px;"><span style="font-size:18px;">ImageLoader.getInstance().displayImage(af.getThumbnail(),holder.image);</span></span>
3.接下来我们看一下怎么在我们的Activity中访问服务器获取信息
因为项目里面用的是Xutils的HttpUtils,所以访问服务器我就用它了,只是给大家举个例子
- <span style="font-size:14px;"><span style="font-size:14px;">public void asyncQF(boolean url1) {
- RequestParams params = new RequestParams();
- params.addBodyParameter("flag",file_group.getFlag());
- HttpUtils http = new HttpUtils();
- http.send(HttpRequest.HttpMethod.POST, "", new RequestCallBack<String>() {
- @Override
- public void onSuccess(ResponseInfo<String> responseInfo) {
- //ToDo:
- //添加数据源,更新适配器
- }
- @Override
- public void onFailure(HttpException error, String msg) {
- //ToDo:
- //更新UI
- }
- });
- }</span></span>
服务器获取数据之后添加到List中更新我们的适配器就ok了,这时候我们的ListView就已经有数据了。
最后我们还可以设置ListView滑动时不加载图片
4.设置滑动不加载图片
ImageLoader已经给我们封装好了方法,我们只需要设置一下ListView滑动监听就可以了,看一下代码:
- <span style="font-size:14px;"><span style="font-size:18px;"> lv_appImageList.setOnScrollListener(new PauseOnScrollListener(ImageLoader.getInstance(),false,true));</span>
- </span>
只需要简单的这么一句话就搞定,是不是很方便?
四、ImageLoader配置
- <span style="font-size:14px;"><span style="font-size:14px;">public static void initImageLoader(Context context) {
- personOptions = new DisplayImageOptions.Builder()
- .showImageOnFail(R.drawable.usericon)
- .showImageForEmptyUri(R.drawable.usericon)
- .resetViewBeforeLoading(false) // default
- .delayBeforeLoading(0)
- .cacheInMemory(true) // default
- .cacheOnDisk(true) // default
- .considerExifParams(true) // default
- .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default
- .bitmapConfig(Bitmap.Config.ARGB_8888) // default
- .displayer(new SimpleBitmapDisplayer()) // default
- .handler(new Handler()) // default
- .build();
- DisplayImageOptions options = new DisplayImageOptions.Builder()
- .showImageOnLoading(R.drawable.download)
- // .showImageOnFail(R.drawable.img_fail)
- .resetViewBeforeLoading(false) // default
- .delayBeforeLoading(0)
- .cacheInMemory(true) // default
- .cacheOnDisk(true) // default
- .considerExifParams(true) // default
- .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default
- .bitmapConfig(Bitmap.Config.ARGB_8888) // default
- .displayer(new SimpleBitmapDisplayer()) // default
- .handler(new Handler()) // default
- .build();
- // This configuration tuning is custom. You can tune every option, you may tune some of them,
- // or you can create default configuration by
- // ImageLoaderConfiguration.createDefault(this);
- // method.
- // File cacheDir = StorageUtils.getCacheDirectory(context);
- File picPath=new File(Environment.getExternalStorageDirectory().getPath()+File.separator+"yourneed"+File.separator+"files");
- ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
- .memoryCacheExtraOptions(480, 800) // default = device screen dimensions
- .diskCacheExtraOptions(480, 800, null)
- .threadPoolSize(3) // default
- .threadPriority(Thread.NORM_PRIORITY - 1) // default
- .tasksProcessingOrder(QueueProcessingType.FIFO) // default
- .denyCacheImageMultipleSizesInMemory()
- .memoryCache(new LruMemoryCache(2 * 1024 * 1024))
- .memoryCacheSize(2 * 1024 * 1024)
- .memoryCacheSizePercentage(13) // default
- .diskCache(new UnlimitedDiscCache(picPath)) // default
- .diskCacheSize(50 * 1024 * 1024)
- .diskCacheFileCount(1000)
- .diskCacheFileNameGenerator(new HashCodeFileNameGenerator()) // default
- .imageDownloader(new BaseImageDownloader(context)) // default
- .imageDecoder(new BaseImageDecoder(true)) // default
- .defaultDisplayImageOptions(options) // default
- .writeDebugLogs()
- .build();
- // Initialize ImageLoader with configuration.
- ImageLoader.getInstance().init(config);
- }</span></span>
这里面有加载图片失败的设置,默认图片的设置,延迟加载设置,以及缓存陌路设置等等,这里就不详细介绍了,一般这个方法基本的配置都有了,大家可以直接拷到你的项目中直接用,可以在application里面初始化Imageloader。如果大家想要详细的了解Imageloader框架的话可以看看
这两篇博客,还是比较不错的。
至于图片就不给大家贴了,只要按照上面的方法做,你的ListView相信不会卡顿的。