android - 无法使用 AsyncTask 在 ListView 中加载图像

标签 android android-listview android-asynctask

在我的 ListView 中只有一个 ImageView 。我正在尝试在 asynctask 中在此 ListView 中加载图像,并且我正在使用可绘制资源,但它会产生许多错误,我无法解决。 这些是错误。

09-11 22:25:00.904: E/dalvikvm-heap(1165): Out of memory on a 3318016-byte allocation.
09-11 22:25:01.664: E/AndroidRuntime(1165): FATAL EXCEPTION: AsyncTask #1
09-11 22:25:01.664: E/AndroidRuntime(1165): java.lang.RuntimeException: An error occured while executing doInBackground()
09-11 22:25:01.664: E/AndroidRuntime(1165):     at android.os.AsyncTask$3.done(AsyncTask.java:278)
09-11 22:25:01.664: E/AndroidRuntime(1165):     at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
09-11 22:25:01.664: E/AndroidRuntime(1165):     at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
09-11 22:25:01.664: E/AndroidRuntime(1165):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
09-11 22:25:01.664: E/AndroidRuntime(1165):     at java.util.concurrent.FutureTask.run(FutureTask.java:137)
09-11 22:25:01.664: E/AndroidRuntime(1165):     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
09-11 22:25:01.664: E/AndroidRuntime(1165):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
09-11 22:25:01.664: E/AndroidRuntime(1165):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
09-11 22:25:01.664: E/AndroidRuntime(1165):     at java.lang.Thread.run(Thread.java:856)
09-11 22:25:01.664: E/AndroidRuntime(1165): Caused by: java.lang.OutOfMemoryError
09-11 22:25:01.664: E/AndroidRuntime(1165):     at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
09-11 22:25:01.664: E/AndroidRuntime(1165):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:483)
09-11 22:25:01.664: E/AndroidRuntime(1165):     at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:351)
09-11 22:25:01.664: E/AndroidRuntime(1165):     at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:374)
09-11 22:25:01.664: E/AndroidRuntime(1165):     at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:404)
09-11 22:25:01.664: E/AndroidRuntime(1165):     at com.example.exampleimages.MyAdapter$BitmapWorkerTask.doInBackground(MyAdapter.java:92)
09-11 22:25:01.664: E/AndroidRuntime(1165):     at com.example.exampleimages.MyAdapter$BitmapWorkerTask.doInBackground(MyAdapter.java:1)
09-11 22:25:01.664: E/AndroidRuntime(1165):     at android.os.AsyncTask$2.call(AsyncTask.java:264)
09-11 22:25:01.664: E/AndroidRuntime(1165):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
09-11 22:25:01.664: E/AndroidRuntime(1165):     ... 5 more

这是我的 ListView 自定义适配器,AsyncTask 类在这个适配器中

class MyAdapter extends BaseAdapter {

    public Context context;
    private int[] images;

    public MyAdapter(Context context, int[] images) {
        this.context = context;
        this.images = images;
    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return images.length;
    }

    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return images[position];
    }

    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    public static class MyViewHolder {
        ImageView imageView;

        public MyViewHolder(View v) {
            // TODO Auto-generated constructor stub
            imageView = (ImageView) v.findViewById(R.id.imgView);
        }
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
        View row = convertView;
        MyViewHolder holder = null;
        if (row == null) {
            LayoutInflater inflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            row = inflater.inflate(R.layout.custom_list, parent, false);
            holder = new MyViewHolder(row);
            row.setTag(holder);
        } else {
            holder = (MyViewHolder) row.getTag();
        }
        // ImageView imageView = (ImageView) row.findViewById(R.id.imgView);
        if (holder.imageView != null) {
            new BitmapWorkerTask(holder.imageView).execute(images[position]);
        }
        //row = convertView;
        //holder.imageView.setImageResource(images[position]);
        //holder.imageView.setImageResource(R.drawable.samplenew003);
        return row;
    }

    class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
        private final WeakReference<ImageView> imageViewReference;
        private int data = 0;

        public BitmapWorkerTask(ImageView imageView) {
            // Use a WeakReference to ensure the ImageView can be garbage
            // collected
            imageViewReference = new WeakReference<ImageView>(imageView);
        }

        // Decode image in background.
        @Override
        protected Bitmap doInBackground(Integer... params) {
            data = params[0];
            // return decodeSampledBitmapFromResource(context.getResources(),
            // data, 100, 100);
            Bitmap bitmap = BitmapFactory.decodeResource(
                    context.getResources(), data);
            // Bitmap bitmap = Bitmap.createScaledBitmap(BitmapFactory
            // .decodeResource(context.getResources(), data), 750 , 1106, true);
            bitmap.compress(Bitmap.CompressFormat.PNG, 0, null); // compress

            // Bitmap bitmap =
            // BitmapBitmapFact.decodeResource(context.getResources(), data,
            // true);
            // bitmap.compress(Bitmap.CompressFormat.PNG, 90);
            return bitmap;
        }

        // Once complete, see if ImageView is still around and set bitmap.
        @Override
        protected void onPostExecute(Bitmap bitmap) {
            if (isCancelled()) {
                bitmap = null;
            }

            if (imageViewReference != null) {
                ImageView imageView = imageViewReference.get();
                if (bitmap != null) {
                    // final ImageView imageView = imageViewReference.get();
                    imageView.setImageBitmap(bitmap);
                } else {
                    imageView.setImageDrawable(imageView.getContext()
                            .getResources()
                            .getDrawable(R.drawable.samplenew003));
                }
            }
        }
    }

}

这是我的主要 Activity

public class MainActivity extends ActionBarActivity {

     private ListView listView;
     private MyAdapter myAdapter;
     int[] images = { R.drawable.img001, R.drawable.img002, R.drawable.img003,
     R.drawable.img004, R.drawable.img005, R.drawable.img006,
     R.drawable.img007, R.drawable.img008, R.drawable.img009,
     R.drawable.img010, R.drawable.img011, R.drawable.img012,
     R.drawable.img013, R.drawable.img014, R.drawable.img015,
     R.drawable.img016, R.drawable.img017, R.drawable.img018,
     R.drawable.img019, R.drawable.img020, R.drawable.img021,
     R.drawable.img022, R.drawable.img023, R.drawable.img024,
     R.drawable.img025, R.drawable.img026, R.drawable.img027,
     R.drawable.img028, R.drawable.img029, R.drawable.img030,
     R.drawable.img031, R.drawable.img032, R.drawable.img033,
     R.drawable.img034, R.drawable.img035, R.drawable.img036,
     R.drawable.img037, R.drawable.img038, R.drawable.img039,
     R.drawable.img040, R.drawable.img041, R.drawable.img042,
     R.drawable.img043, R.drawable.img044, R.drawable.img045,
     R.drawable.img046, R.drawable.img047, R.drawable.img048,
     R.drawable.img049, R.drawable.img050, R.drawable.img051,
     R.drawable.img052, R.drawable.img053, R.drawable.img054,
     R.drawable.img055, R.drawable.img056, R.drawable.img057,
     R.drawable.img058, R.drawable.img059, R.drawable.img060,
     R.drawable.img061, R.drawable.img062, R.drawable.img063,
     R.drawable.img064, R.drawable.img065, R.drawable.img066,
     R.drawable.img067, R.drawable.img068, R.drawable.img069,
     R.drawable.img070, R.drawable.img071, R.drawable.img072,
     R.drawable.img073, R.drawable.img074, R.drawable.img075,
     R.drawable.img076, R.drawable.img077, R.drawable.img078,
     R.drawable.img079, R.drawable.img080, R.drawable.img081,
     R.drawable.img082, R.drawable.img083, R.drawable.img084,
     R.drawable.img085, R.drawable.img086, R.drawable.img087,
     R.drawable.img088, R.drawable.img089, R.drawable.img090,
     R.drawable.img091, R.drawable.img092, R.drawable.img093,
     R.drawable.img094, R.drawable.img095, R.drawable.img096,
     R.drawable.img097, R.drawable.img098, R.drawable.img099,
     R.drawable.img100, R.drawable.img101, R.drawable.img102,

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myAdapter = new MyAdapter(this, images);
        listView = (ListView) findViewById(R.id.imgList);
        listView.setAdapter(myAdapter);
}

最佳答案

问题是Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), data);

您的图像太大,这就是您 3318016 字节分配内存不足的原因。

对于 bitmap.compress(Bitmap.CompressFormat.PNG, 0, null); 这里 0 表示图像质量尝试 8090

此外,请记住 getView() 每个位置可以调用 3-4 次。这意味着在您的异步完成之前,有 2-3 个 View 很可能会变得无效。您需要确保您正在适本地监视空值。此外,您错误地跟踪了哪些数据 int 与每个 View 相关。检查此项将有助于减少创建位图的次数,这可能会减少内存不足错误。这是调整后的代码:

class BitmapWorkerTask extends AsyncTask<Void, Void, Bitmap> {
    private final WeakReference<ImageView> imageViewReference;
    private int data = 0;

    public BitmapWorkerTask(ImageView imageView, int data) {
        //Used later to ensure imageview is the correct view for the data
        imageView.setTag(data);
        // Use a WeakReference to ensure the ImageView can be garbage collected
        imageViewReference = new WeakReference<ImageView>(imageView);

    }

    // Decode image in background.
    @Override
    protected Bitmap doInBackground(Void... params) {
        ImageView iv = imageViewReference.get();
        if (iv == null) return null;
        Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), data);

        if (bitmap != null) {
             bitmap.compress(Bitmap.CompressFormat.PNG, 0, null); // compress
        } else {
            //Load your default image here instead and return it instead
        }

        return bitmap;
    }

    // Once complete, see if ImageView is still around and set bitmap.
    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (isCancelled() || bitmap == null) {
            return;
        }

        ImageView imageView = imageViewReference.get();
        if (imageView != null) {
            int viewData = (Integer) imageView.getTag();
            if (viewData.equals(data)) {  //Make sure our view reference still represents that data we originally started with (This happens due to view recycling)
                imageView.setImageBitmap(bitmap);
            }
        }
    }
}

据我所知,您需要针对何时加载默认图形提出不同的解决方案。

关于android - 无法使用 AsyncTask 在 ListView 中加载图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25793984/

相关文章:

android - 如何在 Android 的 ListView 中隐藏项目

android - 关闭键盘时渐变背景变白(仅当 ListView 有项目时)

android - 将 HashMap 传递给 AsyncTask 并将其转换为 JSONObject

android - Google Maps API V2 addMarker 和 OnCameraChangeListener

android - 使用 XmlResourceParser 解析内部存储中的 xml 文件

java - 使用 SimpleDateFormat 无法解析的日期

java - 将类型为 class 的变量分配给扩展声明的变量类型的不同类

java - ArrayAdapter 中的 OnClickListener 正在对错误的行执行操作

java - 完成后,从 AsyncTask 终止网络服务发现而不会泄漏

android获取 View 的所有 subview