轉自:http://blog.csdn.net/toyuexinshangwan/article/details/8194816
其他相關的文章:開源框架ImageLoader:
http://blog.csdn.net/wwj_748/article/details/10079311
http://blog.csdn.net/yueqinglkong/article/details/27660107
好多應用都需要加載網絡圖片,那ToYueXinShangWan,這是比須熟練掌握的一個點,下面開始學習:
一、最簡單加載網絡圖片
從網絡上取圖片數據,顯示在應用中,簡單不贅述:
- try {
- URL url = new URL(path); //path圖片的網絡地址
- HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
- if(httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK){
- Bitmap bitmap = BitmapFactory.decodeStream(httpURLConnection.getInputStream());
- imageview.setImageBitmap(bitmap);//加載到ImageView上
- System.out.println("加載網絡圖片完成");
- }else{
- System.out.println("加載網絡圖片失敗");
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
二、輕量級異步加載圖片
不會有人用第一種方法加載,連接網絡和從網絡取數據,花費部分時間,阻礙主線程,影響UI效果!
解決方案是:異步加載。先給ImageView設置一張圖片,在異步任務中取數據,當從網絡中取數據中和取數據失敗時,就一直顯示原來圖片,當完成取數據時則再把新圖片加載到ImageView上。
根據上面思路,就可以直接動手寫了,爲了便於代碼複用,將加載圖片寫在一個工具類Utils中:
- package com.lizhen.loadimage;
- import java.io.IOException;
- import java.io.InputStream;
- import java.net.HttpURLConnection;
- import java.net.URL;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.os.Handler;
- import android.os.Message;
- public class Utils {
- public static void onLoadImage(final URL bitmapUrl,final OnLoadImageListener onLoadImageListener){
- final Handler handler = new Handler(){
- public void handleMessage(Message msg){
- onLoadImageListener.OnLoadImage((Bitmap) msg.obj, null);
- }
- };
- new Thread(new Runnable(){
- @Override
- public void run() {
- // TODO Auto-generated method stub
- URL imageUrl = bitmapUrl;
- try {
- HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
- InputStream inputStream = conn.getInputStream();
- Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
- Message msg = new Message();
- msg.obj = bitmap;
- handler.sendMessage(msg);
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }).start();
- }
- public interface OnLoadImageListener{
- public void OnLoadImage(Bitmap bitmap,String bitmapPath);
- }
- }
- Utils.onLoadImage(url, new OnLoadImageListener() {
- @Override
- public void OnLoadImage(Bitmap bitmap, String bitmapPath) {
- // TODO Auto-generated method stub
- if(bitmap!=null){
- imageview.setImageBitmap(bitmap);
- }
- }
- });
三、第二種方法的弊端是,當有大量圖片需要加載時,會啓動很多線程,避免出現這種情況的方法是,定義線程個數,當線程數達到最多時,不再開啓,直到有一個線程結束,再開啓一個線程;這種做法相當於
引入ExecutorService接口,於是代碼可以優化如下:
在主線程中加入:private ExecutorService executorService = Executors.newFixedThreadPool(5);
在相應位置修改代碼如下:
- executorService.submit(new Runnable(){
- @Override
- public void run() {
- // TODO Auto-generated method stub
- URL imageUrl = bitmapUrl;
- try {
- System.out.println(Thread.currentThread().getName() + "線程被調用了。");
- HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
- InputStream inputStream = conn.getInputStream();
- Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
- Message msg = new Message();
- msg.obj = bitmap;
- handler.sendMessage(msg);
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- System.out.println(Thread.currentThread().getName() + "線程結束。");
- }
- });
線程池大小爲3,運行5個線程,我的輸出結果爲:
這裏有關線程池的概念用法寫在另一篇文章裏!
四、關於方法二的改進,考慮到效率問題,可以引入緩存機制,把圖片保留在本地,只需在線程run方法最後加上如下代碼:
- //緩存
- if(Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)){
- System.out.println("存在sd卡");
- File cacheFile = new File(Environment.getExternalStorageDirectory()+"/cacheFile");
- System.out.println(cacheFile.getPath());
- if(!cacheFile.exists())
- cacheFile.mkdir();
- System.out.println(cacheFile.exists());
- File imageCache = new File(cacheFile.getPath()+"/netwrok.png");
- FileOutputStream fos = new FileOutputStream(imageCache);
- BufferedOutputStream bos = new BufferedOutputStream(fos);
- bitmap.compress(Bitmap.CompressFormat.PNG, 80, bos);
- bos.flush();
- bos.close();
- }
另一種把圖片緩存在內存中使用如下步驟:
1、主線程 public Map<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>();
2、如果有緩存則讀取緩存中數據,如果沒有,則從網絡獲取數據;
//如果緩存過就從緩存中取出數據
if (imageCache.containsKey(imageUrl)) {
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
if (softReference.get() != null) {
return softReference.get();//得到緩存中的Drawable
}
}
3、在網絡獲取數據時,不要忘記添加imageCache信息
imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));
注意:SoftReference<Drawable>就是用來處理解決大量圖片下載內存溢出的問題的,還有Bitmap與Drawable之間的轉換,在其他文章中將做總結!
2012 /11/18 1:26 太晚了,沒想這問題會花費這麼長時間;