2011-10-25 22 views
0

Android開發中的常見任務是從Web加載圖像,並使用Activity中的ImageView進行綁定。在我看到的代碼中,程序員經常使用AsyncTask在後臺運行加載,並在上下文中發佈結果。 這種方法導致我們在某些情況下引發了應用方面的變化。原因是背景。因爲活動可能會被破壞並重新創建,我們的上下文也會是丟失,但在運行AsyncTask上下文時不會更新。因此,當postExectute將被調用AsyncTask嘗試將結果發佈到不再存在的活動Android:在不使用AsyncTask的情況下從web上載圖片的最佳方式是什麼?

我想知道您使用什麼方法將數據加載爲圖像,然後發佈到活動中?

回答

4

你應該嘗試使用所謂的和AsyncTaskLoader。它就像一個AsycnTask,除了整個「需要在活動消失時刪除AsyncTask」位爲您打理。一般而言,裝載機幾乎專門設計用於改進列表視圖異步加載數據的任務。事實上,它們很快就成爲我最喜歡使用的新的android類之一。有關裝載機的更多信息,請查看documentation

作爲最後一點,在API級別10之前不會引入裝載程序。即使如此,仍然可以使用android Support Package從較小的api級別訪問它們。

0

這是完整的代碼,加載在後臺的圖像,並將其存儲到SD卡。如果圖像已經存在,那麼它不會向服務器發出請求。 package 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); 

最佳用法:當你需要顯示來自服務器的圖像數量,不希望等待所有圖像下載 - 你可以使用它的列表視圖。

+0

這並沒有解決手頭的問題。提問者想知道如何在方向改變時處理AsyncTasks。這只是顯示如何下載圖像。 –

+0

謝謝你的回答Hitendra和你的評論寇蒂斯。我的目標是在上述情況下找到好的方法。當上下文丟失時我們可以處理acynTask,但是我們應該如何處理?我的意思是,這真的是最好的方法?可能是可能不是。所以可能是android開發人員將無法分享他們自己的經驗。我的問題就是這樣。 – user1012050

+0

kurtis,這裏是user1012050的問題。我想知道你使用什麼方法來加載數據作爲inages和在Activity中發佈?它沒有顯示特定的方法(即asynctask)。 – Hitendra

相關問題