数据的缓存是android中常用的机制,虽然现在有很多框架已经实现了缓存+http请求等等一系列的操作,但是还是缕缕其中的代码过程吧,其实过程很简单,就是在加载数据时判断是否被缓存,没有就进行缓冲(也就是存在本地文件中),有了就直接拿存的数据来用就行了,而ImageView是常用控件,如果用了缓存思想应该会方便很多的,贴出之前做的demo的代码
基本思想
// 1. 尝试从内存缓存(当前控件中自定义的属性,表示图片数据)中加载图片
// 2. 尝试从本地文件中读取图片数据,无论是否读取到,最终,都将把图片数据写入到内存的缓存(为属性赋值)
// 3. 尝试从网络中下载图片,下载完成依然会执行之前的操作:把图片数据写入到内存的缓存(为属性赋值)
// Ps. 开启子线程完成加载,并在主线程中更新UI
这里定义一个WebImage类,用于网络请求+本地缓存操作
<span style="font-size:18px;">package cn.com.tarena.music_online.view;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.os.Environment;
public class WebImage {
private String url;
private Options opts;
private Map<String, Bitmap> cache = new HashMap<String, Bitmap>();
public void setUrl(String url) {
this.url = url;
}
public WebImage(String url) {
this.url = url;
}
public WebImage(String url, Options opts) {
this.url = url;
this.opts = opts;
}
private void setCacheBitmap(Bitmap bitmap) {
cache.put(getLocalFileName(), bitmap);
}
private Bitmap getCacheBitmap() {
return cache.get(getLocalFileName());
}
//创建一个缓存文件
private File dir = new File(
Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
"custom_image_cache");
//设置文件名字,将敏感字符全部替换掉
private String getLocalFileName() {
String fileName = url;
fileName = fileName.replace(":", "+");
fileName = fileName.replace("/", "+");
fileName = fileName.replace("\\", "+");
fileName = fileName.replace("?", "+");
fileName = fileName.replace("|", "+");
fileName = fileName.replace("*", "+");
fileName = fileName.replace("\"", "+");
fileName = fileName.replace("\'", "+");
fileName = fileName.replace("!", "+");
return fileName;
}
//获得bitmap
public Bitmap getBitmap() {
Bitmap bm = getCacheBitmap();
if (bm == null) {
bm = getBitmapFromLocalFile();
//如果本地文件为null,则调用downloadImageFromWeb()请求网络资源
if (bm == null) {
downloadImageFromWeb();
bm = getBitmapFromLocalFile();
}
}
return getCacheBitmap();
}
//获得本地bitmap资源
private Bitmap getBitmapFromLocalFile() {
if (!dir.exists()) {
return null;
}
Bitmap bm = null;
File localFile = new File(dir, getLocalFileName());
if (!localFile.exists()) {
return null;
}
bm = BitmapFactory.decodeFile(localFile.getAbsolutePath(), opts);
setCacheBitmap(bm);
return bm;
}
//网络请求数据并存储在本地
private void downloadImageFromWeb() {
HttpClient client = null;
HttpGet request = null;
HttpResponse response = null;
HttpEntity entity = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
File localFile = null;
try {
client = new DefaultHttpClient();
request = new HttpGet(url);
response = client.execute(request);
if (200 == response.getStatusLine().getStatusCode()) {
entity = response.getEntity();
localFile = new File(dir, getLocalFileName());
if (!dir.exists()) {
dir.mkdirs();
}
bis = new BufferedInputStream(entity.getContent());
bos = new BufferedOutputStream(new FileOutputStream(localFile));
byte[] buffer = new byte[1024];
int len;
while ((len = bis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
bos.flush();
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bos != null) {
bos.close();
bos = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}</span>
然后我们定义一个CustomImageView来继承ImageView
package cn.com.tarena.music_online.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory.Options;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.widget.ImageView;
import cn.com.tarena.music_online.R;
public class CustomImageView extends ImageView {
private WebImage webImage;
// 带1个参数的构造方法,适用于在JAVA程序中使用new ???()的语法,创建控件的对象
public CustomImageView(Context context) {
super(context);
}
// 带2~3个参数的构造方法,适用于在res\layout下设计布局,添加各项属性,最后,通过LayoutInflater加载到程序中
public CustomImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO 自定义需要在构造方法中完成的代码
}
/**
* 显示来自网络的图片
*
* <p>
* 本功能会自动缓存图片的数据分别到本地文件与内存,当显示图片时,将根据内存 -> 本地文件的顺序尝试加载已缓存的图片数据。
* </p>
*
* @param url
* 网络上的图片的完整路径,例如 http://www.baidu.com/logo.png
*/
public void setImageUrl(String url) {
this.setImageUrl(url, null);
}
/**
* 显示来自网络的图片
*
* <p>
* 本功能会自动缓存图片的数据分别到本地文件与内存,当显示图片时,将根据内存 -> 本地文件的顺序尝试加载已缓存的图片数据。
* </p>
*
* @param url
* 网络上的图片的完整路径,例如 http://www.baidu.com/logo.png
* @param otps
* 当BitmapFactory需要decode文件时的参数,例如将图片压缩等等
*/
public void setImageUrl(String url, Options opts) {
if (webImage == null) {
webImage = new WebImage(url, opts);
} else {
webImage.setUrl(url);
}
new LoadWebImageTask().execute();
}
//异步操作来执行WebImage操作
private class LoadWebImageTask extends AsyncTask<Void, Void, Void> {
private Bitmap bm;
@Override
protected Void doInBackground(Void... params) {
bm = webImage.getBitmap();
return null;
}
@Override
protected void onPostExecute(Void result) {
//如果拿不到图片,则给个系统的图片
if (bm == null) {
CustomImageView.this.setImageResource(R.drawable.ic_launcher);
} else {
CustomImageView.this.setImageBitmap(bm);
}
}
}
}
打完收工!