2013-01-12 46 views
0

我想要創建一個Frame by Frame動畫並從URL下載Drawable。使用URL的逐幀動畫返回null可繪製

問題: 是否有可能從onPostExecute或從imageButton檢索bitmapDrawable? 我想不出任何更簡單的方式

下面的代碼是不完整的,我不知道如何從onPostExecute檢索bitmapDrawable,所以我得到什麼,我現在有一個空可繪製。

PrincipalFragment

public class PrincipalFragment extends Fragment { 



    private int mNum; 
    private AnimationDrawable mframeAnimation = null; 
    private static final int DELAY = 500; 




    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     mNum = getArguments() != null ? getArguments().getInt("num") : 1; 
    } 

    /** 
    * The Fragment's UI is just a simple text view showing its 
    * instance number. 
    */ 
    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
      Bundle savedInstanceState) { 
     View v = inflater.inflate(R.layout.scrollview, container, false); 




      ImageButton i = (ImageButton)v.findViewById(R.id.imageButton1); 
      i.setOnTouchListener(new OnTouchListener() { 

      @Override 
      public boolean onTouch(View v, MotionEvent event) { 
       // TODO Auto-generated method stub 
       ImageButton button = (ImageButton)v; 
       String principal = "principal"; 
       if (event.getAction() == MotionEvent.ACTION_DOWN) { 
        button.setColorFilter(0x8066bbdd); 
        return true; 
       } else if (event.getAction() == MotionEvent.ACTION_UP) { 
        button.setColorFilter(null); 
        Intent i = new Intent(getActivity(), SubView.class); 
        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
        i.putExtra("query", principal); 
        startActivity(i); 
        return true; 
       } 
       return false; 
      } 
     }); 
      ImageButton i2 = (ImageButton)v.findViewById(R.id.imageButton2); 
      i2.setOnTouchListener(new OnTouchListener() { 

      @Override 
      public boolean onTouch(View v, MotionEvent event) { 
       // TODO Auto-generated method stub 
       ImageButton button = (ImageButton)v; 
       String principal2 = "principal2"; 
       if (event.getAction() == MotionEvent.ACTION_DOWN) { 
        button.setColorFilter(0x8066bbdd); 
        return true; 
       } else if (event.getAction() == MotionEvent.ACTION_UP) { 
        button.setColorFilter(null); 
        Intent i = new Intent(getActivity(), SubView.class); 
        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
        i.putExtra("query", principal2); 
        startActivity(i); 

        return true; 
       } 
       return false; 
      } 
     }); 



      ImageDownloader.Mode mode = ImageDownloader.Mode.CORRECT; 

      ImageDownloader imageDownloader = new ImageDownloader(); 
      imageDownloader.setMode(mode);   
      BitmapDrawable frame1 = imageDownloader.download(URLnames.URLS[0], i, getResources()); 
      BitmapDrawable frame2 = imageDownloader.download(URLnames.URLS[1], i2, getResources()); 




      int reasonableDuration = 2500; 
      mframeAnimation = new AnimationDrawable(); 
      mframeAnimation.setOneShot(false); 
      mframeAnimation.addFrame(frame1, reasonableDuration); 
      mframeAnimation.addFrame(frame2, reasonableDuration); 

      ImageView img = (ImageView) v.findViewById(R.id.img_animated); 
      img.setImageDrawable(mframeAnimation); 
      mframeAnimation.setVisible(true, true); 

      img.post(new Starter()); 



     return v; 
    } 

    class Starter implements Runnable { 
     public void run() { 
      mframeAnimation.start(); 
     } 
} 

} 

ImageDownloader.class

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; 
    private Resources r = null; 

    /** 
    * 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. 
    * @param resources 
    */ 
    public BitmapDrawable download(String url, ImageView imageView, Resources resources) { 
     resetPurgeTimer(); 
     Bitmap bitmap = getBitmapFromCache(url); 
     BitmapDrawable bitmapDrawable = new BitmapDrawable(r, bitmap); 
     this.r = resources; 

     if (bitmap == null) { 
      bitmapDrawable = forceDownload(url, imageView); 

     } else { 
      cancelPotentialDownload(url, imageView); 
      imageView.setImageBitmap(bitmap); 

     } 
     return bitmapDrawable; 



    } 

    /* 
    * 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. 
    * @param resources 
    * @return 
    */ 
    private BitmapDrawable forceDownload(String url, ImageView imageView) { 
     // State sanity: url is guaranteed to never be null in DownloadedDrawable and cache keys. 
     BitmapDrawable bitmapDrawable; 
     if (url == null) { 
      imageView.setImageDrawable(null); 
      return null; 
     } 

     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; 
      } 
     } 
     return null; 

    } 

    /** 
    * 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 
     */ 
     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); 
        BitmapDrawable bitmapDrawable = new BitmapDrawable(r, bitmap); 
        imageView.setImageDrawable(bitmapDrawable); 
       } 
      } 

     } 
    } 





    /** 
    * 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

我可以把它的唯一途徑是與Asynctask.get();,有人說,這是不是正確的方法是因爲可能會凍結UI,並且應該使用回調接口,很長時間後我無法回撥到工作,Asynctask.get();現在正在工作,代碼是:

public Bitmap download(String url, ImageView imageView, Resources resources) throws InterruptedException, ExecutionException { 
     resetPurgeTimer(); 
     Bitmap bitmap = getBitmapFromCache(url); 

     this.r = resources; 

     if (bitmap == null) { 
      bitmapDrawable = forceDownload(url, imageView); 

     } else { 
      cancelPotentialDownload(url, imageView); 
      imageView.setImageBitmap(bitmap); 

     } 
     return bitmapDrawable; 



    } 

    /* 
    * 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. 
    * @param resources 
    * @return 
    * @throws ExecutionException 
    * @throws InterruptedException 
    */ 
    private Bitmap forceDownload(String url, ImageView imageView) throws InterruptedException, ExecutionException { 
     // State sanity: url is guaranteed to never be null in DownloadedDrawable and cache keys. 
     Bitmap bitmap = null; 
     if (url == null) { 
      imageView.setImageDrawable(null); 
      return null; 
     } 

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

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

       case CORRECT: 

        task = new BitmapDownloaderTask(imageView, this); 
        DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task); 
        imageView.setImageDrawable(downloadedDrawable); 
        imageView.setMinimumHeight(156); 
        task.execute(url); 
        bitmap = task.get(); 
        break; 
      } 
     } 
     return bitmap;