Android:在不使用AsyncTask的情况下从Web加载图像的最佳方法是什么?

时间:2011-10-25 04:16:04

标签: android

Android开发中的常见任务是从Web加载图像并在Activity中与ImageView绑定。在我看过的代码中,程序员经常使用AsyncTask在后台运行加载并在上下文中发布结果。 这种方法使我们在某些情况下开始使用,因为方向改变。原因是背景。因为活动可能被销毁并再次创建,我们的上下文也将丢失,但在运行AsyncTask时,上下文不会更新。因此,当调用postExectute时,AsyncTask会尝试将结果发布到不再存在的

我想知道您使用什么方法将数据加载为图像,然后发布到Activity?

2 个答案:

答案 0 :(得分:4)

您应该尝试使用所谓的AsyncTaskLoader。它就像一个AsycnTask,除了整个“需要在活动死亡时删除AsyncTask”位时才会为你处理。一般来说,加载程序几乎专门用于改进异步加载listviews数据的任务。事实上,他们很快成为我最喜欢的新Android类之一。有关加载器的更多信息,请查看此documentation

作为最后一点,在API级别10之前不会引入加载器。也就是说,您仍然可以使用android Support Package从较小的api级别访问它们。

答案 1 :(得分:0)

以下是在后台加载图像并将其存储到sdcard的完整代码。如果图像已经存在,则它不会向服务器发出请求。 包com.packsmooch.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Stack;


import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.ImageView;

public class Albumartloader 
{
    private HashMap<String, Bitmap> cache = new HashMap<String, Bitmap>();

    private File cacheDir;
    private Bitmap  useThisBitmap;

    public Albumartloader(Context context) 
    {   
        photoLoaderThread.setPriority(Thread.NORM_PRIORITY - 1);
        if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
            cacheDir = new File(android.os.Environment.getExternalStorageDirectory(),"Streaming_Service/AlbumArt/");
        else
            cacheDir = context.getCacheDir();

        if (!cacheDir.exists())
            cacheDir.mkdirs();
    }

    public void DisplayImage(String url, Activity activity, ImageView imageView) 
    {
         if(!url.equals(""))
         {
             if (cache.containsKey(url))
             {
                 imageView.setImageBitmap(cache.get(url));
             }
             else
             {
                queuePhoto(url, activity, imageView);
            }
         }
    }

    private void queuePhoto(String url, Activity activity, ImageView imageView) 
    {
        photosQueue.Clean(imageView);
        PhotoToLoad p = new PhotoToLoad(url, imageView);

        synchronized (photosQueue.photosToLoad) 
        {
            photosQueue.photosToLoad.push(p);
            photosQueue.photosToLoad.notifyAll();
        }

        // start thread if it's not started yet
        if (photoLoaderThread.getState() == Thread.State.NEW)
            photoLoaderThread.start();
    }

    public Bitmap getBitmap(String url) 
    {
        try
        {
            // I identify images by hashcode. Not a perfect solution, good for the
            // demo.
            String filename = String.valueOf(url.hashCode());
            File f = new File(cacheDir, filename);

            // from SD cache
            Bitmap b = decodeFile(f);
            if (b != null)
                return b;

            // from web
            try {
                Bitmap bitmap = null;       
                if(!url.equals("")){
                InputStream is = new URL(url).openStream();
                OutputStream os = new FileOutputStream(f);
                Utils.CopyStream(is, os);
                os.close();
                bitmap = decodeFile(f);
                }
                return bitmap;
            } catch (Exception ex) {
                ex.printStackTrace();
                return null;
            }
        }
        catch(Exception e)
        {
            return null;    
        }
    }

    /*decodes image and scales it to reduce memory consumption
     * @param file path
     * @throws FileNotFoundException
     * @return bitmap
     * */
    private Bitmap decodeFile(File f){
        Bitmap b = null;
        try {

            useThisBitmap = null;
            //Decode image size
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inJustDecodeBounds = true;
            final int IMAGE_MAX_SIZE =50;
            BitmapFactory.decodeStream(new FileInputStream(f), null, o);
            int scale = 2;
            if (o.outHeight > IMAGE_MAX_SIZE || o.outWidth > IMAGE_MAX_SIZE) {
                scale = 2 ^ (int) Math.ceil(Math.log(IMAGE_MAX_SIZE / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5));
            }

            //Decode with inSampleSize
            BitmapFactory.Options o2 = new BitmapFactory.Options();

            o2.inSampleSize = scale;
            b = BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
            useThisBitmap = b;

        } catch (FileNotFoundException e) {

        }
        catch(Exception e)
        {

        }
        finally{
            System.gc();
        }
        return useThisBitmap;
    }


    // Task for the queue
    private class PhotoToLoad 
    {
        public String url;
        public ImageView imageView;

        public PhotoToLoad(String u, ImageView i) {
            url = u;
            imageView = i;
        }
    }

    PhotosQueue photosQueue = new PhotosQueue();

    public void stopThread() 
    {
        photoLoaderThread.interrupt();
    }

    // stores list of photos to download
    class PhotosQueue {
        private Stack<PhotoToLoad> photosToLoad = new Stack<PhotoToLoad>();

        // removes all instances of this ImageView
        public void Clean(ImageView image) {
            for (int j = 0; j < photosToLoad.size();) {
                if (photosToLoad.get(j).imageView == image)
                    photosToLoad.remove(j);
                else
                    ++j;
            }
        }
    }

    class PhotosLoader extends Thread {
        public void run() {
            try {
                while (true) {
                    // thread waits until there are any images to load in the
                    // queue
                    if (photosQueue.photosToLoad.size() == 0)
                        synchronized (photosQueue.photosToLoad) {
                            photosQueue.photosToLoad.wait();
                        }
                    if (photosQueue.photosToLoad.size() != 0) {
                        PhotoToLoad photoToLoad;
                        synchronized (photosQueue.photosToLoad) {
                            photoToLoad = photosQueue.photosToLoad.pop();
                        }
                        Bitmap bmp = getBitmap(photoToLoad.url);
                        cache.put(photoToLoad.url, bmp);
                        if (((String) photoToLoad.imageView.getTag())
                                .equals(photoToLoad.url)) {
                            BitmapDisplayer bd = new BitmapDisplayer(bmp,
                                    photoToLoad.imageView);
                            Activity a = (Activity) photoToLoad.imageView
                                    .getContext();
                            a.runOnUiThread(bd);
                        }
                    }
                    if (Thread.interrupted())
                        break;
                }
            } catch (InterruptedException e) {
                // allow thread to exit
            }
        }
    }

    PhotosLoader photoLoaderThread = new PhotosLoader();

    // Used to display bitmap in the UI thread
    class BitmapDisplayer implements Runnable {
        Bitmap bitmap;
        ImageView imageView;

        public BitmapDisplayer(Bitmap b, ImageView i) {
            bitmap = b;
            imageView = i;
        }

        public void run() 
        {
            if (bitmap != null)
                imageView.setImageBitmap(bitmap);
        }
    }

    public void clearCache() 
    {
        // clear memory cache
        cache.clear();
        // clear SD cache
        File[] files = cacheDir.listFiles();
        for (File f : files)
            f.delete();
    }
}

以下是用法:

Albumartloader  albumartloader=new Albumartloader(this);
imageview.settag(urlofimage);
albumartloader.DisplayImage(url of image,activity context,imageview);

最佳用法: - 当您需要显示来自服务器的图像数量并且不想等待所有图像下载时,您可以将其用于列表视图。