Android性能优化之提高ListView性能的技巧

Android性能优化之提高ListView性能的技巧:

  1. 在adapter中的getView方法中尽量少使用逻辑
  2. 尽最大可能避免GC
  3. 滑动的时候不载入图片
  4. 将ListView的scrollingCache和animateCache设置为false
  5. item的布局层级越少越好
  6. 使用ViewHolder
  7. 使用LRU缓存和异步加载

1.在adapter中的getView方法中尽量少使用逻辑

不要在你的getView()中写过多的逻辑代码,我们能够将这些代码放在别的地方。比如:
优化前的getView():

@Override
public View getView(int position, View convertView, ViewGroup paramViewGroup) {
        Object current_event = mObjects.get(position);
        ViewHolder holder = null;
        if (convertView == null) {
                holder = new ViewHolder();
                convertView = inflater.inflate(R.layout.row_event, null);
                holder.ThreeDimension = (ImageView) convertView.findViewById(R.id.ThreeDim);
                holder.EventPoster = (ImageView) convertView.findViewById(R.id.EventPoster);
                convertView.setTag(holder);

        } else {
                holder = (ViewHolder) convertView.getTag();
        }

       //在这里进行逻辑推断。这是有问题的 
        if (doesSomeComplexChecking()) {
                holder.ThreeDimention.setVisibility(View.VISIBLE);
        } else {
                holder.ThreeDimention.setVisibility(View.GONE); 
        }

        // 这是设置image的參数,每次getView方法运行时都会运行这段代码。这显然是有问题的
        RelativeLayout.LayoutParams imageParams = new RelativeLayout.LayoutParams(measuredwidth, rowHeight);
        holder.EventPoster.setLayoutParams(imageParams);

        return convertView;
}

优化后的getView():

@Override
public View getView(int position, View convertView, ViewGroup paramViewGroup) {
    Object object = mObjects.get(position);
    ViewHolder holder = null;

    if (convertView == null) {
            holder = new ViewHolder();
            convertView = inflater.inflate(R.layout.row_event, null);
            holder.ThreeDimension = (ImageView) convertView.findViewById(R.id.ThreeDim);
            holder.EventPoster = (ImageView) convertView.findViewById(R.id.EventPoster);
            //设置參数提到这里,仅仅有第一次的时候会运行,之后会复用 
            RelativeLayout.LayoutParams imageParams = new RelativeLayout.LayoutParams(measuredwidth, rowHeight);
            holder.EventPoster.setLayoutParams(imageParams);
            convertView.setTag(holder);
    } else {
            holder = (ViewHolder) convertView.getTag();
    }

    // 我们直接通过对象的getter方法取代刚才那些逻辑推断。那些逻辑推断放到别的地方去运行了
    holder.ThreeDimension.setVisibility(object.getVisibility());

    return convertView;
}

2.尽最大可能避免GC

当你创建了大量的对象的时候。GC就会频繁的运行。所以在getView()方法中不要创建非常多的对象。最好的优化是,不要在ViewHolder以外创建不论什么对象。假设你的你的log里面发现“GC has freed some memory”频繁出现的话。那你的程序肯定有问题了。
你能够检查一下:
a) item布局的层级是否太深
b) getView()方法中是否有大量对象存在
c) ListView的布局属性

3.滑动的时候不载入图片

假设你的ListView中须要显示从网络上下载的图片的话。我们不要在ListView滑动的时候载入图片,那样会使ListView变得卡顿,所以我们须要再监听器里面监听ListView的状态。假设滑动的时候,停止载入图片,假设没有滑动,则開始载入图片

listView.setOnScrollListener(new OnScrollListener() {

            @Override
            public void onScrollStateChanged(AbsListView listView, int scrollState) {
                    //停止载入图片 
                    if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) {
                            imageLoader.stopProcessingQueue();
                    } else {
                    //開始载入图片
                            imageLoader.startProcessingQueue();
                    }
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                    // TODO Auto-generated method stub

            }
    });

4.将ListView的scrollingCache和animateCache设置为false

scrollingCache: scrollingCache本质上是drawing cache,你能够让一个View将他自己的drawing保存在cache中(保存为一个bitmap),这样下次再显示View的时候就不用重画了,而是从cache中取出。默认情况下drawing cahce是禁用的。由于它太耗内存了,可是它确实比重画来的更加平滑。
而在ListView中,scrollingCache是默认开启的,我们能够手动将它关闭。
animateCache: ListView默认开启了animateCache,这会消耗大量的内存,因此会频繁调用GC,我们能够手动将它关闭掉
优化前的ListView
<

ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:cacheColorHint="#00000000"
        android:divider="@color/list_background_color"
        android:dividerHeight="0dp"
        android:listSelector="#00000000"
        android:smoothScrollbar="true"
        android:visibility="gone" /> 

优化后的ListView

<ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:divider="@color/list_background_color"
        android:dividerHeight="0dp"
        android:listSelector="#00000000"
        android:scrollingCache="false"
        android:animationCache="false"
        android:smoothScrollbar="true"
        android:visibility="gone" />

5.降低item的布局的深度

我们应该尽量降低item布局深度,由于当滑动ListView的时候,这回直接导致測量与绘制,因此会浪费大量的时间。所以我们应该将一些不必要的布局嵌套关系去掉。降低item布局深度

6.使用ViewHolder

这个大家应该非常熟悉了,可是不要小看这个ViewHolder,它能够大大提高我们ListView的性能

7.使用LRU缓存和异步加载

package com.example.mp3;

import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.List;
import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.v4.util.LruCache;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
@SuppressLint("NewApi")
public class music_Adapter extends ArrayAdapter<Music> {

	private int resourceId;
	private LruCache<Integer, Bitmap> mMemoryCache;
	/**
	 * 图片缓存技术的核心类,用于缓存所有下载好的图片,在程序内存达到设定值时会将最少最近使用的图片移除掉。
	 */
	public music_Adapter(Context view, int resource, List<Music> objects) {
		super(view, resource, objects);
		// TODO Auto-generated constructor stub
		resourceId = resource;
		// 获取应用程序最大可用内存
		int maxMemory = (int) Runtime.getRuntime().maxMemory();
		int cacheSize = maxMemory / 8;
		mMemoryCache = new LruCache<Integer, Bitmap>(cacheSize) {
			@Override
			protected int sizeOf(Integer key, Bitmap drawable) {
				return drawable.getByteCount();
			}
		};
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		ViewHolder holder = null;
		//判断是否缓存
		if(convertView==null){
			holder = new ViewHolder();
			convertView = LayoutInflater.from(getContext()).inflate(resourceId,parent, false);	
			holder.musicImage = (ImageView)convertView.findViewById(R.id.image_list);
			holder.musicName = (TextView)convertView.findViewById(R.id.music_name);
			holder.musicArtist = (TextView)convertView.findViewById(R.id.music_author);
			convertView.setTag(holder);
		} else {
			//通过tag找到缓存的布局
			holder = (ViewHolder)convertView.getTag();
		}
		
		Music music = getItem(position);
		//判断专辑图片是否为空
//		if(loadCoverFromMediaStore(music.getAlbumId()) != null) {
//			holder.musicImage.setImageBitmap(loadCoverFromMediaStore(music.getAlbumId()));
//		} else {
//			holder.musicImage.setImageResource(R.drawable.qq);
//		}
		
		Bitmap drawable = getBitmapFromMemoryCache(music.getAlbumId());
		if (drawable != null) {
			holder.musicImage.setImageBitmap(drawable);
		} else {
			BitmapWorkerTask task = new BitmapWorkerTask(holder.musicImage);
			task.execute(music.getAlbumId());
		}

		holder.musicName.setText(music.getTitle());
		holder.musicArtist.setText(music.getArtist());
		return convertView;
	}
	
	/**
	 * 将一张图片存储到LruCache中。
	 * 
	 * @param key
	 *            LruCache的键,这里传入专辑ID地址。
	 * @param drawable
	 *            LruCache的值,这里传入从网络上下载的BitmapDrawable对象。
	 */
	public void addBitmapToMemoryCache(Integer albumId, Bitmap drawable) {
		if (getBitmapFromMemoryCache(albumId) == null&&albumId!=null&&drawable!=null) {
			mMemoryCache.put(albumId, drawable);
		}
	}
 
	/**
	 * 从LruCache中获取一张图片,如果不存在就返回null。
	 * 
	 * @param key
	 *            LruCache的键,这里传入图片的URL地址。
	 * @return 对应传入键的BitmapDrawable对象,或者null。
	 */
	public Bitmap getBitmapFromMemoryCache(Integer albumId) {
		return mMemoryCache.get(albumId);
	}

	
	private Bitmap loadCoverFromMediaStore(int albumId){
		 Uri artworkUri = Uri.parse("content://media/external/audio/albumart"); 
		 Uri uri = ContentUris.withAppendedId(artworkUri, albumId);
		 ContentResolver resolver = getContext().getContentResolver();
		InputStream is;
		try {
			is = resolver.openInputStream(uri);
		} catch (FileNotFoundException e) {
			//e.printStackTrace();
			return null;
		}
		BitmapFactory.Options options = new Options();
		options.inPreferredConfig = Bitmap.Config.RGB_565;
		return BitmapFactory.decodeStream(is,null,options);
	}
	public final class ViewHolder{
		public ImageView musicImage;
		public TextView musicName;
		public TextView musicArtist;
	}
	

	class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
 
		private ImageView mImageView;
 
		public BitmapWorkerTask(ImageView imageView) {
			mImageView = imageView;
		}
 
		@Override
		protected Bitmap doInBackground(Integer... params) {
			Integer imageUrl = params[0];
			// 在后台开始下载图片
			Bitmap drawable = loadCoverFromMediaStore(imageUrl);

			addBitmapToMemoryCache(imageUrl, drawable);
			return drawable;
		}
 
		@Override
		protected void onPostExecute(Bitmap drawable) {
			if(drawable != null && mImageView != null) {
				mImageView.setImageBitmap(drawable);
			} else {
				mImageView.setImageResource(R.drawable.qq);
			}
		}
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值