您的位置:首页 > 移动开发 > Android开发

android异步加载图片显示,并且对图片进行缓存实例

2013-07-11 09:42 771 查看


android异步加载图片显示,并且对图片进行缓存实例

分类: Android2013-04-16
14:31 493人阅读 评论(4) 收藏 举报

step1:新建项目DataAsyncLoad,如下图所示



step2:设置应用的UI界面

a.应用的主界面 main.xml

[html] view
plaincopy

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

<ListView

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:id="@+id/listView"

/>

</LinearLayout>

b.每个ListView的界面 listview_item.xml

[html] view
plaincopy

<?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="42dp"

android:layout_height="42dp"

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>

step3:写一些辅助类 cn.roco.data.utilsMD5.java

[java] view
plaincopy

package cn.roco.data.utils;

import java.security.MessageDigest;

import java.security.NoSuchAlgorithmException;

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();

}

}

step4:写应用使用的JavaBean cn.roco.data.domain.Contact.java

[java] view
plaincopy

package cn.roco.data.domain;

public class Contact {

private int id;

private String name;

private String image;

public int getId() {

return id;

}

public void setId(int id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getImage() {

return image;

}

public void setImage(String image) {

this.image = image;

}

public Contact(int id, String name, String image) {

this.id = id;

this.name = name;

this.image = image;

}

public Contact(){

}

}

step5:写一个应用的service层,用于对javabean进行操作 cn.roco.data.service.ContactService.java

[java] view
plaincopy

package cn.roco.data.service;

import java.io.File;

import java.io.FileOutputStream;

import java.io.InputStream;

import java.net.HttpURLConnection;

import java.net.URL;

import java.util.ArrayList;

import java.util.List;

import org.xmlpull.v1.XmlPullParser;

import android.net.Uri;

import android.util.Xml;

import cn.roco.data.domain.Contact;

import cn.roco.data.utils.MD5;

public class ContactService {

/**

* 获取联系人数据

*

* @return

* @throws Exception

*/

public static List<Contact> getContacts() throws Exception {

String path = "http://192.168.1.100:8080/Hello/contact.xml";

HttpURLConnection connection = (HttpURLConnection) new URL(path)

.openConnection();

connection.setConnectTimeout(5000);

connection.setRequestMethod("GET");

if (connection.getResponseCode() == 200) {

return parseXML(connection.getInputStream());

}

return null;

}

/**转化XML获取数据

* 服务器端的xml文件如下。。。。。。

* <?xml version="1.0" encoding="UTF-8"?>

<contacts>

<contact id="1">

<name>Roco_1</name>

<image src="http://192.168.1.100:8080/Hello/images/1.png" />

</contact>

.......

</contacts>*/

private static List<Contact> parseXML(InputStream inputStream)

throws Exception {

List<Contact> contacts = new ArrayList<Contact>();

Contact contact = null;

XmlPullParser pullParser = Xml.newPullParser();

pullParser.setInput(inputStream, "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.setId(new Integer(pullParser.getAttributeValue(0)));

} else if ("name".equals(pullParser.getName())) {

contact.setName(pullParser.nextText());

} else if ("image".equals(pullParser.getName())) {

contact.setImage(pullParser.getAttributeValue(0));

}

break;

case XmlPullParser.END_TAG:

if ("contact".equals(pullParser.getName())) {

contacts.add(contact);

contact = null;

}

}

event = pullParser.next();

}

return contacts;

}

/**

* 获取网络图片,如果图片存在于缓存中,就返回该图片,否则从网络中加载该图片并缓存起来

*

* @param path

* 图片路径

* @return

*/

public static Uri getImage(String imagePath, File cacheDir)

throws Exception {

//缓存文件的文件名用MD5进行加密

File localFile = new File(cacheDir, MD5.getMD5(imagePath)

+ imagePath.substring(imagePath.lastIndexOf(".")));

if (localFile.exists()) {

return Uri.fromFile(localFile);

} else {

HttpURLConnection connection = (HttpURLConnection) new URL(

imagePath).openConnection();

connection.setConnectTimeout(5000);

connection.setRequestMethod("GET");

//将文件缓存起来

if (connection.getResponseCode() == 200) {

FileOutputStream outputStream = new FileOutputStream(localFile);

InputStream inputStream = connection.getInputStream();

byte[] buffer = new byte[1024];

int len = 0;

while ((len = inputStream.read(buffer)) != -1) {

outputStream.write(buffer, 0, len);

}

inputStream.close();

outputStream.close();

return Uri.fromFile(localFile);

}

}

return null;

}

}

step6:写一个Adapter用于对ListView进行数据更新 cn.roco.data.adapter.ContactAdapter.java

[java] view
plaincopy

package cn.roco.data.adapter;

import java.io.File;

import java.util.List;

import cn.roco.data.R;

import cn.roco.data.domain.Contact;

import cn.roco.data.service.ContactService;

import android.content.Context;

import android.net.Uri;

import android.os.AsyncTask;

import android.os.Handler;

import android.os.Message;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.BaseAdapter;

import android.widget.ImageView;

import android.widget.TextView;

/**适配器,用于更新View*/

public class ContactAdapter extends BaseAdapter {

private List<Contact> data;

private int listviewItem;

private File cache;

/**

* LayoutInflater的作用类似于 findViewById(),不同点是LayoutInflater是用来找layout文件夹下的xml布局文件,并且实例化!

* 而 findViewById()是找具体某一个xml下的具体 widget控件(如:Button,TextView等)。

*/

private LayoutInflater layoutInflater;

public ContactAdapter(Context context, List<Contact> data,

int listviewItem, File cache) {

this.data = data;

this.listviewItem = listviewItem;

this.cache = cache;

this.layoutInflater = (LayoutInflater) context

.getSystemService(Context.LAYOUT_INFLATER_SERVICE);//取得xml里定义的view

/***

* getSystemService()是Android很重要的一个API,它是Activity的一个方法,

* 根据传入的NAME来取得对应的Object,然后转换成相应的服务对象。以下介绍系统相应的服务。

* 传入的Name 返回的对象 说明

WINDOW_SERVICE WindowManager 管理打开的窗口程序

LAYOUT_INFLATER_SERVICE LayoutInflater 取得xml里定义的view

ACTIVITY_SERVICE ActivityManager 管理应用程序的系统状态

POWER_SERVICE PowerManger 电源的服务

ALARM_SERVICE AlarmManager 闹钟的服务

NOTIFICATION_SERVICE NotificationManager 状态栏的服务

KEYGUARD_SERVICE KeyguardManager 键盘锁的服务

LOCATION_SERVICE LocationManager 位置的服务,如GPS

SEARCH_SERVICE SearchManager 搜索的服务

VEBRATOR_SERVICE Vebrator 手机震动的服务

CONNECTIVITY_SERVICE Connectivity 网络连接的服务

WIFI_SERVICE WifiManager Wi-Fi服务

TELEPHONY_SERVICE TeleponyManager 电话服务

*/

}

/** 得到数据的总数 */

@Override

public int getCount() {

return data.size();

}

/** 根据数据索引,得到集合中所对应的数据 */

@Override

public Object getItem(int position) {

return data.get(position);

}

@Override

public long getItemId(int position) {

return position;

}

@Override

public View getView(int position, View convertView, ViewGroup parent) {

ImageView imageView = null;

TextView textView = null;

if (convertView == null) {

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.getImageView();

textView=dataWrapper.getTextView();

}

Contact contact=data.get(position);

textView.setText(contact.getName());

/**异步加载图片文件*/

asynchImageLoad(imageView,contact.getImage());

return convertView;

}

/*

//该方法会创建很多的线程,也会很耗资源

private void asynchImageLoad(final ImageView imageView, final String imagePath) {

final Handler handler=new Handler(){

@Override

public void handleMessage(Message msg) {//运行在主线程中

Uri uri=(Uri) msg.obj;

if (uri!=null&&imageView!=null) {

imageView.setImageURI(uri);

}

}

};

Runnable runnable=new Runnable() {

@Override

public void run() {

try {

Uri uri=ContactService.getImage(imagePath, cache);

handler.sendMessage(handler.obtainMessage(10,uri));

} catch (Exception e) {

e.printStackTrace();

}

}

};

new Thread(runnable).start();

}

*/

/**异步加载图片文件*/

private void asynchImageLoad(ImageView imageView, String imagePath) {

AsycImageTask asycImageTask=new AsycImageTask(imageView);

asycImageTask.execute(imagePath);

}

/**

* 使用AsyncTask提高性能

* 可选方法:

1, onprogressupdate(progress…) 可以使用进度条增加用户体验度。此方法在主线程执行,用户显示任务执行的进度。

2, onpreExecute() 这里是最新用户调用excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。

3, onCancelled() 用户调用取消时,要做的操作。

AsyncTask<Params, Progress, Result>

AsyscTask定义了三种泛型类型params,progress和result.

1, params启动任务执行的输入参数,比如http请求的URL

2, progress后台任务执行的百分比

3, result后台执行任务最终返回的结果,比如String,比如我需要得到的list。

使用AsyncTask类,遵守的准则:1, Task的实例必须在UI thread中创建;2, Execute方法必须在UI thread中调用

3, 不要手动的调用onPfreexecute(),onPostExecute(result)Doinbackground(params…),onProgressupdate(progress…)这几个方法;

4, 该task只能被执行一次,否则多次调用时将会出现异常;

AsyncTask的整个调用过程都是从execute方法开始的,一旦在主线程中调用execute方法,就可以通过onpreExecute方法,

这是一个预处理方法,比如可以在这里开始一个进度框,同样也可以通过onprogressupdate方法给用户一个进度条的显示,增加用户体验;

最后通过onpostexecute方法,相当于handler处理UI的方式,在这里可以使用在doinbackground得到的结果处理操作UI。

此方法在主线程执行,任务执行的结果作为此方法的参数返回

*/

private final class AsycImageTask extends AsyncTask<String, Integer, Uri>{

private ImageView imageView;

public AsycImageTask(ImageView imageView) {

this.imageView=imageView;

}

/**

* 后台执行,比较耗时的操作都可以放在这里。

注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作

,通常需要较长的时间。在执行过程中可以调用

Public progress(progress…)来更新任务的进度。

*/

@Override

protected Uri doInBackground(String... params) {//子线程中执行

try {

return ContactService.getImage(params[0], cache);

} catch (Exception e) {

e.printStackTrace();

}

return null;

}

/**

* 相当于handler处理UI的方式,在这里可以使用在doinbackground得到的结果

* 处理操作UI。此方法在主线程执行,任务执行的结果作为此方法的参数返回。

*/

@Override

protected void onPostExecute(Uri result) {//运行在主线程

if (result!=null&&imageView!=null) {

imageView.setImageURI(result);

}

}

}

/**数据包装类*/

private final class DataWrapper {

private ImageView imageView;

private TextView textView;

public ImageView getImageView() {

return imageView;

}

public TextView getTextView() {

return textView;

}

public DataWrapper(ImageView imageView, TextView textView) {

this.imageView = imageView;

this.textView = textView;

}

}

}

step7:应用的主程序 cn.roco.data.MainActivity.java

[java] view
plaincopy

package cn.roco.data;

import java.io.File;

import java.util.List;

import cn.roco.data.adapter.ContactAdapter;

import cn.roco.data.domain.Contact;

import cn.roco.data.service.ContactService;

import android.app.Activity;

import android.os.Bundle;

import android.os.Environment;

import android.os.Handler;

import android.widget.ListView;

public class MainActivity extends Activity {

private ListView listView;

/**缓存文件*/

private File cache;

/**接受消息,处理消息 ,此Handler会与当前主线程一块运行

* 使用匿名内部类来复写Handler当中的handlerMessage()方法 */

Handler handler = new Handler() {

// 接受数据

public void handleMessage(android.os.Message msg) {

//设置适配器,将获取的数据使用适配器更新View

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);

/**在SD卡中生成缓存目录*/

cache = new File(Environment.getExternalStorageDirectory(), "cache");

/**如果目录不存在就新建一个*/

if (!cache.exists()) cache.mkdir();

new Thread(new Runnable() {

@Override

public void run() {

try {

//获取联系人数据

List<Contact> data= ContactService.getContacts();

// 向Handler发送消息,更新UI

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();

}

}

step8:AndroidManifest.xml

[html] view
plaincopy

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="cn.roco.data" android:versionCode="1" android:versionName="1.0">

<uses-sdk android:minSdkVersion="8" />

<!-- 访问Internet权限 -->

<uses-permission android:name="android.permission.INTERNET" />

<!-- 在SD卡中创建和删除文件权限 -->

<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

<!-- 往SD卡中写入数据权限 -->

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<application android:icon="@drawable/icon" android:label="@string/app_name">

<activity android:name=".MainActivity" android:label="@string/app_name">

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>

</application>

</manifest>

step9:编写服务器端的代码,主要是一个contact.xml文件

[html] view
plaincopy

<?xml version="1.0" encoding="UTF-8"?>

<contacts>

<contact id="1">

<name>Roco_1</name>

<image src="http://192.168.1.100:8080/Hello/images/1.png" />

</contact>

<contact id="2">

<name>Roco_2</name>

<image src="http://192.168.1.100:8080/Hello/images/2.png" />

</contact>

<contact id="3">

<name>Roco_3</name>

<image src="http://192.168.1.100:8080/Hello/images/3.png" />

</contact>

<contact id="4">

<name>Roco_4</name>

<image src="http://192.168.1.100:8080/Hello/images/4.png" />

</contact>

<contact id="5">

<name>Roco_5</name>

<image src="http://192.168.1.100:8080/Hello/images/5.png" />

</contact>

<contact id="6">

<name>Roco_6</name>

<image src="http://192.168.1.100:8080/Hello/images/6.png" />

</contact>

<contact id="7">

<name>Roco_7</name>

<image src="http://192.168.1.100:8080/Hello/images/7.png" />

</contact>

<contact id="8">

<name>Roco_8</name>

<image src="http://192.168.1.100:8080/Hello/images/8.png" />

</contact>

<contact id="9">

<name>Roco_9</name>

<image src="http://192.168.1.100:8080/Hello/images/9.png" />

</contact>

<contact id="10">

<name>Roco_10</name>

<image src="http://192.168.1.100:8080/Hello/images/10.png" />

</contact>

<contact id="11">

<name>Roco_11</name>

<image src="http://192.168.1.100:8080/Hello/images/11.png" />

</contact>

<contact id="12">

<name>Roco_12</name>

<image src="http://192.168.1.100:8080/Hello/images/12.png" />

</contact>

<contact id="13">

<name>Roco_13</name>

<image src="http://192.168.1.100:8080/Hello/images/13.png" />

</contact>

<contact id="14">

<name>Roco_14</name>

<image src="http://192.168.1.100:8080/Hello/images/14.png" />

</contact>

<contact id="15">

<name>Roco_15</name>

<image src="http://192.168.1.100:8080/Hello/images/15.png" />

</contact>

<contact id="16">

<name>Roco_16</name>

<image src="http://192.168.1.100:8080/Hello/images/16.png" />

</contact>

<contact id="17">

<name>Roco_17</name>

<image src="http://192.168.1.100:8080/Hello/images/17.png" />

</contact>

<contact id="18">

<name>Roco_18</name>

<image src="http://192.168.1.100:8080/Hello/images/18.png" />

</contact>

<contact id="19">

<name>Roco_19</name>

<image src="http://192.168.1.100:8080/Hello/images/19.png" />

</contact>

<contact id="20">

<name>Roco_20</name>

<image src="http://192.168.1.100:8080/Hello/images/20.png" />

</contact>

</contacts>

以及在images目录下放置了一些图片



step10:将项目部署到模拟器上运行效果如下图:





在SD卡中会生成缓存文件



当应用退出的时候,会将缓存文件删除



有了缓存文件,只要应用没有退出,即使联网不成功,也可以读取缓存中的图片文件
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐