【问题标题】:Android :: Download Image cause An error occurred while executing doInBackground()Android :: 下载图片原因执行doInBackground()时出错
【发布时间】:2014-06-29 09:17:30
【问题描述】:

问题

我正在实现自定义 ListView,它在一个列表视图中有 3 种不同的布局。

在 ListView 中的每个项目执行 AsyncTask 之前一切正常

用于下载图像并在 ImageView 中设置。而这个过程应用强制关闭...

注意

我无法在此处提供所有代码,因为它太长了。

但是,自定义 ListView 的所有过程都可以正常工作,我通过剪切 AsyncTask 部分进行了测试。

请假设在这种情况下所需数据已准备好并且已设置互联网连接。

INTEREST_ADAPTER 类

 @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View v = convertView;
        ViewHolder_Type1 vh1 = null;
        ViewHolder_Type2 vh2 = null;
        ViewHolder_Type3 vh3 = null;
        int type = getItemViewType(position);

        /* initiate setup view */
        if (v == null){
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            switch (type) {
                case LAYOUT_TYPE1 :
                    v = inflater.inflate(R.layout.listview_interest_type1,null);
                    vh1 = new ViewHolder_Type1();
                    vh1.imgHeading = (ImageView) v.findViewById(R.id.imgHeading);
                    vh1.imgUser    = (ImageView) v.findViewById(R.id.imgUserPic);
                    vh1.tvHeading  = (TextView) v.findViewById(R.id.tvHeading);
                    vh1.tvUserName = (TextView) v.findViewById(R.id.tvUserName);
                    vh1.tvPostTime = (TextView) v.findViewById(R.id.tvPostTime);
                    vh1.tvCategory = (TextView) v.findViewById(R.id.tvCategory);
                    v.setTag(vh1);
                    break;
                case  LAYOUT_TYPE2 :
                    v = inflater.inflate(R.layout.listview_interest_type2,null);
                    vh2 = new ViewHolder_Type2();
                    vh2.imgUser    = (ImageView) v.findViewById(R.id.imgUserPic);
                    vh2.tvHeading  = (TextView) v.findViewById(R.id.tvHeading);
                    vh2.tvBody     = (TextView) v.findViewById(R.id.tvBody);
                    vh2.tvUserName = (TextView) v.findViewById(R.id.tvUserName);
                    vh2.tvPostTime = (TextView) v.findViewById(R.id.tvPostTime);
                    vh2.tvCategory = (TextView) v.findViewById(R.id.tvCategory);
                    v.setTag(vh2);
                    break;
                case  LAYOUT_TYPE3 :
                    v = inflater.inflate(R.layout.listview_interest_type3,null);
                    vh3 = new ViewHolder_Type3();
                    vh3.imgGallery = (ImageView) v.findViewById(R.id.imgGallery);
                    vh3.imgUser    = (ImageView) v.findViewById(R.id.imgUserPic);
                    vh3.tvHeading  = (TextView) v.findViewById(R.id.tvTitle);
                    vh3.tvUserName = (TextView) v.findViewById(R.id.tvUserName);
                    vh3.tvCategory = (TextView) v.findViewById(R.id.tvCategory);
                    v.setTag(vh3);
                    break;
            }
        } else {
            switch (type) {
                case LAYOUT_TYPE1 :
                    vh1 = (ViewHolder_Type1) v.getTag();
                    break;
                case LAYOUT_TYPE2 :
                    vh2 = (ViewHolder_Type2) v.getTag();
                    break;
                case LAYOUT_TYPE3 :
                    vh3 = (ViewHolder_Type3) v.getTag();
                    break;
            }
        }


        /* initiate setup data */

        Interest_ListView interestListView = interestListViews.get(position);

        String imgHeading = interestListView.img_heading.replaceAll(" ","%20");
        String imgGallery = interestListView.img_gallery.replaceAll(" ","%20");
        String heading    = interestListView.post_heading;
        String body       = interestListView.post_body;
        String username   = interestListView.user_name;
        String userAvatar = interestListView.user_avatar.replaceAll(" ","%20");
        String categories = interestListView.post_categories;
        String second     = interestListView.second;
        String minutes    = interestListView.minutes;
        String hour       = interestListView.hour;
        String days       = interestListView.days;

        switch (type) {

            case LAYOUT_TYPE1 :

                vh1.tvHeading.setText(heading);
                vh1.tvUserName.setText(username);
                vh1.tvPostTime.setText(getTime(second, minutes, hour, days));
                vh1.tvCategory.setText(categories);
                vh1.asyncHeading = new downloadImageTask(vh1.imgHeading, context);
                vh1.asyncHeading.execute(imgHeading);
                vh1.asyncUser = new downloadImageTask(vh1.imgUser, context);
                vh1.asyncUser.execute(imgHeading);
                v.setTag(vh1);

                break;

            case LAYOUT_TYPE2 :

                vh2.tvHeading.setText(heading);
                vh2.tvBody.setText(body);
                vh2.tvUserName.setText(username);
                vh2.tvPostTime.setText(getTime(second, minutes, hour, days));
                vh2.tvCategory.setText(categories);
                vh2.urlUser = userAvatar;
//                new downloadImageTask(vh2.imgUser, context).execute(userAvatar);
                v.setTag(vh2);

                break;

            case LAYOUT_TYPE3 :

                vh3.tvHeading.setText(heading);
                vh3.tvUserName.setText(username);
                vh3.tvCategory.setText(categories);
                vh3.urlGallery = imgGallery;
                vh3.urlUser = userAvatar;
//                new downloadImageTask(vh3.imgGallery, context).doInBackground(imgGallery);
//                new downloadImageTask(vh3.imgUser, context).doInBackground(userAvatar);
                v.setTag(vh3);

                break;
        }

        return v;
    }


    public static class ViewHolder_Type1{
        ImageView imgHeading, imgUser;
        TextView tvHeading,tvUserName, tvPostTime, tvCategory;
        String urlHeading, urlUser;
        downloadImageTask asyncHeading, asyncUser;
    }
    public static class ViewHolder_Type2{
        ImageView imgUser;
        TextView tvHeading, tvBody, tvUserName, tvPostTime, tvCategory;
        String urlUser;
    }
    public static class ViewHolder_Type3{
        ImageView imgUser, imgGallery;
        TextView tvHeading, tvUserName, tvCategory;
        String urlUser, urlGallery;
    }

    private static class downloadImageTask extends AsyncTask<String, Integer, Bitmap> {

        ImageView imgContainer;
        Context context;

        private downloadImageTask(ImageView imgContainer, Context context) {
            this.imgContainer = imgContainer;
            this.context = context;
        }

        protected Bitmap doInBackground(String... urls) {
            Bitmap getBitmap = null;
            int count = urls.length;
            for (int i = 0; i < count; i++) {
                try {
                    URL url = new URL(urls[i]);
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    connection.setDoInput(true);
                    connection.connect();
                    InputStream input = connection.getInputStream();
                    getBitmap = BitmapFactory.decodeStream(input);      //LINE 256 IS HERE

                } catch (IOException e) {
                    e.printStackTrace();
                    getBitmap = null;
                }
            }
            return getBitmap;
        }


        protected void onProgressUpdate(Integer... progress) {
            //setProgressPercent(progress[0]);
        }

        protected void onPostExecute(Bitmap result) {
            Drawable dr = new BitmapDrawable(context.getResources(), result);
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                //Methods for version <16 (JELLY_BEAN 4.1)
                imgContainer.setBackgroundDrawable(dr);
            } else {
                // Methods for version >=16 (JELLY_BEAN 4.1)
                imgContainer.setBackground(dr);
            }
        }
    }

LOGCAT

06-29 16:02:05.435    2125-2143/com.bis.org.auInsight W/dalvikvm﹕ threadid=13: thread exiting with uncaught exception (group=0xb5fe8180)
06-29 16:02:05.435    2125-2143/com.bis.org.auInsight E/AndroidRuntime﹕ FATAL EXCEPTION: AsyncTask #2
    java.lang.RuntimeException: An error occured while executing doInBackground()
            at android.os.AsyncTask$3.done(AsyncTask.java:278)
            at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
            at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
            at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
            at java.util.concurrent.FutureTask.run(FutureTask.java:137)
            at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
            at java.lang.Thread.run(Thread.java:856)
     Caused by: java.lang.OutOfMemoryError
            at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
            at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:493)
            at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:549)
            at com.bis.org.auInsight.interest.Interest_Adapter$downloadImageTask.doInBackground(Interest_Adapter.java:256)
            at com.bis.org.auInsight.interest.Interest_Adapter$downloadImageTask.doInBackground(Interest_Adapter.java:236)
            at android.os.AsyncTask$2.call(AsyncTask.java:264)
            at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
            at java.util.concurrent.FutureTask.run(FutureTask.java:137)
            at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
            at java.lang.Thread.run(Thread.java:856)
06-29 16:02:05.594    2125-2144/com.bis.org.auInsight I/dalvikvm-heap﹕ Clamp target GC heap from 16.347MB to 16.000MB
06-29 16:02:05.594    2125-2144/com.bis.org.auInsight D/dalvikvm﹕ GC_FOR_ALLOC freed 78K, 2% free 14636K/14855K, paused 6ms
06-29 16:02:05.594    2125-2144/com.bis.org.auInsight I/dalvikvm-heap﹕ Forcing collection of SoftReferences for 6000012-byte allocation
06-29 16:02:05.604    2125-2144/com.bis.org.auInsight I/dalvikvm-heap﹕ Clamp target GC heap from 16.346MB to 16.000MB
06-29 16:02:05.614    2125-2144/com.bis.org.auInsight D/dalvikvm﹕ GC_BEFORE_OOM freed <1K, 2% free 14635K/14855K, paused 20ms
06-29 16:02:05.614    2125-2144/com.bis.org.auInsight E/dalvikvm-heap﹕ Out of memory on a 6000012-byte allocation.
06-29 16:02:05.614    2125-2144/com.bis.org.auInsight I/dalvikvm﹕ "AsyncTask #3" prio=5 tid=14 RUNNABLE
06-29 16:02:05.614    2125-2144/com.bis.org.auInsight I/dalvikvm﹕ | group="main" sCount=0 dsCount=0 obj=0xb6695790 self=0x91c30b8
06-29 16:02:05.614    2125-2144/com.bis.org.auInsight I/dalvikvm﹕ | sysTid=2144 nice=10 sched=3/0 cgrp=[fopen-error:2] handle=153307736
06-29 16:02:05.614    2125-2144/com.bis.org.auInsight I/dalvikvm﹕ | schedstat=( 0 0 0 ) utm=1 stm=0 core=0
06-29 16:02:05.614    2125-2144/com.bis.org.auInsight I/dalvikvm﹕ at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
06-29 16:02:05.614    2125-2144/com.bis.org.auInsight I/dalvikvm﹕ at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:493)
06-29 16:02:05.614    2125-2144/com.bis.org.auInsight I/dalvikvm﹕ at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:549)
06-29 16:02:05.614    2125-2144/com.bis.org.auInsight I/dalvikvm﹕ at com.bis.org.auInsight.interest.Interest_Adapter$downloadImageTask.doInBackground(Interest_Adapter.java:256)
06-29 16:02:05.614    2125-2144/com.bis.org.auInsight I/dalvikvm﹕ at com.bis.org.auInsight.interest.Interest_Adapter$downloadImageTask.doInBackground(Interest_Adapter.java:236)
06-29 16:02:05.614    2125-2144/com.bis.org.auInsight I/dalvikvm﹕ at android.os.AsyncTask$2.call(AsyncTask.java:264)
06-29 16:02:05.614    2125-2144/com.bis.org.auInsight I/dalvikvm﹕ at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
06-29 16:02:05.614    2125-2144/com.bis.org.auInsight I/dalvikvm﹕ at java.util.concurrent.FutureTask.run(FutureTask.java:137)
06-29 16:02:05.614    2125-2144/com.bis.org.auInsight I/dalvikvm﹕ at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
06-29 16:02:05.614    2125-2144/com.bis.org.auInsight I/dalvikvm﹕ at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
06-29 16:02:05.614    2125-2144/com.bis.org.auInsight I/dalvikvm﹕ at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
06-29 16:02:05.614    2125-2144/com.bis.org.auInsight I/dalvikvm﹕ at java.lang.Thread.run(Thread.java:856)
06-29 16:02:05.614    2125-2144/com.bis.org.auInsight I/dalvikvm﹕ [ 06-29 16:02:05.614  2125:0x860 D/skia     ]

【问题讨论】:

  • Caused by: java.lang.OutOfMemoryError
  • 哇,应该有什么方法来防止这种情况??

标签: android listview android-listview android-asynctask


【解决方案1】:

BitmapFactory 可以为图像分配内存。为您下载的每个图像生成一个单独的AsyncTask 可能会更好。特别是因为您当前只从AsyncTask 返回一个Bitmap,从而使整个循环变得无用。

为了提高性能,您还可以将图像缩小到较小的尺寸,但请注意不要损失太多质量:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
getBitmap = BitmapFactory.decodeStream(input, null, options);

参考:BitmapFactory.Options documentation

【讨论】:

  • 抱歉,您所说的“为每个图像生成一个单独的 AsyncTask”是什么意思。
  • 您在AsyncTask 中下载了多张图片,但只返回了一张。为您要下载的每个图像创建一个单独的AsyncTask,并省略下载多个图像的循环。
【解决方案2】:

您检索到的图像太大,这意味着它在您的堆中消耗了太多空间,导致堆溢出,因此应用程序崩溃,您可以使用ImageLoader 下载图像,因为这样您将有能力控制下载的图像大小、压缩率、分辨率、内存消耗和许多其他选项:

DisplayImageOptions options = new DisplayImageOptions.Builder()
                    .bitmapConfig(Bitmap.Config.ALPHA_8)
                    .imageScaleType(ImageScaleType.IN_SAMPLE_INT).build();
    ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
                    ISolaceContext.getAppContext())
                    .discCacheExtraOptions(20, 20, CompressFormat.JPEG, 100, null)
                    .defaultDisplayImageOptions(options).build();
    ImageLoader.getInstance().init(config);
    ImageLoader loader = ImageLoader.getInstance();

    loader.loadImage(url, new SimpleImageLoadingListener() {

       @Override
       public void onLoadingComplete(String imageUri, View view,
                                Bitmap loadedImage) {
          // Now you have the image in your hands as a Bitmap(called: loadedImage) and Now you can do whatever you want with it
          stream.close();
          stream = null;
       }

    });

    loader.clearDiscCache();
    loader.clearMemoryCache();

【讨论】:

    【解决方案3】:

    当列表中有多个图像时,滚动后内存已满,现在无法分配内存,而且您的方法不会回收先前图像占用的内存,并且只有在巨大的 RAM 可用时才能运行。尝试使用Univesal-Image-Loader,它使用 LruCache 进行内存管理,并尝试运行此示例并根据需要修改您的代码!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-05
      • 2015-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多