Android 带有复选框的自定义listview在滚动时崩溃

Android 带有复选框的自定义listview在滚动时崩溃,android,android-listview,android-arrayadapter,Android,Android Listview,Android Arrayadapter,我正在使用带有复选框、imageview和2文本框的listview。 列出使用ArayAdapter生成的列表,但我正在缓慢地滚动listview,但当我以某种速度滚动listview时,它崩溃了。 下面是我的代码 导入java.io.File; 导入java.util.ArrayList; 导入java.util.List import android.annotation.SuppressLint; import android.annotation.TargetApi; import a

我正在使用带有复选框、imageview和2文本框的listview。 列出使用ArayAdapter生成的列表,但我正在缓慢地滚动listview,但当我以某种速度滚动listview时,它崩溃了。 下面是我的代码

导入java.io.File; 导入java.util.ArrayList; 导入java.util.List

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;


@SuppressLint("SdCardPath")
public class AddOptionItemAdapter extends ArrayAdapter<String>
{

    String MenuId="";
    Context context;
    String tag;
    String tag1;
    String ogFilePath="";
    String imgpath="";
    private List<NameBean> list;
    ArrayList< String>priceList=new ArrayList<String>();
    ArrayList< String>imagepathList=new ArrayList<String>();

    public AddOptionItemAdapter(Context context,  List<NameBean> list,ArrayList<String> priceList,ArrayList<String> imagePathList) {
        super(context, R.layout.lvoptncat,priceList);
        this.list=list;
        this.priceList=priceList;
        this.imagepathList=imagePathList;
        this.context=context;
    }

    @TargetApi(16)
    public View getView (int position, View convertView, ViewGroup parent) 
        {
            ViewHolder holder = null;
            if (convertView == null)
            {
                holder = new ViewHolder();
                convertView = LayoutInflater.from(getContext()).inflate(R.layout.lvoptncat, null);
                holder.tvOptnCatName=(com.example.hotelmenu.CustomTextView)convertView.findViewById(R.id.tvSubMenu);
                holder.tvPrice=(com.example.hotelmenu.CustomTextView)convertView.findViewById(R.id.tvPrice);
                holder.checkbox = (CheckBox) convertView.findViewById(R.id.checkBox1);
                holder.imgPath = (ImageView) convertView.findViewById(R.id.imgMenu);
                holder.checkbox
                .setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {

                    @Override
                    public void onCheckedChanged(CompoundButton view,
                            boolean isChecked) {
                        int getPosition = (Integer) view.getTag();
                        addOptionActivity.optnCatNameList.get(getPosition).setSelected(view.isChecked());

                    }
                });
            }
            else
                holder = (ViewHolder) convertView.getTag();
            String filepath = Environment.getExternalStorageDirectory().getPath();
            File file = new File(filepath,"HotelMenuImages");      
            if(!file.exists())
            {
               file.mkdirs();
            }
            ogFilePath=file.getAbsolutePath();
            //String str=getItem(position);
            //String []OptnCatDetails=str.split(",");
            //DataSource datasource=new DataSource(context);
            try
            {
                //Log.d("ImagePath111",MenuDetails[3].trim());
                //String photo2 =OptnCatDetails[2];
                //Log.d("ImagePath1222",photo2);
                String photo2=imagepathList.get(position);
                BitmapFactory.Options options = new BitmapFactory.Options(); 
                options.inPurgeable = true;
                options.inSampleSize = 4;
                Bitmap myBitmap = BitmapFactory.decodeFile(ogFilePath+"/"+photo2, options);
                holder.imgPath.setImageBitmap(myBitmap);
            }
            catch(OutOfMemoryError e)
            {
                Log.d("ImageError",""+e);
            }
            holder.tvOptnCatName.setText(list.get(position).getName());
            holder.tvPrice.setText(priceList.get(position));
            holder.checkbox.setTag(position);
            holder.checkbox.setChecked(addOptionActivity.optnCatNameList.get(position).isSelected());

            return convertView;         
        }
     class ViewHolder {
        protected com.example.hotelmenu.CustomTextView tvOptnCatName,tvPrice;
        protected CheckBox checkbox;
        protected ImageView imgPath;
    }
}

请从getView()中删除文件操作和重位图操作

使用下面的类来处理列表视图中的图像,而不是使用此类

public class ImageStorage {

    private String mBaseDir;
    private static final String TAG = "Image Storage";
    private static boolean DEBUG = false;
    public static final int DEFAULT_CACHE_SIZE = 64;
    private BasicBitmapCache mCache;    

    private Handler mHandler = new Handler();
    private ExecutorService mExecutor = Executors.newCachedThreadPool();

    private Set<LoadRequest> mActiveRequests = new HashSet<LoadRequest>();

    public static class LoadRequest {

        public LoadRequest(String key, ImageView v) {
            if (key == null)
                throw new NullPointerException("key must not be null");

            mKey = key;

            mImageView = v;

        }

        public ImageView getImageView() {
            return mImageView;
        }

        public String getKey() {
            return mKey;
        }

        @Override
        public boolean equals(Object b) {
            if (b instanceof LoadRequest)
                return mKey.equals(((LoadRequest) b).getKey());

            return false;
        }

        private String mKey;
        private ImageView mImageView;
    }

    public ImageStorage(String baseDir) {
        this.mBaseDir = baseDir;
        this.mCache = new BasicBitmapCache(DEFAULT_CACHE_SIZE);
    }

    public boolean exists(String key) {
        File file = new File(new File(mBaseDir), key);
        return file.exists();
    }

    public Bitmap loadData(String key) {

        if (!exists(key)) {
            return null;
        }

        // load the bitmap as-is (no scaling, no crop)
        Bitmap bitmap = null;

        File file = new File(new File(mBaseDir), key);
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            bitmap = BitmapFactory.decodeStream(fis);
            if (bitmap == null) {
                // something wrong with the persistent data, can't be decoded to
                // bitmap.
                // removeDir(file); // Let's remove this file will gets
                // downloaded again from server
                throw new RuntimeException(
                        "data from db can't be decoded to bitmap");
            }
            return bitmap;
        } catch (IOException e) {
            if (DEBUG)
                Log.e(TAG, "error loading bitmap", e);
            return null;
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                }
            }
        }
    }

    public void storeData(String key, Bitmap data) {

        if (data == null || data.isRecycled())
            return;

        //Scaling image before storing
        data = scaleBitmap(data);

        OutputStream outputStream = null;
        try {
            File file = new File(new File(mBaseDir), key);

            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            outputStream = new FileOutputStream(file);
            if (!data.compress(Bitmap.CompressFormat.PNG, 100, outputStream)) {
                throw new RuntimeException("failed to compress bitmap");
            }

        } catch (IOException e) {
            if (DEBUG)
                Log.e(TAG, "error storing bitmap", e);
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                }
            }
        }

    }

    public void clear() {

        try {
            this.removeDir(new File(mBaseDir));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    public int deleteFile(String key) {

        if (!exists(key)) {
            return -1;
        }

        File file = new File(new File(mBaseDir), key);
        boolean deleted = file.delete();

        if (!deleted)
            return 0;

        return 1;

    }

    /**
     * Delete a directory
     * 
     * @param d
     *            the directory to delete
     * 
     */
    private void removeDir(File d) throws IOException {

        // to see if this directory is actually a symbolic link to a directory,
        // we want to get its canonical path - that is, we follow the link to
        // the file it's actually linked to
        File candir = d.getCanonicalFile();

        // a symbolic link has a different canonical path than its actual path,
        // unless it's a link to itself
        if (!candir.equals(d.getAbsoluteFile())) {
            // this file is a symbolic link, and there's no reason for us to
            // follow it, because then we might be deleting something outside of
            // the directory we were told to delete
            return;
        }

        // now we go through all of the files and subdirectories in the
        // directory and delete them one by one
        File[] files = candir.listFiles();
        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                File file = files[i];

                // in case this directory is actually a symbolic link, or it's
                // empty, we want to try to delete the link before we try
                // anything
                boolean deleted = file.delete();
                if (!deleted) {
                    // deleting the file failed, so maybe it's a non-empty
                    // directory
                    if (file.isDirectory())
                        removeDir(file);

                    // otherwise, there's nothing else we can do
                }
            }
        }

        // now that we tried to clear the directory out, we can try to delete it
        // again
        d.delete();
    }

    public Bitmap loadImage(LoadRequest r) {

        if (r == null || r.getKey() == null) {
            // throw new IllegalArgumentException( "null or empty request");
            return null;
        }

        ImageView v = r.getImageView();
        if (v != null) {
            synchronized (v) {
                v.setTag(r.getKey()); // bind URI to the ImageView, to prevent
                                        // image write-back of earlier requests.
            }
        }

        mExecutor.submit(newRequestCall(r));
        return null;
    }

    private Bitmap scaleBitmap(Bitmap image) {

        int width = image.getWidth();
        int height = image.getHeight();
        float scale = (float)480/(float)width;

        Matrix matrix = new Matrix();
        matrix.postScale(scale, scale);

        Bitmap scaledBitmap = Bitmap.createScaledBitmap(image,
                (int) (width * scale), (int) (height * scale), true);
        // Bitmap scaledBitmap = Bitmap.createBitmap(images.get(i), 0, 0, width,
        // height, matrix, true);

        return scaledBitmap;
    }

    private Callable<LoadRequest> newRequestCall(final LoadRequest request) {
        return new Callable<LoadRequest>() {

            public LoadRequest call() {

                synchronized (mActiveRequests) {

                    while (mActiveRequests.contains(request)) {

                        try {
                            mActiveRequests.wait();
                        } catch (InterruptedException e) {
                        }

                    }
                    mActiveRequests.add(request);
                }

                Bitmap data = null;

                try {

                    String key = request.getKey();

                    data = mCache.loadData(key);

                    if (data == null) {

                        if (DEBUG)
                            Log.d(TAG, "cache missing " + request.getKey());
                        // then check the persistent storage
                        data = loadData(key);

                        if (data != null) {

                            if (DEBUG)
                                Log.d(TAG,
                                        "found in persistent: "
                                                + request.getKey());

                            mCache.storeData(key, data);
                        }
                    }

                    if (data != null && !data.isRecycled()
                            && request.getImageView() != null) {

                        final Bitmap theData = data;
                        final ImageView iv = request.getImageView();

                        synchronized (iv) {

                            if (iv != null && iv.getTag() == request.getKey()) {

                                mHandler.post(new Runnable() {

                                    @Override
                                    public void run() {

                                        if (iv.getTag() == request.getKey()
                                                && !theData.isRecycled()) {
                                            iv.setAnimation(null);
                                            iv.setImageBitmap(theData);
                                        }

                                    }

                                });

                            }

                        }

                    }
                } catch (Throwable e) {
                    if (DEBUG)
                        Log.e(TAG,
                                "error handling request " + request.getKey(), e);
                } finally {

                    synchronized (mActiveRequests) {
                        mActiveRequests.remove(request);
                        mActiveRequests.notifyAll(); // wake up pending requests
                                                        // who's querying the
                                                        // same URL.
                    }

                    if (DEBUG)
                        Log.d(TAG, "finished request for: " + request.getKey());
                }

                return request;
            }
        };
    }

}
基本位图缓存在这里

/**
 * Basic implementation of BitmapCache
 * 
 * @author Chirag Jain
 */
public class BasicBitmapCache {

    private static class CacheEntry {
        public Bitmap data;
        public int nUsed;
        public long timestamp;
    }

    private static final String TAG = "BasicBitmapCache";
    private static final boolean DEBUG = false;

    private int mMaxSize;
    private HashMap<String, CacheEntry> mMap = new HashMap<String, CacheEntry>();

    /**
     * max number of resource this cache contains
     * 
     * @param size
     */
    public BasicBitmapCache(int size) {
        this.mMaxSize = size;
    }

    public synchronized boolean exists(String key) {
        return mMap.get(key) != null;
    }

    public synchronized void invalidate(String key) {
        CacheEntry e = mMap.get(key);
        Bitmap data = e.data;
        data.recycle();
        mMap.remove(key);
        if (DEBUG)
            Log.d(TAG, key + " is invalidated from the cache");
    }

    public synchronized void clear() {
        for (String key : mMap.keySet()) {
            invalidate(key);
        }
    }

    /**
     * If the cache storage is full, return an item to be removed.
     * 
     * Default strategy: the least and oldest out: O(n)
     * 
     * @return item key
     */
    protected synchronized String findItemToInvalidate() {
        Map.Entry<String, CacheEntry> out = null;
        for (Map.Entry<String, CacheEntry> e : mMap.entrySet()) {
            if (out == null || e.getValue().nUsed < out.getValue().nUsed
                    || e.getValue().nUsed == out.getValue().nUsed
                    && e.getValue().timestamp < out.getValue().timestamp) {
                out = e;
            }
        }
        return out.getKey();
    }

    public synchronized Bitmap loadData(String key) {
        if (!exists(key)) {
            return null;
        }
        CacheEntry res = mMap.get(key);
        res.nUsed++;
        res.timestamp = System.currentTimeMillis();
        return res.data;
    }

    public synchronized void storeData(String key, Bitmap data) {
        if (this.exists(key) || data == null || data.isRecycled()) {
            return;
        }
        CacheEntry res = new CacheEntry();
        res.nUsed = 1;
        res.timestamp = System.currentTimeMillis();
        res.data = data;

        // if the number exceeds, move an item out
        // to prevent the storage from increasing indefinitely.
        if (mMap.size() >= mMaxSize) {
            String outkey = this.findItemToInvalidate();
            this.invalidate(outkey);
        }

        mMap.put(key, res);
    }

}
/**
*BitmapCache的基本实现
* 
*@作者Chirag Jain
*/
公共类BasicBitmapCache{
私有静态类CacheEntry{
公共位图数据;
公众参与;
公共长时间戳;
}
私有静态最终字符串标记=“BasicBitmapCache”;
私有静态最终布尔调试=false;
私有int-mMaxSize;
私有HashMap mMap=新HashMap();
/**
*此缓存包含的最大资源数
* 
*@param大小
*/
公共BasicBitmapCache(整数大小){
this.mMaxSize=大小;
}
存在公共同步布尔值(字符串键){
返回mMap.get(key)!=null;
}
公共同步无效失效(字符串键){
CacheEntry e=mMap.get(键);
位图数据=e.data;
data.recycle();
mMap.移除(键);
如果(调试)
Log.d(标记,key+“从缓存中无效”);
}
公共同步无效清除(){
for(字符串键:mMap.keySet()){
使(密钥)无效;
}
}
/**
*如果缓存已满,请返回要删除的项。
* 
*默认策略:最小和最早的输出:O(n)
* 
*@返回项目密钥
*/
受保护的同步字符串findItemToInvalidate(){
Map.Entry out=null;
对于(Map.Entry e:mMap.entrySet()){
如果(out==null | | e.getValue().nUsed=mMaxSize){
String outkey=this.findItemToInvalidate();
此。无效(outkey);
}
mMap.put(键,res);
}
}

第95行是什么
addOptionineMadapter.java
?-Raghunandan holder.imgPath.setImageBitmap(myBitmap);但每当我在适配器类中为视图设置值时,就会发生错误。如果我删除这一行,错误将更改为下一个视图,我将在其中设置文本视图的值。-错误仅在我以一定速度滚动列表视图时出现。我应该首先说,我不确定,但请尝试添加
if(holder!=null){holder.imgPath.setImageBitmap(myBitmap);}
.Hemant这将中断ui线程,从外部内存加载listview中的图像,并且从内存加载适配器的getView中的图像与从网络加载图像(并且您希望在运行时加载图像)类似.–Chirag Jain那么我们应该做些什么来克服这样的问题呢?只要在活动中或适配器的构造函数中给出基本目录的路径,创建ImageStorage类的实例即可。然后调用您的\u instance.loadImage(您的\u文件\u名称,您的\u图像\u视图);在第一条评论中有一个拼写错误。。你是说“不打扰”吗。感谢分享你的课程,期待在我的画廊项目中使用它…谢谢Deepak。是的,它是“不打断”。很抱歉,键入错误:(
getImageStorage().loadImage(
                    new LoadRequest(//name of image,
                            //your image view));
/**
 * Basic implementation of BitmapCache
 * 
 * @author Chirag Jain
 */
public class BasicBitmapCache {

    private static class CacheEntry {
        public Bitmap data;
        public int nUsed;
        public long timestamp;
    }

    private static final String TAG = "BasicBitmapCache";
    private static final boolean DEBUG = false;

    private int mMaxSize;
    private HashMap<String, CacheEntry> mMap = new HashMap<String, CacheEntry>();

    /**
     * max number of resource this cache contains
     * 
     * @param size
     */
    public BasicBitmapCache(int size) {
        this.mMaxSize = size;
    }

    public synchronized boolean exists(String key) {
        return mMap.get(key) != null;
    }

    public synchronized void invalidate(String key) {
        CacheEntry e = mMap.get(key);
        Bitmap data = e.data;
        data.recycle();
        mMap.remove(key);
        if (DEBUG)
            Log.d(TAG, key + " is invalidated from the cache");
    }

    public synchronized void clear() {
        for (String key : mMap.keySet()) {
            invalidate(key);
        }
    }

    /**
     * If the cache storage is full, return an item to be removed.
     * 
     * Default strategy: the least and oldest out: O(n)
     * 
     * @return item key
     */
    protected synchronized String findItemToInvalidate() {
        Map.Entry<String, CacheEntry> out = null;
        for (Map.Entry<String, CacheEntry> e : mMap.entrySet()) {
            if (out == null || e.getValue().nUsed < out.getValue().nUsed
                    || e.getValue().nUsed == out.getValue().nUsed
                    && e.getValue().timestamp < out.getValue().timestamp) {
                out = e;
            }
        }
        return out.getKey();
    }

    public synchronized Bitmap loadData(String key) {
        if (!exists(key)) {
            return null;
        }
        CacheEntry res = mMap.get(key);
        res.nUsed++;
        res.timestamp = System.currentTimeMillis();
        return res.data;
    }

    public synchronized void storeData(String key, Bitmap data) {
        if (this.exists(key) || data == null || data.isRecycled()) {
            return;
        }
        CacheEntry res = new CacheEntry();
        res.nUsed = 1;
        res.timestamp = System.currentTimeMillis();
        res.data = data;

        // if the number exceeds, move an item out
        // to prevent the storage from increasing indefinitely.
        if (mMap.size() >= mMaxSize) {
            String outkey = this.findItemToInvalidate();
            this.invalidate(outkey);
        }

        mMap.put(key, res);
    }

}