2016-06-12 71 views
0

我正在通过AsyncTask下载多个图像。有2-3张图片时效果很好;但是,如果有更多图像,则会创建许多AsyncTask实例,并导致错误。有没有人有一个想法如何克服这个问题?下载AsyncTask线程中的多重图像会导致错误

+0

您正在从列表视图中加载图像? – USKMobility

+0

什么是错误,发布logtrace! –

+0

类的拼写,语法,语法和命名。 – Ben

回答

0

你可以在这里添加你的代码吗?

也许你可以尝试使用onPostExecute您的AsyncTask的功能,开始一个新的名字:

protected void onPostExecute() { 
    doInBackground(); 
} 

,或者你可以通过你的onPostExecute触发的活动()函数中开始下载“下一张图片”等等它只会创建一个asynctask一次。

0

从Android电子文档:普通的视图组件如ListView和GridView的 结合的AsyncTask用作 前一节中所示,当引入的另一个问题。为了高效利用内存,这些组件在用户滚动时回收子视图。如果 每个子视图都触发AsyncTask,则不能保证当 它完成时,相关视图尚未被回收,用于在另一个子视图中使用 。此外,不保证异步任务启动的顺序是它们完成的顺序。

Handle Concurrency

http://android-developers.blogspot.in/2010/07/multithreading-for-performance.html

public class ImageDownloader { 
     private static final String LOG_TAG = "ImageDownloader"; 

     public enum Mode { NO_ASYNC_TASK, NO_DOWNLOADED_DRAWABLE, CORRECT } 
     private Mode mode = Mode.NO_ASYNC_TASK; 

     /** 
     * Download the specified image from the Internet and binds it to the provided ImageView. The 
     * binding is immediate if the image is found in the cache and will be done asynchronously 
     * otherwise. A null bitmap will be associated to the ImageView if an error occurs. 
     * 
     * @param url The URL of the image to download. 
     * @param imageView The ImageView to bind the downloaded image to. 
     */ 
     public void download(String url, ImageView imageView) { 
      resetPurgeTimer(); 
      Bitmap bitmap = getBitmapFromCache(url); 

      if (bitmap == null) { 
       forceDownload(url, imageView); 
      } else { 
       cancelPotentialDownload(url, imageView); 
       imageView.setImageBitmap(bitmap); 
      } 
     } 

     /* 
     * Same as download but the image is always downloaded and the cache is not used. 
     * Kept private at the moment as its interest is not clear. 
      private void forceDownload(String url, ImageView view) { 
       forceDownload(url, view, null); 
      } 
     */ 

     /** 
     * Same as download but the image is always downloaded and the cache is not used. 
     * Kept private at the moment as its interest is not clear. 
     */ 
     private void forceDownload(String url, ImageView imageView) { 
      // State sanity: url is guaranteed to never be null in DownloadedDrawable and cache keys. 
      if (url == null) { 
       imageView.setImageDrawable(null); 
       return; 
      } 

      if (cancelPotentialDownload(url, imageView)) { 
       switch (mode) { 
        case NO_ASYNC_TASK: 
         Bitmap bitmap = downloadBitmap(url); 
         addBitmapToCache(url, bitmap); 
         imageView.setImageBitmap(bitmap); 
         break; 

        case NO_DOWNLOADED_DRAWABLE: 
         imageView.setMinimumHeight(156); 
         BitmapDownloaderTask task = new BitmapDownloaderTask(imageView); 
         task.execute(url); 
         break; 

        case CORRECT: 
         task = new BitmapDownloaderTask(imageView); 
         DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task); 
         imageView.setImageDrawable(downloadedDrawable); 
         imageView.setMinimumHeight(156); 
         task.execute(url); 
         break; 
       } 
      } 
     } 

     /** 
     * Returns true if the current download has been canceled or if there was no download in 
     * progress on this image view. 
     * Returns false if the download in progress deals with the same url. The download is not 
     * stopped in that case. 
     */ 
     private static boolean cancelPotentialDownload(String url, ImageView imageView) { 
      BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView); 

      if (bitmapDownloaderTask != null) { 
       String bitmapUrl = bitmapDownloaderTask.url; 
       if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) { 
        bitmapDownloaderTask.cancel(true); 
       } else { 
        // The same URL is already being downloaded. 
        return false; 
       } 
      } 
      return true; 
     } 

     /** 
     * @param imageView Any imageView 
     * @return Retrieve the currently active download task (if any) associated with this imageView. 
     * null if there is no such task. 
     */ 
     private static BitmapDownloaderTask getBitmapDownloaderTask(ImageView imageView) { 
      if (imageView != null) { 
       Drawable drawable = imageView.getDrawable(); 
       if (drawable instanceof DownloadedDrawable) { 
        DownloadedDrawable downloadedDrawable = (DownloadedDrawable)drawable; 
        return downloadedDrawable.getBitmapDownloaderTask(); 
       } 
      } 
      return null; 
     } 

     Bitmap downloadBitmap(String url) { 
      final int IO_BUFFER_SIZE = 4 * 1024; 

      // AndroidHttpClient is not allowed to be used from the main thread 
      final HttpClient client = (mode == Mode.NO_ASYNC_TASK) ? new DefaultHttpClient() : 
       AndroidHttpClient.newInstance("Android"); 
      final HttpGet getRequest = new HttpGet(url); 

      try { 
       HttpResponse response = client.execute(getRequest); 
       final int statusCode = response.getStatusLine().getStatusCode(); 
       if (statusCode != HttpStatus.SC_OK) { 
        Log.w("ImageDownloader", "Error " + statusCode + 
          " while retrieving bitmap from " + url); 
        return null; 
       } 

       final HttpEntity entity = response.getEntity(); 
       if (entity != null) { 
        InputStream inputStream = null; 
        try { 
         inputStream = entity.getContent(); 
         // return BitmapFactory.decodeStream(inputStream); 
         // Bug on slow connections, fixed in future release. 
         return BitmapFactory.decodeStream(new FlushedInputStream(inputStream)); 
        } finally { 
         if (inputStream != null) { 
          inputStream.close(); 
         } 
         entity.consumeContent(); 
        } 
       } 
      } catch (IOException e) { 
       getRequest.abort(); 
       Log.w(LOG_TAG, "I/O error while retrieving bitmap from " + url, e); 
      } catch (IllegalStateException e) { 
       getRequest.abort(); 
       Log.w(LOG_TAG, "Incorrect URL: " + url); 
      } catch (Exception e) { 
       getRequest.abort(); 
       Log.w(LOG_TAG, "Error while retrieving bitmap from " + url, e); 
      } finally { 
       if ((client instanceof AndroidHttpClient)) { 
        ((AndroidHttpClient) client).close(); 
       } 
      } 
      return null; 
     } 

     /* 
     * An InputStream that skips the exact number of bytes provided, unless it reaches EOF. 
     */ 
     static class FlushedInputStream extends FilterInputStream { 
      public FlushedInputStream(InputStream inputStream) { 
       super(inputStream); 
      } 

      @Override 
      public long skip(long n) throws IOException { 
       long totalBytesSkipped = 0L; 
       while (totalBytesSkipped < n) { 
        long bytesSkipped = in.skip(n - totalBytesSkipped); 
        if (bytesSkipped == 0L) { 
         int b = read(); 
         if (b < 0) { 
          break; // we reached EOF 
         } else { 
          bytesSkipped = 1; // we read one byte 
         } 
        } 
        totalBytesSkipped += bytesSkipped; 
       } 
       return totalBytesSkipped; 
      } 
     } 

     /** 
     * The actual AsyncTask that will asynchronously download the image. 
     */ 
     class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> { 
      private String url; 
      private final WeakReference<ImageView> imageViewReference; 

      public BitmapDownloaderTask(ImageView imageView) { 
       imageViewReference = new WeakReference<ImageView>(imageView); 
      } 

      /** 
      * Actual download method. 
      */ 
      @Override 
      protected Bitmap doInBackground(String... params) { 
       url = params[0]; 
       return downloadBitmap(url); 
      } 

      /** 
      * Once the image is downloaded, associates it to the imageView 
      */ 
      @Override 
      protected void onPostExecute(Bitmap bitmap) { 
       if (isCancelled()) { 
        bitmap = null; 
       } 

       addBitmapToCache(url, bitmap); 

       if (imageViewReference != null) { 
        ImageView imageView = imageViewReference.get(); 
        BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView); 
        // Change bitmap only if this process is still associated with it 
        // Or if we don't use any bitmap to task association (NO_DOWNLOADED_DRAWABLE mode) 
        if ((this == bitmapDownloaderTask) || (mode != Mode.CORRECT)) { 
         imageView.setImageBitmap(bitmap); 
        } 
       } 
      } 
     } 


     /** 
     * A fake Drawable that will be attached to the imageView while the download is in progress. 
     * 
     * <p>Contains a reference to the actual download task, so that a download task can be stopped 
     * if a new binding is required, and makes sure that only the last started download process can 
     * bind its result, independently of the download finish order.</p> 
     */ 
     static class DownloadedDrawable extends ColorDrawable { 
      private final WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference; 

      public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) { 
       super(Color.BLACK); 
       bitmapDownloaderTaskReference = 
        new WeakReference<BitmapDownloaderTask>(bitmapDownloaderTask); 
      } 

      public BitmapDownloaderTask getBitmapDownloaderTask() { 
       return bitmapDownloaderTaskReference.get(); 
      } 
     } 

     public void setMode(Mode mode) { 
      this.mode = mode; 
      clearCache(); 
     } 


     /* 
     * Cache-related fields and methods. 
     * 
     * We use a hard and a soft cache. A soft reference cache is too aggressively cleared by the 
     * Garbage Collector. 
     */ 

     private static final int HARD_CACHE_CAPACITY = 10; 
     private static final int DELAY_BEFORE_PURGE = 10 * 1000; // in milliseconds 

     // Hard cache, with a fixed maximum capacity and a life duration 
     private final HashMap<String, Bitmap> sHardBitmapCache = 
      new LinkedHashMap<String, Bitmap>(HARD_CACHE_CAPACITY/2, 0.75f, true) { 
      @Override 
      protected boolean removeEldestEntry(LinkedHashMap.Entry<String, Bitmap> eldest) { 
       if (size() > HARD_CACHE_CAPACITY) { 
        // Entries push-out of hard reference cache are transferred to soft reference cache 
        sSoftBitmapCache.put(eldest.getKey(), new SoftReference<Bitmap>(eldest.getValue())); 
        return true; 
       } else 
        return false; 
      } 
     }; 

     // Soft cache for bitmaps kicked out of hard cache 
     private final static ConcurrentHashMap<String, SoftReference<Bitmap>> sSoftBitmapCache = 
      new ConcurrentHashMap<String, SoftReference<Bitmap>>(HARD_CACHE_CAPACITY/2); 

     private final Handler purgeHandler = new Handler(); 

     private final Runnable purger = new Runnable() { 
      public void run() { 
       clearCache(); 
      } 
     }; 

     /** 
     * Adds this bitmap to the cache. 
     * @param bitmap The newly downloaded bitmap. 
     */ 
     private void addBitmapToCache(String url, Bitmap bitmap) { 
      if (bitmap != null) { 
       synchronized (sHardBitmapCache) { 
        sHardBitmapCache.put(url, bitmap); 
       } 
      } 
     } 

     /** 
     * @param url The URL of the image that will be retrieved from the cache. 
     * @return The cached bitmap or null if it was not found. 
     */ 
     private Bitmap getBitmapFromCache(String url) { 
      // First try the hard reference cache 
      synchronized (sHardBitmapCache) { 
       final Bitmap bitmap = sHardBitmapCache.get(url); 
       if (bitmap != null) { 
        // Bitmap found in hard cache 
        // Move element to first position, so that it is removed last 
        sHardBitmapCache.remove(url); 
        sHardBitmapCache.put(url, bitmap); 
        return bitmap; 
       } 
      } 

      // Then try the soft reference cache 
      SoftReference<Bitmap> bitmapReference = sSoftBitmapCache.get(url); 
      if (bitmapReference != null) { 
       final Bitmap bitmap = bitmapReference.get(); 
       if (bitmap != null) { 
        // Bitmap found in soft cache 
        return bitmap; 
       } else { 
        // Soft reference has been Garbage Collected 
        sSoftBitmapCache.remove(url); 
       } 
      } 

      return null; 
     } 

     /** 
     * Clears the image cache used internally to improve performance. Note that for memory 
     * efficiency reasons, the cache will automatically be cleared after a certain inactivity delay. 
     */ 
     public void clearCache() { 
      sHardBitmapCache.clear(); 
      sSoftBitmapCache.clear(); 
     } 

     /** 
     * Allow a new delay before the automatic cache clear is done. 
     */ 
     private void resetPurgeTimer() { 
      purgeHandler.removeCallbacks(purger); 
      purgeHandler.postDelayed(purger, DELAY_BEFORE_PURGE); 
     } 
    } 
0

你可以使用Android的Vinci图书馆的testet和支持Concurrency及其版本之上

  • Builder模式
  • 仙gleton模式
  • 回调格局

及其手柄下载由她自己和其易于使用的多图像。

如果你想获得每次下载请求的结果:

Vinci 
    .base(context) 
    .process() 
    .load(uri, 
     new Request() { 
        @Override 
        public void onSuccess(Bitmap bitmap) { 
         viewHolder.Writer.setImageBitmap(bitmap); 
         //or 
         //do some thing with bitmap 
        } 

        @Override 
        public void onFailure(Throwable e) { 
         Log.e(e.getClass().getSimpleName(), e.getMessage()); 
        } 
      }); 

如果ImageView你想要显示的图像,你可以使用它像这样

Vinci 
    .base(context) 
    .process() 
    .load(uri) 
    .view(imageView); 

使用它RecycleView看到这个wiki page

0

只需使用Picasso库将图像加载到ImageView中,因为它非常易于使用,并且也非常容易支持并发。 例如:

Picasso.with(this.context).load(url_of_image).into(imageView); 
相关问题