Android之圖片異步加載并緩存到本地

openkk 12年前發布 | 46K 次閱讀 Android Android開發 移動開發

           在android項目中訪問網絡圖片是非常普遍性的事情,如果我們每次請求都要訪問網絡來獲取圖片,會非常耗費流量,而且圖片占用內存空間也比較大,圖片過多且不釋放的話很容易造成內存溢出。針對上面遇到的兩個問題,首先耗費流量我們可以將圖片第一次加載上面緩存到本地,以后如果本地有就直接從本地加載。圖片過多造成內存溢出,這個是最不容易解決的,要想一些好的緩存策略,比如大圖片使用LRU緩存策略或懶加載緩存策略。今天首先介紹一下本地緩存圖片。

           首先看一下異步加載緩存本地代碼:

public class AsyncBitmapLoader
{
/**

 * 內存圖片軟引用緩沖 
 */  
private HashMap<String, SoftReference<Bitmap>> imageCache = null;  

public AsyncBitmapLoader()  
{  
    imageCache = new HashMap<String, SoftReference<Bitmap>>();  
}  

public Bitmap loadBitmap(final ImageView imageView, final String imageURL, final ImageCallBack imageCallBack)  
{  
    //在內存緩存中,則返回Bitmap對象  
    if(imageCache.containsKey(imageURL))  
    {  
        SoftReference<Bitmap> reference = imageCache.get(imageURL);  
        Bitmap bitmap = reference.get();  
        if(bitmap != null)  
        {  
            return bitmap;  
        }  
    }  
    else  
    {  
        /** 
         * 加上一個對本地緩存的查找 
         */  
        String bitmapName = imageURL.substring(imageURL.lastIndexOf("/") + 1);  
        File cacheDir = new File("/mnt/sdcard/test/");  
        File[] cacheFiles = cacheDir.listFiles();  
        int i = 0;  
        if(null!=cacheFiles){
        for(; i<cacheFiles.length; i++)  
        {  
            if(bitmapName.equals(cacheFiles[i].getName()))  
            {  
                break;  
            }  
        }  

        if(i < cacheFiles.length)  
        {  
            return BitmapFactory.decodeFile("/mnt/sdcard/test/" + bitmapName);  
        }
        }
    }  

    final Handler handler = new Handler()  
    {  
        /* (non-Javadoc) 
         * @see android.os.Handler#handleMessage(android.os.Message) 
         */  
        @Override  
        public void handleMessage(Message msg)  
        {  
            // TODO Auto-generated method stub  
            imageCallBack.imageLoad(imageView, (Bitmap)msg.obj);  
        }  
    };  

    //如果不在內存緩存中,也不在本地(被jvm回收掉),則開啟線程下載圖片  
    new Thread()  
    {  
        /* (non-Javadoc) 
         * @see java.lang.Thread#run() 
         */  
        @Override  
        public void run()  
        {  
            // TODO Auto-generated method stub  
            InputStream bitmapIs = HttpUtils.getStreamFromURL(imageURL);  

            Bitmap bitmap = BitmapFactory.decodeStream(bitmapIs);  
            imageCache.put(imageURL, new SoftReference<Bitmap>(bitmap));  
            Message msg = handler.obtainMessage(0, bitmap);  
            handler.sendMessage(msg);  

            File dir = new File("/mnt/sdcard/test/");  
            if(!dir.exists())  
            {  
                dir.mkdirs();  
            }  

            File bitmapFile = new File("/mnt/sdcard/test/" +   
                    imageURL.substring(imageURL.lastIndexOf("/") + 1));  
            if(!bitmapFile.exists())  
            {  
                try  
                {  
                    bitmapFile.createNewFile();  
                }  
                catch (IOException e)  
                {  
                    // TODO Auto-generated catch block  
                    e.printStackTrace();  
                }  
            }  
            FileOutputStream fos;  
            try  
            {  
                fos = new FileOutputStream(bitmapFile);  
                bitmap.compress(Bitmap.CompressFormat.PNG,   
                        100, fos);  
                fos.close();  
            }  
            catch (FileNotFoundException e)  
            {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
            catch (IOException e)  
            {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
        }  
    }.start();  

    return null;  
}  

public interface ImageCallBack  
{  
    public void imageLoad(ImageView imageView, Bitmap bitmap);  
}  

}</pre>
     這是一個封裝好的異步加載圖片類,緩存了兩份,一份是使用軟引用緩存到內存中,一份是緩存到本地sd卡,如果內存中沒有,則從本地查找,如果本地沒有則從網絡獲取圖片。

public class HttpUtils {

public static InputStream getStreamFromURL(String imageURL) {
    InputStream in=null;
    try {
        URL url=new URL(imageURL);
        HttpURLConnection connection=(HttpURLConnection) url.openConnection();
        in=connection.getInputStream();

    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return in;

}

}</pre>
    這是一個訪問網絡獲取類。不細說了。

   下面看一下如何使用封裝好的異步加載圖片的類:

public class ImageCacheActivity extends Activity {
    /* Called when the activity is first created. /
    private ListView listview;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

    listview=(ListView) findViewById(R.id.listView_list);
    MyAdapter adapter=new MyAdapter();
    listview.setAdapter(adapter);
}

private class MyAdapter extends BaseAdapter{

    private AsyncBitmapLoader asyncBitmapLoader;
    public MyAdapter(){
        asyncBitmapLoader=new AsyncBitmapLoader();
    }
    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return 10;
    }

    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
        if(convertView==null){
            convertView=LayoutInflater.from(getApplicationContext()).inflate(R.layout.list_item, null);
        }
        ImageView image=(ImageView) convertView.findViewById(R.id.addexam_list_icon);
        String imageURL="http://s.ata.net.cn/4f98db46908987a21a000003/logo/2012/04/114_80aaf295c083d07a496743699aac3193.png";
        Bitmap bitmap=asyncBitmapLoader.loadBitmap(image, imageURL, new ImageCallBack() {

            @Override
            public void imageLoad(ImageView imageView, Bitmap bitmap) {
                // TODO Auto-generated method stub
                imageView.setImageBitmap(bitmap);
            }
        });
         if(bitmap == null)  
            {  
               image.setImageResource(R.drawable.ic_launcher);  
            }  
            else  
            {  
                image.setImageBitmap(bitmap);  
            }  

        return convertView;
    }

}

}</pre>
這樣就完成了,網絡獲取不到bitmap則顯示默認圖片。

 

這是一種很實用的方法,大家自己試試吧!

轉自:http://blog.csdn.net/wangkuifeng0118/article/details/7648618

 本文由用戶 openkk 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!