安卓網路請求圖片到圖片的三級緩衝技術(記憶體緩衝,本機快取,網路緩衝)

來源:互聯網
上載者:User

標籤:

安卓網路請求圖片,對於我們來說並不陌生,因為每個應用都有可能會用到這一技術。通常情況下,我們第一次都是從網路上請求圖片資源,然後將

圖片資源儲存到記憶體和本地,下一次動態顯示圖片的時候就不需要再從網路上請求圖片資源了,直接從本地或者記憶體中擷取就可以了。這就涉及到圖片

的三級緩衝技術,分別是記憶體緩衝,本機快取,網路緩衝。

 

緩衝的流程圖:

首先我們定義一個類叫ClassLoader:

package com.jsako.showprodinfodemo;import java.io.FileOutputStream;import java.io.InputStream;import java.net.HttpURLConnection;import java.net.URL;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Bitmap.CompressFormat;import android.graphics.BitmapFactory;import android.os.AsyncTask;import android.support.v4.util.LruCache;import android.widget.ImageView;/** * 圖片載入類 *  * @author Administrator *  */public class ImageLoader {    private Context context;    private int loadingImage;    private int errorImage;    private LruCache<String, Bitmap> mapCache;    public ImageLoader(Context context, int loadingImage, int errorImage) {        this.context = context;        this.loadingImage = loadingImage;        this.errorImage = errorImage;        int maxMemory = (int) Runtime.getRuntime().maxMemory();        int mCacheSize = maxMemory / 8;        mapCache = new LruCache<String, Bitmap>(mCacheSize) {            @Override            protected int sizeOf(String key, Bitmap value) {                return value.getRowBytes() * value.getHeight();            }        };    }    public void getAndSetImage(String imagePath, ImageView iv_image) {        //儲存當前的ImageView對應的imagepath        iv_image.setTag(imagePath);        iv_image.setImageResource(loadingImage);        /*         * 從第一級緩衝中找對應imagePath的圖片 如果第一級緩衝有對應圖片,顯示! 如果第一級緩衝沒有圖片,從第二級緩衝中找         */        Bitmap bitmap = getImageByFirstCache(imagePath);        if (bitmap != null) {            iv_image.setImageBitmap(bitmap);            System.out.println("從一級緩衝中找到");            return;        }        /*         * 從第二級緩衝中找對應的圖片 如果有,則緩衝到第一緩衝中 如果沒有,則從第三集緩衝中找         */        bitmap = getImageBySecondCache(imagePath);        if (bitmap != null) {            iv_image.setImageBitmap(bitmap);            cacheInFirst(imagePath, bitmap);            System.out.println("從二級緩衝中找到");            return;        }        /*         * 從第三級緩衝中找對應的圖片 如果有,則緩衝到第一、二緩衝中 如果沒有,則顯示錯誤的圖片         */        loadImageByThridCache(imagePath, iv_image);    }    /**     * 將圖片緩衝到一級緩衝     *      * @param imagePath     *            圖片的url     * @param bitmap     */    private void cacheInFirst(String imagePath, Bitmap bitmap) {        mapCache.put(imagePath, bitmap);    }    /**     * 從三級緩衝中尋找圖片     *      * @param imagePath     *            圖片的url     * @param     * @return     */    private void loadImageByThridCache(final String imagePath,            final ImageView iv_image) {        new AsyncTask<String, Void, Bitmap>() {            /**             * 開啟非同步任務前調用             */            @Override            protected void onPreExecute() {            }            /**             * 非同步任務完成後調用             */            @Override            protected void onPostExecute(Bitmap result) {                String nowImagePath=(String) iv_image.getTag();                if(!nowImagePath.equals(imagePath)){                    //如果當前請求的圖片路徑和需要顯示的圖片路徑不一致的話,就不顯示圖片                    System.out.println("不顯示圖片了");                    return;                }                                if (result != null) {                    iv_image.setImageBitmap(result);                } else {                    iv_image.setImageResource(errorImage);                }            }            /**             * 後台進行非同步任務             */            @Override            protected Bitmap doInBackground(String... params) {                String nowImagePath=(String) iv_image.getTag();                if(!nowImagePath.equals(params[0])){                    //如果當前請求的圖片路徑和需要顯示的圖片路徑不一致的話,就不進行網路請求了                    System.out.println("不進行網路請求了");                    return null;                }                String url = params[0];                HttpURLConnection conn = null;                try {                    URL mUrl = new URL(url);                    conn = (HttpURLConnection) mUrl.openConnection();                    conn.setRequestMethod("GET");                    conn.setReadTimeout(6000);                    conn.setConnectTimeout(6000);                    conn.setDoInput(true);                    conn.connect();                    int code = conn.getResponseCode();                    if (code == 200) {                        InputStream in = conn.getInputStream();                        Bitmap bitmap = BitmapFactory.decodeStream(in);                        // 在分線程中緩衝圖片到一級和二級緩衝                        cacheInFirst(url, bitmap);                        String imageName = url                                .substring(url.lastIndexOf("/") + 1);                        String fileName = context.getExternalFilesDir(null)                                .getAbsolutePath() + "/" + imageName;                        bitmap.compress(CompressFormat.JPEG, 50,                                new FileOutputStream(fileName));                        return bitmap;                    } else {                        return null;                    }                } catch (Exception e) {                    e.printStackTrace();                    return null;                } finally {                    if (conn != null) {                        conn.disconnect();                    }                }            }        }.execute(imagePath);    }    /**     * 從二級緩衝中尋找圖片     *      * @param imagePath     *            圖片的url     * @return     */    private Bitmap getImageBySecondCache(String imagePath) {        String imageName = imagePath.substring(imagePath.lastIndexOf("/") + 1);        String fileName = context.getExternalFilesDir(null).getAbsolutePath()                + "/" + imageName;        return BitmapFactory.decodeFile(fileName);    }    /**     * 從一級緩衝中尋找圖片     *      * @param imagePath     *            圖片的url     * @return     */    private Bitmap getImageByFirstCache(String imagePath) {        return mapCache.get(imagePath);    }}

可以看到這個類的構造方法有三個,第一個是上下文,第二個是載入的圖片的時候所顯示的圖片對應的資源id,第三個是圖片載入失敗後所顯示的圖片對應的資源id。

這裡有幾個關鍵點:

第一個是在記憶體緩衝中,我們應該使用LruCache來緩衝圖片,這個類會根據當前所儲存的圖片空間是否大過設定值,如果比設定值大就會自動釋放記憶體,

這樣就能防止記憶體溢出的問題。

 

第二個是在使用ListView非同步載入圖片的時候,並且重用了convertView的時候會導致圖片錯位的現象。

導致圖片錯位的根本原因就是重用了convertView。

解決方案如下:

a. 每次getView()都將圖片的url儲存到ImageView上: imageView.setTag(imagePath)
b. 在分線程準備請求伺服器載入圖片之前, 比較準備載入圖片的url與ImageView中儲存的最新圖片的url是同一個,
如果不是同一個, 當前載入圖片的任務不應該再執行
如果相同, 繼續執行載入遠程圖片
c. 在主線程準備顯示圖片之前, 比較載入到圖片的url與ImageView中儲存的最新圖片的url是同一個
如果不是同一個, 不需要顯示此圖片
如果相同, 顯示圖片

安卓網路請求圖片到圖片的三級緩衝技術(記憶體緩衝,本機快取,網路緩衝)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.