实现数据的网络异步加载及文件缓存
用到的权限
<!-- 访问internet权限 -->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- 在SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 往SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
listview_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<ImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:id="@+id/imageView"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textColor="#FFFFFF"
android:id="@+id/textView"
/>
</LinearLayout>
public class MainActivity extends Activity {
ListView listView;
File cache;
Handler handler = new Handler(){
public void handleMessage(Message msg) {
listView.setAdapter(new ContactAdapter(MainActivity.this, (List<Contact>)msg.obj,
R.layout.listview_item, cache));
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
listView = (ListView) this.findViewById(R.id.listView);
cache = new File(Environment.getExternalStorageDirectory(), "cache");
if(!cache.exists()) cache.mkdirs();
new Thread(new Runnable() {
public void run() {
try {
List<Contact> data = ContactService.getContacts();//这个方法可能需要很长的时间,所以放在新的线程中,线程完成后通过Handler更新界面
handler.sendMessage(handler.obtainMessage(22, data));
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
@Override
protected void onDestroy() {
for(File file : cache.listFiles()){
file.delete();
}
cache.delete();
super.onDestroy();
}
}
Service中
public class ContactService {
/**
* 获取联系人
* @return
*/
public static List<Contact> getContacts() throws Exception{
String path = "http://192.168.1.100:8080/web/list.xml";
HttpURLConnection conn = (HttpURLConnection) new URL(path).openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
if(conn.getResponseCode() == 200){
return parseXML(conn.getInputStream());
}
return null;
}
private static List<Contact> parseXML(InputStream xml) throws Exception{
List<Contact> contacts = new ArrayList<Contact>();
Contact contact = null;
XmlPullParser pullParser = Xml.newPullParser();
pullParser.setInput(xml, "UTF-8");
int event = pullParser.getEventType();
while(event != XmlPullParser.END_DOCUMENT){
switch (event) {
case XmlPullParser.START_TAG:
if("contact".equals(pullParser.getName())){
contact = new Contact();
contact.id = new Integer(pullParser.getAttributeValue(0));
}else if("name".equals(pullParser.getName())){
contact.name = pullParser.nextText();
}else if("image".equals(pullParser.getName())){
contact.image = pullParser.getAttributeValue(0);
}
break;
case XmlPullParser.END_TAG:
if("contact".equals(pullParser.getName())){
contacts.add(contact);
contact = null;
}
break;
}
event = pullParser.next();
}
return contacts;
}
/**
* 获取网络图片,如果图片存在于缓存中,就返回该图片,否则从网络中加载该图片并缓存起来
* @param path 图片路径
* @return
*/
public static Uri getImage(String path, File cacheDir) throws Exception{// path -> MD5 ->32字符串.jpg
File localFile = new File(cacheDir, MD5.getMD5(path)+ path.substring(path.lastIndexOf(".")));
if(localFile.exists()){
return Uri.fromFile(localFile);
}else{
HttpURLConnection conn = (HttpURLConnection) new URL(path).openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
if(conn.getResponseCode() == 200){
FileOutputStream outStream = new FileOutputStream(localFile);
InputStream inputStream = conn.getInputStream();
byte[] buffer = new byte[1024];
int len = 0;
while( (len = inputStream.read(buffer)) != -1){
outStream.write(buffer, 0, len);
}
inputStream.close();
outStream.close();
return Uri.fromFile(localFile);
}
}
return null;
}
}
实体
public class Contact {
public int id;
public String name;
public String image;
public Contact(int id, String name, String image) {
this.id = id;
this.name = name;
this.image = image;
}
public Contact(){}
}
网络上准备的XML数据
<?xml version="1.0" encoding="UTF-8"?>
<images>
<image src="http://192.168.1.100:8080/web/images/1.gif"/>
<image src="http://192.168.1.100:8080/web/images/2.gif"/>
<image src="http://192.168.1.100:8080/web/images/3.gif"/>
<image src="http://192.168.1.100:8080/web/images/4.gif"/>
<image src="http://192.168.1.100:8080/web/images/5.gif"/>
<image src="http://192.168.1.100:8080/web/images/6.gif"/>
<image src="http://192.168.1.100:8080/web/images/7.gif"/>
<image src="http://192.168.1.100:8080/web/images/8.gif"/>
<image src="http://192.168.1.100:8080/web/images/9.gif"/>
<image src="http://192.168.1.100:8080/web/images/10.gif"/>
<image src="http://192.168.1.100:8080/web/images/11.gif"/>
<image src="http://192.168.1.100:8080/web/images/12.gif"/>
<image src="http://192.168.1.100:8080/web/images/13.gif"/>
<image src="http://192.168.1.100:8080/web/images/14.gif"/>
<image src="http://192.168.1.100:8080/web/images/15.jpg"/>
<image src="http://192.168.1.100:8080/web/images/16.jpg"/>
<image src="http://192.168.1.100:8080/web/images/17.jpg"/>
<image src="http://192.168.1.100:8080/web/images/18.jpg"/>
</images>
ContactAdapter【ListView的适配器,实现异步加载】
public class ContactAdapter extends BaseAdapter {
private List<Contact> data;
private int listviewItem;
private File cache;
LayoutInflater layoutInflater;
public ContactAdapter(Context context, List<Contact> data, int listviewItem, File cache) {
this.data = data;
this.listviewItem = listviewItem;
this.cache = cache;
layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
/**
* 得到数据的总数
*/
public int getCount() {
return data.size();
}
/**
* 根据数据索引得到集合所对应的数据
*/
public Object getItem(int position) {
return data.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = null;
TextView textView = null;
if(convertView == null){//防止多次生成新的view,重用原来的view
convertView = layoutInflater.inflate(listviewItem, null);
imageView = (ImageView) convertView.findViewById(R.id.imageView);
textView = (TextView) convertView.findViewById(R.id.textView);
convertView.setTag(new DataWrapper(imageView, textView));//保存起来
}else{
DataWrapper dataWrapper = (DataWrapper) convertView.getTag();//获取以前的重用
imageView = dataWrapper.imageView;
textView = dataWrapper.textView;
}
Contact contact = data.get(position);
textView.setText(contact.name);
asyncImageLoad(imageView, contact.image);
return convertView;
}
//以下是使用AsyncTask实现的异步加载
private void asyncImageLoad(ImageView imageView, String path) {
AsyncImageTask asyncImageTask = new AsyncImageTask(imageView);
asyncImageTask.execute(path);
}
private final class AsyncImageTask extends AsyncTask<String, Integer, Uri>{
private ImageView imageView;
public AsyncImageTask(ImageView imageView) {
this.imageView = imageView;
}
protected Uri doInBackground(String... params) {//子线程中执行的
try {
return ContactService.getImage(params[0], cache);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(Uri result) {//运行在主线程
if(result!=null && imageView!= null)
imageView.setImageURI(result);
}
}
//以下是使用Handler实现的异步加载,因为每次都生成一个新线程,如果条目太多的话就会有很多很多的线程,造成效率下降
/*
private void asyncImageLoad(final ImageView imageView, final String path) {
final Handler handler = new Handler(){
public void handleMessage(Message msg) {//运行在主线程中
Uri uri = (Uri)msg.obj;
if(uri!=null && imageView!= null)
imageView.setImageURI(uri);
}
};
Runnable runnable = new Runnable() {
public void run() {
try {
Uri uri = ContactService.getImage(path, cache);//这个方法可能很耗时间
handler.sendMessage(handler.obtainMessage(10, uri));
} catch (Exception e) {
e.printStackTrace();
}
}
};
new Thread(runnable).start();
}
*/
private final class DataWrapper{//DataHolder模式,使用public装数据,避免调用函数的开销
public ImageView imageView;
public TextView textView;
public DataWrapper(ImageView imageView, TextView textView) {
this.imageView = imageView;
this.textView = textView;
}
}
}
工具类
public class MD5 {
public static String getMD5(String content) {
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update(content.getBytes());
return getHashString(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
private static String getHashString(MessageDigest digest) {
StringBuilder builder = new StringBuilder();
for (byte b : digest.digest()) {
builder.append(Integer.toHexString((b >> 4) & 0xf));
builder.append(Integer.toHexString(b & 0xf));
}
return builder.toString();
}
}