博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
我的Android进阶之旅------>android异步加载图片显示,并且对图片进行缓存实例
阅读量:7282 次
发布时间:2019-06-30

本文共 13871 字,大约阅读时间需要 46 分钟。

先来看看效果示意图:

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

step2:设置应用的UI界面

a.应用的主界面    main.xml

b.每个ListView的界面  listview_item.xml

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

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

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

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
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文件如下。。。。。。 *
Roco_1
.......
*/ private static List
parseXML(InputStream inputStream) throws Exception { List
contacts = new ArrayList
(); 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

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
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
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
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
{ 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

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

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

Roco_1
Roco_2
Roco_3
Roco_4
Roco_5
Roco_6
Roco_7
Roco_8
Roco_9
Roco_10
Roco_11
Roco_12
Roco_13
Roco_14
Roco_15
Roco_16
Roco_17
Roco_18
Roco_19
Roco_20
以及在images目录下放置了一些图片

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

         

==================================下面看一个gif动画===========================================

                      

在SD卡中会生成缓存文件

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

有了缓存文件,只要应用没有退出,即使联网不成功,也可以读取缓存中的图片文件

==================================================================================================

  作者:欧阳鹏  欢迎转载,与人分享是进步的源泉!

  转载请保留原文地址

==================================================================================================

转载于:https://www.cnblogs.com/ouyangpeng/archive/2013/04/16/8538397.html

你可能感兴趣的文章
Mozilla网站安全分析工具Observatory已发布
查看>>
.NET Core 2.1改进了性能,并提供了新的部署选项
查看>>
AWS推出RoboMaker,可构建智能机器人应用程序
查看>>
1100名达摩院“扫地僧”加持,阿里云的下一个十年
查看>>
取代ZooKeeper!高并发下的分布式一致性开源组件StateSynchronizer
查看>>
《Elasticsearch in Action》书评与作者访谈
查看>>
腾讯云发布CDN 2.0,四大优势加速移动化进程
查看>>
Visual Studio 2017 15.6预览版最新进展
查看>>
ZenHub Epics创造了GitHub中敏捷Epics
查看>>
《七周七并发模型》作者Paul Butcher、阿里云研究员余锋(褚霸)——QCon北京2016前瞻...
查看>>
iOS应用开发登陆Windows平台惹争议
查看>>
《Java 20年:道路与梦想》迷你书发布
查看>>
GitHub的MySQL高可用性实践
查看>>
微软发布Azure Application Insights for Node.js 1.0版本
查看>>
UPYUN亮相GIF2016 展示实时性能监控系统
查看>>
Node.js async.parallelLimit 与 async.eachLimit 的区别与不同使用场景
查看>>
音频降噪在58直播中的研究与实现
查看>>
AI一周热闻:12306数据泄露,嫌疑人被捕;BERT提升文档检索性能至1.5-2倍
查看>>
知道大数据却不清楚工业大数据,知识架构“欠”在哪里?
查看>>
经验分享:微信小程序外包接单常见问题及流程
查看>>