[listview] listview优化

Android 4.0

listview优化
ListView优化,ListView内存优化
ListView异步加载缓存图片

1、复用convertView
2、缓存findViewById(),static viewHolder
3、软引用、弱引用
用LruCache替换
4、图片缩放
1、复用convertView
2、ViewHolder缓存查找到的组件的引用,防止多次查找,浪费内存和耗时
private static class ViewHolder {
    private TextView tv;
    private ImageView iv;
}
......
View view = null;
ViewHolder viewHolder = null;
if (convertView != null && convertView instanceof LinearLayout) {
    System.out.println("复用以前的convertView:" + position);
    view = convertView;
    viewHolder = (ViewHolder) view.getTag();
}else {
    System.out.println("新创建View:" + position);
    view = View.inflate(getApplicationContext(), R.layout.bitmap_listnull);
    
    viewHolder = new ViewHolder();
    
    viewHolder.tv = (TextView) view.findViewById(R.id.tv);
    viewHolder.iv = (ImageView) view.findViewById(R.id.iv);
    
    view.setTag(viewHolder);
}
3、软引用和弱引用
// TODO 1:软引用、虚引用
// SoftReference<ImageView> softReferenceBitmap = new SoftReference<ImageView>(iv);
WeakReference<Bitmap> softReferenceBitmap = new WeakReference<Bitmap>(bitmap);
bitmap.recycle(); 
bitmap = null;
......
WeakReference<Bitmap> softReferenceBitmap = softReferenceImages.get(position);
Bitmap refBitmap = softReferenceBitmap.get();
if (refBitmap == null) {
    // System.gc();
    System.out.println("被GC回收:" + position);
    refBitmap = scaleBitmap(imagesIds[position]);
}
4、图片缩放
/**
 * //TODO 2:图片缩放
 * @param resId 要缩放的图片的id
 * @return 缩放后的图片的bitmap
 */
@SuppressLint("NewApi")
// api13
private Bitmap scaleBitmap(int resId) {
    Options opts = new Options();
    opts.inJustDecodeBounds = true;// 不是真正的去解析图片,而是解析图片的头
    BitmapFactory.decodeResource(getResources(), resId, opts);
    int outWidth = opts.outWidth;
    int outHeight = opts.outHeight;
    System.out.println("图片宽度:" + outWidth);
    System.out.println("图片高度:" + outHeight);
    // 获取屏幕尺寸
    Display display = wm.getDefaultDisplay();
    Point screenSize = new Point();
    display.getSize(screenSize);
    int window_width = screenSize.x;
    int window_height = screenSize.y;
    System.out.println("屏幕宽度:" + window_width);
    System.out.println("屏幕高度:" + window_height);
    int scale = 1;
    int scaleX = outWidth / window_width;
    int scaleY = outHeight / window_height;
    if (scaleX < scaleY) {// 按照最大的缩放
        scale = scaleY;
    } else if (scaleX >= scaleY) {
        scale = scaleX;
    }
    opts.inSampleSize = scale;// 缩放比例,如果大于0,缩放比例为x和y轴各缩放1/scale,小于0,原图
    System.out.println("缩放比例:" + scale);
    opts.inJustDecodeBounds = false;// 重新设置为解析全图
    return BitmapFactory.decodeResource(getResources(), resId, opts);
}
全部核心代码:
package cn.zengfansheng.softreferencetest;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Point;
import android.os.Bundle;
import android.view.Display;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends Activity {
    private ListView lv;
    private int[] imagesIds;
    
    // private ArrayList<SoftReference<ImageView>> softReferenceImages;
    private ArrayList<WeakReference<Bitmap>> softReferenceImages;
    
    private WindowManager wm;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
        initData();
        lv = (ListView) this.findViewById(R.id.lv);
        MyAdapter adapter = new MyAdapter();
        lv.setAdapter(adapter);
        // VMRuntime
    }
    @SuppressLint("NewApi")
    public void initData() {
        imagesIds = LoadRes.loadResId();
        // softReferenceImages = new ArrayList<SoftReference<ImageView>>();
        softReferenceImages = new ArrayList<WeakReference<Bitmap>>();
        for (int i : imagesIds) {
            
            Bitmap bitmap = scaleBitmap(i);
            // TODO 1:软引用、虚引用
            // SoftReference<ImageView> softReferenceBitmap = new SoftReference<ImageView>(iv);
            WeakReference<Bitmap> softReferenceBitmap = new WeakReference<Bitmap>(bitmap);
            bitmap.recycle(); 
            bitmap = null;
            System.gc();
            softReferenceImages.add(softReferenceBitmap);
        }
    }
    /**
     * //TODO 2:图片缩放
     * @param resId 要缩放的图片的id
     * @return 缩放后的图片的bitmap
     */
    @SuppressLint("NewApi")
    // api13
    private Bitmap scaleBitmap(int resId) {
        Options opts = new Options();
        opts.inJustDecodeBounds = true;// 不是真正的去解析图片,而是解析图片的头
        BitmapFactory.decodeResource(getResources(), resId, opts);
        int outWidth = opts.outWidth;
        int outHeight = opts.outHeight;
        System.out.println("图片宽度:" + outWidth);
        System.out.println("图片高度:" + outHeight);
        // 获取屏幕尺寸
        Display display = wm.getDefaultDisplay();
        Point screenSize = new Point();
        display.getSize(screenSize);
        int window_width = screenSize.x;
        int window_height = screenSize.y;
        System.out.println("屏幕宽度:" + window_width);
        System.out.println("屏幕高度:" + window_height);
        int scale = 1;
        int scaleX = outWidth / window_width;
        int scaleY = outHeight / window_height;
        if (scaleX < scaleY) {// 按照最大的缩放
            scale = scaleY;
        } else if (scaleX >= scaleY) {
            scale = scaleX;
        }
        opts.inSampleSize = scale;// 缩放比例,如果大于0,缩放比例为x和y轴各缩放1/scale,小于0,原图
        System.out.println("缩放比例:" + scale);
        opts.inJustDecodeBounds = false;// 重新设置为解析全图
        return BitmapFactory.decodeResource(getResources(), resId, opts);
    }
    // TODO 3: ViewHolder,findViewByid() 查找id的优化
    private static class ViewHolder {
        private TextView tv;
        private ImageView iv;
    }
    // TODO :适配器
    private class MyAdapter extends BaseAdapter {
        @Override
        public int getCount() {
            return softReferenceImages.size();
        }
        @Override
        public Object getItem(int position) {
            return null;
        }
        @Override
        public long getItemId(int position) {
            return 0;
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            
            // TODO 4:使用convertView缓存
            View view = null;
            ViewHolder viewHolder = null;
            if (convertView != null && convertView instanceof LinearLayout) {
                System.out.println("复用以前的convertView:" + position);
                view = convertView;
                viewHolder = (ViewHolder) view.getTag();
            }else {
                System.out.println("新创建View:" + position);
                view = View.inflate(getApplicationContext(), R.layout.bitmap_listnull);
                
                viewHolder = new ViewHolder();
                
                viewHolder.tv = (TextView) view.findViewById(R.id.tv);
                viewHolder.iv = (ImageView) view.findViewById(R.id.iv);
                
                view.setTag(viewHolder);
            }
            
            //SoftReference<ImageView> softReferenceBitmap = softReferenceImages.get(position);
            WeakReference<Bitmap> softReferenceBitmap = softReferenceImages.get(position);
            Bitmap refBitmap = softReferenceBitmap.get();
            if (refBitmap == null) {
                // System.gc();
                System.out.println("被GC回收:" + position);
                refBitmap = scaleBitmap(imagesIds[position]);
            }
            viewHolder.tv.setText("图片名称:1000" + Math.random() * 100);
            viewHolder.iv.setImageBitmap(refBitmap);
            return view;
        }
    }
}