一、名词解释
客户端缓存机制是android应用开发中非常重要的一项工作,使用缓存机制不仅仅可以为用户节省3G流量,同时在用户体验方面也是非常好的选择。
缓存机制分为两部分,一部分是文字缓存,另一部分是多媒体文件缓存。
缓存系统,要注意缓存内容的过期以及清除问题,尽量保证数据一致性。
二、以ListView为例
在ListView上显示多个从网络上下载的图片。如果是第一次运行程序,需要实时从网络上下载这些图片文件。但由于网络速度的原因,如果一边下载、一边显示,ListView就会有些卡。所以我们采用了缓存技术,也就是说,当ListView显示网络上某个图片时,先显示默认的本地图片,然后启动一个线程下载图片,当下载完后,再通知ListView重新显示下载后的图片。
Download.java:
未缓存时下载图片所需类,用到了HttpConnection.
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
public class Download extends Thread {
private CacheAdapter mCacheAdapter;
private String mUrl;
private String mFilename;
private Handler mHandler = new Handler()
{
@Override
public void handleMessage(Message msg) {
mCacheAdapter.notifyDataSetChanged();
}
};
public Download(CacheAdapter adapter, String url) {
mCacheAdapter = adapter;
mUrl = url;
mFilename = "/sdcard/" + url.hashCode();
}
@Override
public void run() {
try {
URL url = new URL(mUrl);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.setDoInput(true);
u盾 connection.setDoOutput(true);
connection.setUseCaches(false);
connection.setRequestMethod("GET");
InputStream is= connection.getInputStream();
FileOutputStream fos = new FileOutputStream(mFilename);
byte[] buffer = new byte[8192];
int count = 0;
while((count = is.read(buffer)) > -1)
{
fos.write(buffer, 0, count);
}
fos.close();
is.close();
connection.disconnect();
mHandler.sendEmptyMessage(0);
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
}
CacheAdapter.java
缓存适配器,继承了BaseAdpter.
package cn.eoe.cache;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.Toast;
public class CacheAdapter extends BaseAdapter {
private List<String> mUrls = new ArrayList<String>();
private LayoutInflater mLayoutInflater;
private Context mContext;
public CacheAdapter(Context context) {
mUrls.add("http://ww4.sinaimg.cn/bmiddle/84217b4fjw1e3zvdsjtupj20ih0ppn13.jpg");
mUrls.add("http://ww2.sinaimg.cn/bmiddle/76a19fefjw1e3zr5z0zi7j20sg0fjtdg.jpg");
mUrls.add("http://ww1.sinaimg.cn/bmiddle/475b3d56jw1e3zvdwoln1j208c08c0tr.jpg");
mUrls.add("http://ww1.sinaimg.cn/bmiddle/6e3fa31fjw1e3zvfd6zqlj20c807fwfr.jpg");
mUrls.add("http://ww1.sinaimg.cn/bmiddle/6adce985jw1e3zttk0v20j20b408cglh.jpg");
mUrls.add("http://ww1.sinaimg.cn/bmiddle/63918611jw1e3ztipg4lij205r064dge.jpg");
mLayoutInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mContext = context;
}
@Override
public int getCount() {
return mUrls.size();
}
@Override
public Object getItem(int position) {
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) {
if (convertView == null) {
convertView = mLayoutInflater.inflate(R.layout.item, null);
}
ImageView imageView = (ImageView) convertView.findViewById(R.id.imageview);
imageView.setImageBitmap(getBitmap(position));
return convertView;
}
// cache
private Bitmap getBitmap(int position) {
Bitmap bitmap = null;
String filename = "/sdcard/" + mUrls.get(position).hashCode();
if (new File(filename).exists()) {
try {
bitmap = BitmapFactory.decodeFile(filename);
} catch (Exception e) {
// TODO: handle exception
}
} else {
bitmap = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.ic_launcher);
new Download(this, mUrls.get(position)).start();
}
return bitmap;
}
}
当图片加载完时,通过notifyDataSetChanged()方法更新ListView。如果目录下存在文件,则直接加载目录下的文件。