Android 實現非同步載入圖片

來源:互聯網
上載者:User

標籤:獨立   out   print   trace   imageview   cancel   can   ash   sof   

麥洛開通部落格以來,有一段時間沒有更新博文了.主要是麥洛這段時間因項目開發實在太忙了.今天周六還在公司加班,苦逼程式猿都是這樣生活的.

今天在做項目的時候,有一個實現非同步載入圖片的功能,雖然比較簡單但還是記錄一下吧.因為麥洛之前實現非同步載入圖片都是使用了AsynTask這個API,繼續這個類,實現起來非常簡單也很方便.在doInBackground()方法裡實現下載邏輯.具體實現如下

實現邏輯是:先從記憶體中讀取,如果記憶體中有這張圖片,則直接使用;如果記憶體沒有再到sdcard上讀取,如果有則顯示;如果sdcard上還沒有則到網路上讀取.記憶體中開啟緩衝是參考了網上的實現.麥洛在這裡非常感謝喜歡分享的程式猿們.

public class ImageDownloader extends AsyncTask<String, Integer, Object> {    private static final String TAG = "ImageDownloader";    // 為了加快速度,在記憶體中開啟緩衝(主要應用於重複圖片較多時,或者同一個圖片要多次被訪問,比如在ListView時來復原動)    private Map<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>();    /**     * 顯示圖片的控制項     */    private ImageView mImageView;    public ImageDownloader(ImageView image) {        mImageView = image;    }    @Override    protected void onPreExecute() {        super.onPreExecute();    }    @Override    protected Object doInBackground(String... params) {        // Log.i("ImageDownloader", "loading image...");        String url = params[0];        Drawable drawable = null;        try {            if (!"".equals(url) && url != null) {                String fileName = url.hashCode()+".jpg";                // 如果緩衝過就從緩衝中取出資料                if (imageCache.containsKey(fileName)) {                    SoftReference<Drawable> softReference = imageCache.get(fileName);                    drawable = softReference.get();                    if (drawable != null) {                        return drawable;                    }                }                File dir = new File(FileConstant.IMAGE_FILE_PATH);                if (!dir.exists()) {                    boolean m = dir.mkdirs();                }                File file = new File(dir, fileName);                if (file.exists() && file.length() > 0) {                    Log.i(TAG, "load image from sd card");                    // 如果檔案存在則直接讀取sdcard                    drawable = readFromSdcard(file);                } else {                    //file.createNewFile();                    Log.i(TAG, "load image from network");                    URL imageUrl = new URL(url);                    // 寫入sdcard                    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {                        saveImageFile(imageUrl, file);                        drawable = Drawable.createFromStream(new FileInputStream(file), fileName);                    }else{                        //直接從流讀取                        drawable = Drawable.createFromStream(imageUrl.openStream(), fileName);                    }                }                if(drawable!=null){                    //儲存在緩衝中                    imageCache.put(fileName, new SoftReference<Drawable>(drawable));                }            }        } catch (Exception e) {            e.printStackTrace();        }         return drawable;    }    /**     * save image*/    private void saveImageFile(URL url, File file) {        FileOutputStream out = null;        InputStream in = null;        try {            file.deleteOnExit();            out = new FileOutputStream(file);            in = url.openStream();            byte[] buf = new byte[1024];            int len = -1;            while((len = in.read(buf))!=-1){                out.write(buf, 0, len);                out.flush();            }        } catch (Exception e) {            e.printStackTrace();        } finally {            if(out!=null){                try {                    out.close();                } catch (IOException e) {                    e.printStackTrace();                }            }            if(in!=null){                try {                    in.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }    }    /**     * 從sdcard中擷取圖片*/    private Drawable readFromSdcard(File file) throws Exception {        FileInputStream in = new FileInputStream(file);        return Drawable.createFromStream(in, file.getName());    }    @Override    protected void onPostExecute(Object result) {        super.onPostExecute(result);        Drawable drawable = (Drawable) result;        if (mImageView != null && drawable != null) {            mImageView.setBackgroundDrawable(drawable);        }    }    @Override    protected void onProgressUpdate(Integer... values) {        super.onProgressUpdate(values);    }    @Override    protected void onCancelled() {        super.onCancelled();    }}

使用時:

ImageDownloader loader = new ImageDownloader(imageView);loader.execute(url);

其實這樣的話,還有一些隱患的,就是說這個類實現還是有些問題的.比如每次都在imageView中設定網路上的圖片時,其實是沒有使用到這個類裡面的記憶體緩衝的,就是imageCache

Map<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>();
因為每次設定imageView的時候,都是new了一個ImageDownloader的對象.所以每個ImageDownloader對象裡面都是獨立的一個imageCache.      另外,AsynTask也是一個線程.而每次使用都開一個線程來load 圖片,對線程個數沒有進行顯示,畢竟線程數目還是有限制的.所以麥洛今天發現了這個問題,於是參考了別人的實現,使用了線程池,實現邏輯也上面的代碼一樣,先從記憶體讀取,如果沒有到sdcard讀取,如果還是沒有,則是網路讀取;實現沒有使用AsynTask,具體代碼如下:
/** * 非同步載入圖片,並將圖片設定到ImageView控制項中*/public class ImageDownloader extends AsyncTask<String, Integer, Object> {    private static final String TAG = "ImageDownloader";    // 為了加快速度,在記憶體中開啟緩衝(主要應用於重複圖片較多時,或者同一個圖片要多次被訪問,比如在ListView時來復原動)    private Map<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>();    /**     * 顯示圖片的控制項     */    private ImageView mImageView;    public ImageDownloader(ImageView image) {        mImageView = image;    }    @Override    protected void onPreExecute() {        super.onPreExecute();    }    @Override    protected Object doInBackground(String... params) {        // Log.i("ImageDownloader", "loading image...");        String url = params[0];        Drawable drawable = null;        try {            if (!"".equals(url) && url != null) {                String fileName = url.hashCode()+".jpg";                // 如果緩衝過就從緩衝中取出資料                if (imageCache.containsKey(fileName)) {                    SoftReference<Drawable> softReference = imageCache.get(fileName);                    drawable = softReference.get();                    if (drawable != null) {                        return drawable;                    }                }                File dir = new File(FileConstant.IMAGE_FILE_PATH);                if (!dir.exists()) {                    boolean m = dir.mkdirs();                }                File file = new File(dir, fileName);                if (file.exists() && file.length() > 0) {                    Log.i(TAG, "load image from sd card");                    // 如果檔案存在則直接讀取sdcard                    drawable = readFromSdcard(file);                } else {                    //file.createNewFile();                    Log.i(TAG, "load image from network");                    URL imageUrl = new URL(url);                    // 寫入sdcard                    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {                        saveImageFile(imageUrl, file);                        drawable = Drawable.createFromStream(new FileInputStream(file), fileName);                    }else{                        //直接從流讀取                        drawable = Drawable.createFromStream(imageUrl.openStream(), fileName);                    }                }                if(drawable!=null){                    //儲存在緩衝中                    imageCache.put(fileName, new SoftReference<Drawable>(drawable));                }            }        } catch (Exception e) {            e.printStackTrace();        }         return drawable;    }    /**     * save image*/    private void saveImageFile(URL url, File file) {        FileOutputStream out = null;        InputStream in = null;        try {            file.deleteOnExit();            out = new FileOutputStream(file);            in = url.openStream();            byte[] buf = new byte[1024];            int len = -1;            while((len = in.read(buf))!=-1){                out.write(buf, 0, len);                out.flush();            }        } catch (Exception e) {            e.printStackTrace();        } finally {            if(out!=null){                try {                    out.close();                } catch (IOException e) {                    e.printStackTrace();                }            }            if(in!=null){                try {                    in.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }    }    /**     * 從sdcard中擷取圖片  */    private Drawable readFromSdcard(File file) throws Exception {        FileInputStream in = new FileInputStream(file);        return Drawable.createFromStream(in, file.getName());    }    @Override    protected void onPostExecute(Object result) {        super.onPostExecute(result);        Drawable drawable = (Drawable) result;        if (mImageView != null && drawable != null) {            mImageView.setBackgroundDrawable(drawable);        }    }    @Override    protected void onProgressUpdate(Integer... values) {        super.onProgressUpdate(values);    }    @Override    protected void onCancelled() {        super.onCancelled();    }}

這個ImageDownloader2的使用也很簡單

public class ImageUtil {    /**     * image loader     */    static ImageDownloader2 loader = null;        /**     * load image*/    public static void loadImage(String url,final ImageView imageView){        if(loader == null){            loader = new ImageDownloader2();        }        loader.loadDrawable(url, new ImageCallback() {                        @Override            public void imageLoaded(Drawable imageDrawable) {                if(imageDrawable!=null){                    imageView.setBackgroundDrawable(imageDrawable);                }            }        });    }    }

每次在使用是需要調用ImageUtil.loadImage(url,imageView)將圖片url已經需要顯示圖片的控制項ImageView的引用傳入就可以了.

 

Android 實現非同步載入圖片

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.