一、名词解释
客户端缓存机制是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。如果目录下存在文件,则直接加载目录下的文件。