Android如何優雅的緩存網絡圖片
在Android開發中,基本上都會有與網絡握手,如果沒實現這個功能,那也就只能是在開發一個“單機遊戲”咯。既然從網絡獲取數據,那就避免不了加載網絡數據,那麼問題來了,流量怎麼辦?大家都知道,加載網絡圖片比加載網絡文本耗費的流量多得多。不用擔心,今天來分享以下如何緩存網絡圖片到本地來:
- 根據圖片的url去加載,本地有就加載本地,沒有則請求網絡
- 圖片壓縮,降低內存使用
- 圖片鏈接和圖片上傳
主要思路
在我們我實現圖片顯示的時候,一般都是在Adapter裏面,或者其他地方,先調用我們工具類的主方法,主方法重載了兩個,傳入的參數不一樣,一個是傳ImageView加圖片的url,一個是隻傳url,這個根據你的需求來。調用主方法後,工具類先會從內存中去加載,如果沒有就去本地加載,本地也沒有,就就只能去網絡請求了,所以會有三個類是去做對應地方的操作。
不羅嗦,上代碼
這是主方法,都有註釋的,扯那麼多理論也還是抵不過一行代碼
``` java
import android.graphics.Bitmap;
import android.widget.ImageView;
import com.example.smilefood.R;
/**
* 自定義圖片加載工具類
*
* @author Kevin
*
*/
public class MyBitmapUtils {
private NetCacheUtils mNetCacheUtils;
private LocalCacheUtils mLocalCacheUtils;
private MemoryCacheUtils mMemoryCacheUtils;
public MyBitmapUtils() {
mMemoryCacheUtils = new MemoryCacheUtils();
mLocalCacheUtils = new LocalCacheUtils();
mNetCacheUtils = new NetCacheUtils(mLocalCacheUtils, mMemoryCacheUtils);
}
/**
* 加載圖片的核心api
*
* @param ivPic
* ImageView對象
* @param url
* 圖片鏈接
*/
public void display(ImageView ivPic, String url) {
// 從內存緩存讀
Bitmap bitmap = mMemoryCacheUtils.getBitmapFromMemory(url);
if(bitmap!=null) {//如果內存存在,就直接設置並返回
ivPic.setImageBitmap(bitmap);
System.out.println("從內存讀取圖片");
return;
}
// 從本地緩存讀
bitmap = mLocalCacheUtils.getBitmapFromLocal(url);
if (bitmap != null) {//如果本地文件存在,就直接設置並返回
ivPic.setImageBitmap(bitmap);
System.out.println("從本地讀取圖片");
mMemoryCacheUtils.putBitmapToMemory(url, bitmap);//設置內存圖片
return;
}
// 從網絡緩存下載
mNetCacheUtils.getBitmapFromNet(ivPic, url);
}
public Bitmap display( String url) {
// 從內存緩存讀
Bitmap bitmap = mMemoryCacheUtils.getBitmapFromMemory(url);
if(bitmap!=null) {//如果內存存在,就直接設置並返回
System.out.println("從內存讀取圖片");
return bitmap;
}
// 從本地緩存讀
bitmap = mLocalCacheUtils.getBitmapFromLocal(url);
if (bitmap != null) {//如果本地文件存在,就直接設置並返回
System.out.println("從本地讀取圖片");
mMemoryCacheUtils.putBitmapToMemory(url, bitmap);//設置內存圖片
return bitmap;
}
// 從網絡緩存下載
//mNetCacheUtils.getBitmapFromNet(ivPic, url);
return null;
}
}
本地緩存工具類
public class LocalCacheUtils {
private static final String LOCAL_PATH = Environment
.getExternalStorageDirectory().getAbsolutePath() + "/smile_cache";
/**
* 從本地讀取圖片
*
* @param url
* @return
*/
public Bitmap getBitmapFromLocal(String url) {
try {
String fileName = url;
File file = new File(LOCAL_PATH, fileName);
if (file.exists()) {
// 圖片壓縮
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;// 表示壓縮比例,2表示寬高都壓縮爲原來的二分之一, 面積爲四分之一
options.inPreferredConfig = Config.RGB_565;// 設置bitmap的格式,565可以降低內存佔用
Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(
file), null, options);
return bitmap;
} else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 向本地存圖片
*
* @param url
* @param bitmap
*/
public void putBitmapToLocal(String url, Bitmap bitmap) {
try {
String fileName =url;
File file = new File(LOCAL_PATH, fileName);
File parent = file.getParentFile();
// 創建父文件夾
if (!parent.exists()) {
parent.mkdirs();
}
bitmap.compress(CompressFormat.JPEG, 100,
new FileOutputStream(file));
} catch (Exception e) {
e.printStackTrace();
}
}
}
內存緩存工具類
public class MemoryCacheUtils {
// HashMap<String, SoftReference<Bitmap>> mMemoryCache = new HashMap<String,
// SoftReference<Bitmap>>();
LruCache<String, Bitmap> mMemoryCache;
public MemoryCacheUtils() {
int maxMemory = (int) Runtime.getRuntime().maxMemory();// 當前手機分配給app進程的最大內存,虛擬機默認16M
System.out.println("maxMemory:" + maxMemory);
mMemoryCache = new LruCache<String, Bitmap>(maxMemory / 8) {
@Override
protected int sizeOf(String key, Bitmap value) {
int size = value.getRowBytes() * value.getHeight();// 返回bitmap佔用的內存大小
System.out.println("sizeof:" + size);
return size;
}
};
}
/**
* 從內存讀取圖片
*
* @param url
* @return
*/
public Bitmap getBitmapFromMemory(String url) {
// SoftReference<Bitmap> softBitmap = mMemoryCache.get(url);
// System.out.println("讀取內存圖片。。。" + softBitmap);
// if (softBitmap != null) {
// Bitmap bitmap = softBitmap.get();
// System.out.println("讀取內存圖片成功。。。" + bitmap);
// return bitmap;
// }
Bitmap bitmap = mMemoryCache.get(url);
return bitmap;
}
/**
* 向內存存圖片
*
* @param url
* @param bitmap
*/
public void putBitmapToMemory(String url, Bitmap bitmap) {
// System.out.println("設置內存圖片。。。");
// SoftReference<Bitmap> softBitmap = new
// SoftReference<Bitmap>(bitmap);// 通過軟引用對對象包裝
// mMemoryCache.put(url, softBitmap);
mMemoryCache.put(url, bitmap);
}
}
網絡緩存工具類
public class NetCacheUtils {
LocalCacheUtils mLocalCacheUtils;
MemoryCacheUtils mMemoryCacheUtils;
public NetCacheUtils(LocalCacheUtils localCacheUtils,
MemoryCacheUtils memoryCacheUtils) {
mLocalCacheUtils = localCacheUtils;
mMemoryCacheUtils = memoryCacheUtils;
}
public void getBitmapFromNet(ImageView ivPic, String url) {
BitmapTask task = new BitmapTask();
task.execute(new Object[] { ivPic, url });
}
class BitmapTask extends AsyncTask<Object, Void, Bitmap> {
private ImageView imageView;
private String url;
/**
* 返回的對象會自動回傳到onPostExecute裏面
*/
@Override
protected Bitmap doInBackground(Object... params) {
imageView = (ImageView) params[0];
url = (String) params[1];
imageView.setTag(url);
Bitmap bitmap = downloadBitmap(url);
return bitmap;
}
@Override
protected void onPostExecute(Bitmap result) {
// 這裏的result就是doInBackground返回回來的對象
if (result != null) {
String ivUrl = (String) imageView.getTag();
if (url.equals(ivUrl)) {// 確保imageview設置的是正確的圖片(因爲有時候listview有重用機制,多個item會公用一個imageview對象,從而導致圖片錯亂)
imageView.setImageBitmap(result);
System.out.println("從網絡緩存讀取圖片");
// 向本地保存圖片文件
mLocalCacheUtils.putBitmapToLocal(url, result);
// 向內存保存圖片對象
mMemoryCacheUtils.putBitmapToMemory(url, result);
}
}
}
}
/**
* 下載圖片
*
* @param url
* @return
*/
private Bitmap downloadBitmap(String url) {
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) new URL(url).openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
conn.setRequestMethod("GET");
conn.connect();
int responseCode = conn.getResponseCode();
if (responseCode == 200) {
InputStream inputStream = conn.getInputStream();
//圖片壓縮
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;//表示壓縮比例,2表示寬高都壓縮爲原來的二分之一, 面積爲四分之一
options.inPreferredConfig = Config.RGB_565;//設置bitmap的格式,565可以降低內存佔用
Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options);
return bitmap;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
conn.disconnect();
}
return null;
}
}
最後說兩句,想要加載圖片的時候直接看下面
new MyBitmapUtils().display(holder.foodImg_img,mFoodList.get(position).getFoodUrl());
這裏我是在Adapter裏面要實現item裏面一個ImageView顯示圖片
瀏覽器兼容
- 目前,本編輯器對Chrome瀏覽器支持最爲完整。建議大家使用較新版本的Chrome。
- IE9以下不支持
- IE9,10,11存在以下問題
- 不支持離線功能
- IE9不支持文件導入導出
- IE10不支持拖拽文件導入