解决ListView加载错乱问题

ListView在使用holder的过程中会减少内存的使用,但是另一方面,在listview的每一个item的数据都很多时,特别是加载网络图片的时候,有可能会出现图片加载过慢,图片加载错位问题,尝试过很多方法,终于找到了一种还不错的方法。


第一步:

在holder的基础上加入reset方法:

class ImgHolder {
private TextView tv_number;
private TextView tv_name;
private CircleImageView cimg_head;


}


private void resetImgHolder(ImgHolder imgHolder) {
imgHolder.tv_name.setText(null);
imgHolder.tv_number.setText(null);
imgHolder.cimg_head.setImageDrawable(null);
}

在每次调用完getTag方法后调用一下这个方法

if (null == convertView) {
convertView = LayoutInflater.from(context).inflate(
R.layout.item_imglist, null);
imgHolder = new ImgHolder();
imgHolder.cimg_head = (CircleImageView) convertView
.findViewById(R.id.cimg_head);
imgHolder.tv_name = (TextView) convertView
.findViewById(R.id.tv_name);
imgHolder.tv_number = (TextView) convertView
.findViewById(R.id.tv_number);
convertView.setTag(imgHolder);
} else {
imgHolder = (ImgHolder) convertView.getTag();
resetImgHolder(imgHolder);
}

第二步:


判断list中是否有值,如果没有值的话也要去设置值

if(null!=imgList.get(position).getImgUrl()){
BitmapUtilsHelp
.getImage(context, R.drawable.defalut_user_icon)
.display(imgHolder.cimg_head, imgList.get(position).getImgUrl());
}else{
imgHolder.cimg_head.setImageResource(R.drawable.defalut_user_icon);
}


第三步:

也是最关键的一步 加入缓存

package com.example.imageholder;


import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Comparator;


import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.os.StatFs;
import android.util.Base64;
import android.util.Log;


/**
 * TODO:图片缓存:本地文件缓存类
 * @version 1.0, 2013-11-18/下午4:22:38
 */
public class ImageFileCache
{
    // 图片缓存目录
    public static final String CACHDIR = ".mtc/cache/";


    public static final String School_Cache = ".mfc_school";


    private static final String WHOLESALE_CONV = ".png";


    private static final int MB = 1024 * 1024;


    private static final int CACHE_SIZE = 50;


    private static final int FREE_SD_SPACE_NEEDED_TO_CACHE = 64;


    public ImageFileCache()
    {
        // 清理文件缓存
        removeCache(getDirectory());
    }


    /** 从缓存中获取图片 **/
    public Bitmap getImage(final String url)
    {
        final String path = getDirectory() + "/" + convertUrlToFileName(url);
        File file = new File(path);
        if (file.exists())
        {
            Bitmap bmp = BitmapFactory.decodeFile(path);
            if (bmp == null)
            {
                file.delete();
            }
            else
            {
                updateFileTime(path);
                return bmp;
            }
        }
        return null;
    }


    /** 将图片存入文件缓存 **/
    public void saveBitmap(Bitmap bm, String url)
    {
        if (bm == null)
        {
            return;
        }
        // 判断sdcard上的空间
        if (FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd())
        {
            // SD空间不足
            return;
        }
        String filename = convertUrlToFileName(url);
        String dir = getDirectory();
        File dirFile = new File(dir);
        if (!dirFile.exists())
            dirFile.mkdirs();
        File file = new File(dir + "/" + filename);
        try
        {
            file.createNewFile();
            OutputStream outStream = new FileOutputStream(file);
            bm.compress(Bitmap.CompressFormat.PNG, 100, outStream);


            outStream.flush();
            outStream.close();
        }
        catch(FileNotFoundException e)
        {
            Log.e("ImageFileCache", "FileNotFoundException");
        }
        catch(IOException e)
        {
            Log.e("ImageFileCache", "IOException");
        }
    }


    /**
     * 计算存储目录下的文件大小,
     * 当文件总大小大于规定的CACHE_SIZE或者sdcard剩余空间小于FREE_SD_SPACE_NEEDED_TO_CACHE的规定
     * 那么删除20%最近没有被使用的文件
     */
    private boolean removeCache(String dirPath)
    {
        File dir = new File(dirPath);
        File[] files = dir.listFiles();
        if (files == null)
        {
            return true;
        }
        if (!Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED))
        {
            return false;
        }


        int dirSize = 0;
        for (int i = 0; i < files.length; i++)
        {
            if (files[i].getName().contains(WHOLESALE_CONV))
            {
                dirSize += files[i].length();
            }
        }


        if (dirSize > CACHE_SIZE * MB
                || FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd())
        {
            int removeFactor = (int) ((0.2 * files.length) + 1);
            Arrays.sort(files, new FileLastModifSort());
            for (int i = 0; i < removeFactor; i++)
            {
                if (files[i].getName().contains(WHOLESALE_CONV))
                {
                    files[i].delete();
                }
            }
        }


        if (freeSpaceOnSd() <= CACHE_SIZE)
        {
            return false;
        }


        return true;
    }


    /** 修改文件的最后修改时间 **/
    public void updateFileTime(String path)
    {
        File file = new File(path);
        long newModifiedTime = System.currentTimeMillis();
        file.setLastModified(newModifiedTime);
    }


    /** 计算sdcard上的剩余空间 **/
    private int freeSpaceOnSd()
    {
        StatFs stat = new StatFs(Environment.getExternalStorageDirectory()
                .getPath());
        double sdFreeMB = ((double) stat.getAvailableBlocks() * (double) stat
                .getBlockSize()) / MB;
        return (int) sdFreeMB;
    }


    /** 将url转成文件名 **/
    private String convertUrlToFileName(String url)
    {
        String[] strs = url.split("/");
        String filename = base64Encode(strs[strs.length - 1]).trim();
        return filename + WHOLESALE_CONV;
    }


    /** 获得缓存目录 **/
    public static String getDirectory()
    {
        String dir = getSDPath() + File.separator + CACHDIR;
        return dir;
    }


    public static String getSchoolDirectory()
    {
        String dir = getSDPath() + File.separator + School_Cache;
        return dir;
    }


    public static String getPicDirectory()
    {
        String dir = getSDPath() + File.separator + "mzone/pic/";
        return dir;
    }


    /** 取SD卡路径 **/
    private static String getSDPath()
    {
        File sdDir = null;
        boolean sdCardExist = Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED); // 判断sd卡是否存在
        if (sdCardExist)
        {
            sdDir = Environment.getExternalStorageDirectory(); // 获取根目录
        }
        if (sdDir != null)
        {
            return sdDir.toString();
        }
        else
        {
            return "";
        }
    }


    /**
     * 根据文件的最后修改时间进行排序
     */
    private class FileLastModifSort implements Comparator
    {
        public int compare(File arg0, File arg1)
        {
            if (arg0.lastModified() > arg1.lastModified())
            {
                return 1;
            }
            else if (arg0.lastModified() == arg1.lastModified())
            {
                return 0;
            }
            else
            {
                return -1;
            }
        }
    }
    /**
     * 检查该网络图片是否存在
     */
    public boolean checkImageExist(String url){
        String filename = convertUrlToFileName(url);
        String dir = getDirectory();
        File dirFile = new File(dir);
        if (!dirFile.exists())
            return false;
        File file = new File(dir + "/" + filename);
        if(!file.exists()){
            return false;
        }
        return true;
    }


    public static String base64Encode(String str)
    {
        return Base64.encodeToString(str.getBytes(), Base64.DEFAULT);
    }


    public static String base64Decode(String pContent)
    {
        byte b[] = Base64.decode(pContent, Base64.DEFAULT);
        return new String(b);
    }


}


当然还有一些自己的方法,大家可以去下载我写的demo查看



  网址    http://download.csdn.net/detail/qq_29986595/9532781



你可能感兴趣的:(android,开发)