0

我正在使用带有复选框、图像视图和 2 个文本框的列表视图。列出使用 araayaadapter 生成的内容,但我正在轻轻滚动列表视图,但当我以一定速度滚动列表视图时,它会崩溃。以下是我的代码。

导入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;
    }
}

以下是我的日志猫

07-19 10:56:13.549: E/InputEventReceiver(11356): Exception dispatching input event.
07-19 10:56:13.549: D/AndroidRuntime(11356): Shutting down VM
07-19 10:56:13.549: W/dalvikvm(11356): threadid=1: thread exiting with uncaught exception (group=0x4169a2a0)
07-19 10:56:13.565: E/AndroidRuntime(11356): FATAL EXCEPTION: main
07-19 10:56:13.565: E/AndroidRuntime(11356): java.lang.NullPointerException
07-19 10:56:13.565: E/AndroidRuntime(11356):    at com.example.hotelmenu.AddOptionItemAdapter.getView(AddOptionItemAdapter.java:95)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.widget.AbsListView.obtainView(AbsListView.java:2449)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.widget.ListView.makeAndAddView(ListView.java:1769)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.widget.ListView.fillUp(ListView.java:706)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.widget.ListView.correctTooHigh(ListView.java:1395)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.widget.ListView.fillGap(ListView.java:637)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.widget.AbsListView.trackMotionScroll(AbsListView.java:5534)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.widget.AbsListView.scrollIfNeeded(AbsListView.java:3417)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.widget.AbsListView.onTouchEvent(AbsListView.java:3910)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.View.dispatchTouchEvent(View.java:7340)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2181)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1914)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2187)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1929)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2187)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1929)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2187)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1929)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2187)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1929)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2187)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1929)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2187)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1929)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2113)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1466)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.app.Activity.dispatchTouchEvent(Activity.java:2468)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2061)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.View.dispatchPointerEvent(View.java:7525)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3370)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3302)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4394)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4372)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4476)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:171)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:163)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:4444)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:4495)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.Choreographer.doCallbacks(Choreographer.java:555)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.Choreographer.doFrame(Choreographer.java:523)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.os.Handler.handleCallback(Handler.java:615)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.os.Handler.dispatchMessage(Handler.java:92)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.os.Looper.loop(Looper.java:137)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at android.app.ActivityThread.main(ActivityThread.java:4895)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at java.lang.reflect.Method.invokeNative(Native Method)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at java.lang.reflect.Method.invoke(Method.java:511)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:994)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:761)
07-19 10:56:13.565: E/AndroidRuntime(11356):    at dalvik.system.NativeStart.main(Native Method)
4

1 回答 1

0

请从 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;
            }
        };
    }

}

并在您的适配器中使用

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);
    }

}
于 2013-07-19T06:06:43.690 回答