【问题标题】:Preventing application from hanging while image is downloading?下载图像时防止应用程序挂起?
【发布时间】:2012-05-25 20:24:35
【问题描述】:

我正在使用 ListView 来显示与这些图像相关的一些图像和标题。我正在从互联网上获取图像。有没有办法延迟加载图像,以便在显示文本时,UI 不会锁定,并且在下载图像时会显示图像。图片数量不固定。

更新:

(使用下面的代码,我尝试下载图像并在 ListView 中显示)

Bitmap bmImg; Bitmap downloadFile(String fileUrl) 
{ 
 URL myFileUrl = null; 
  try { 
      myFileUrl = new URL(fileUrl); 
   } 
   catch (MalformedURLException e) 
   { 
      e.printStackTrace(); 
   } 

   try { 
     HttpURLConnection conn = (HttpURLConnection) myFileUrl .openConnection(); 
    conn.setDoInput(true); 
    conn.connect(); 
    InputStream is = conn.getInputStream(); 
    bmImg = BitmapFactory.decodeStream(is); 
   } catch (IOException e) 
    { 
        e.printStackTrace(); 
   } 
    return bmImg; 
  } 

【问题讨论】:

  • 请发布代码。我还发布了如何执行下载并添加到列表视图中?
  • 位图 bmImg;位图 downloadFile(String fileUrl) { URL myFileUrl = null;尝试 { myFileUrl = 新 URL(fileUrl); } catch (MalformedURLException e) { e.printStackTrace(); } 尝试 { HttpURLConnection conn = (HttpURLConnection) myFileUrl .openConnection(); conn.setDoInput(true);连接.connect(); InputStream = conn.getInputStream(); bmImg = BitmapFactory.decodeStream(is); } catch (IOException e) { e.printStackTrace(); } 返回 bmImg; }
  • 在网上搜索时,我发现了一些有趣的链接来解决您的问题 - github.com/thest1/LazyList - codehenge.net/blog/2011/06/… 希望这些对您有所帮助

标签: android performance process download


【解决方案1】:
import java.io.IOException;

public class DrawableManager {
    private final Map<String, Drawable> drawableMap;

    public DrawableManager() {
        drawableMap = new HashMap<String, Drawable>();
    }

    public Drawable fetchDrawable(String urlString) {
        if (drawableMap.containsKey(urlString)) {
            return drawableMap.get(urlString);
        }

        Log.d(this.getClass().getSimpleName(), "image url:" + urlString);
        try {
            InputStream is = fetch(urlString);
            Drawable drawable = Drawable.createFromStream(is, "src");


            if (drawable != null) {
                drawableMap.put(urlString, drawable);
                Log.d(this.getClass().getSimpleName(), "got a thumbnail drawable: " + drawable.getBounds() + ", "
                        + drawable.getIntrinsicHeight() + "," + drawable.getIntrinsicWidth() + ", "
                        + drawable.getMinimumHeight() + "," + drawable.getMinimumWidth());
            } else {
              Log.w(this.getClass().getSimpleName(), "could not get thumbnail");
            }

            return drawable;
        } catch (MalformedURLException e) {
            Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
            return null;
        } catch (IOException e) {
            Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
            return null;
        }
    }

    public void fetchDrawableOnThread(final String urlString, final ImageView imageView) {
        if (drawableMap.containsKey(urlString)) {
            imageView.setImageDrawable(drawableMap.get(urlString));
        }

        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message message) {
                imageView.setImageDrawable((Drawable) message.obj);
            }
        };

        Thread thread = new Thread() {
            @Override
            public void run() {
                //TODO : set imageView to a "pending" image
                Drawable drawable = fetchDrawable(urlString);
                Message message = handler.obtainMessage(1, drawable);
                handler.sendMessage(message);
            }
        };
        thread.start();
    }

    private InputStream fetch(String urlString) throws MalformedURLException, IOException {
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpGet request = new HttpGet(urlString);
        HttpResponse response = httpClient.execute(request);
        return response.getEntity().getContent();
    }

}

【讨论】:

    【解决方案2】:

    我在这里读到你的问题是尝试这个的代码......

    公共类 ImageDownloader { private static final String LOG_TAG = "ImageDownloader";

    public enum Mode {
        NO_ASYNC_TASK, NO_DOWNLOADED_DRAWABLE, CORRECT
    }
    
    private Mode mode = Mode.CORRECT;
    
    /**
     * 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) {
    
        if (url != null && !url.isEmpty()) {
            url = url.replaceAll(" ", "%20");
            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.WHITE);
            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 = 1000;
    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();
            System.gc();
        }
    };
    
    /**
     * 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);
    }
    

    }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-12-22
      • 1970-01-01
      • 2023-03-04
      • 1970-01-01
      • 1970-01-01
      • 2014-11-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多