android异步加载图片显示,并且对图片进行缓存实例
16lz
2021-01-23
android异步加载图片显示,并且对图片进行缓存实例
分类:Android 2013-04-16 14:31 493人阅读 评论(4) 收藏 举报step1:新建项目DataAsyncLoad,如下图所示
step2:设置应用的UI界面
a.应用的主界面 main.xml
[html] view plain copy
- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayoutxmlns: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 plain copy
- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayoutxmlns: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 plain copy
- packagecn.roco.data.utils;
- importjava.security.MessageDigest;
- importjava.security.NoSuchAlgorithmException;
- publicclassMD5{
- publicstaticStringgetMD5(Stringcontent){
- try{
- MessageDigestdigest=MessageDigest.getInstance("MD5");
- digest.update(content.getBytes());
- returngetHashString(digest);
- }catch(NoSuchAlgorithmExceptione){
- e.printStackTrace();
- }
- returnnull;
- }
- privatestaticStringgetHashString(MessageDigestdigest){
- StringBuilderbuilder=newStringBuilder();
- for(byteb:digest.digest()){
- builder.append(Integer.toHexString((b>>4)&0xf));
- builder.append(Integer.toHexString(b&0xf));
- }
- returnbuilder.toString();
- }
- }
[java] view plain copy
- packagecn.roco.data.domain;
- publicclassContact{
- privateintid;
- privateStringname;
- privateStringimage;
- publicintgetId(){
- returnid;
- }
- publicvoidsetId(intid){
- this.id=id;
- }
- publicStringgetName(){
- returnname;
- }
- publicvoidsetName(Stringname){
- this.name=name;
- }
- publicStringgetImage(){
- returnimage;
- }
- publicvoidsetImage(Stringimage){
- this.image=image;
- }
- publicContact(intid,Stringname,Stringimage){
- this.id=id;
- this.name=name;
- this.image=image;
- }
- publicContact(){
- }
- }
step5:写一个应用的service层,用于对javabean进行操作 cn.roco.data.service.ContactService.java
[java] view plain copy
- packagecn.roco.data.service;
- importjava.io.File;
- importjava.io.FileOutputStream;
- importjava.io.InputStream;
- importjava.net.HttpURLConnection;
- importjava.net.URL;
- importjava.util.ArrayList;
- importjava.util.List;
- importorg.xmlpull.v1.XmlPullParser;
- importandroid.net.Uri;
- importandroid.util.Xml;
- importcn.roco.data.domain.Contact;
- importcn.roco.data.utils.MD5;
- publicclassContactService{
- /**
- *获取联系人数据
- *
- *@return
- *@throwsException
- */
- publicstaticList<Contact>getContacts()throwsException{
- Stringpath="http://192.168.1.100:8080/Hello/contact.xml";
- HttpURLConnectionconnection=(HttpURLConnection)newURL(path)
- .openConnection();
- connection.setConnectTimeout(5000);
- connection.setRequestMethod("GET");
- if(connection.getResponseCode()==200){
- returnparseXML(connection.getInputStream());
- }
- returnnull;
- }
- /**转化XML获取数据
- *服务器端的xml文件如下。。。。。。
- *<?xmlversion="1.0"encoding="UTF-8"?>
- <contacts>
- <contactid="1">
- <name>Roco_1</name>
- <imagesrc="http://192.168.1.100:8080/Hello/images/1.png"/>
- </contact>
- .......
- </contacts>*/
- privatestaticList<Contact>parseXML(InputStreaminputStream)
- throwsException{
- List<Contact>contacts=newArrayList<Contact>();
- Contactcontact=null;
- XmlPullParserpullParser=Xml.newPullParser();
- pullParser.setInput(inputStream,"UTF-8");
- intevent=pullParser.getEventType();
- while(event!=XmlPullParser.END_DOCUMENT){
- switch(event){
- caseXmlPullParser.START_TAG:
- if("contact".equals(pullParser.getName())){
- contact=newContact();
- contact.setId(newInteger(pullParser.getAttributeValue(0)));
- }elseif("name".equals(pullParser.getName())){
- contact.setName(pullParser.nextText());
- }elseif("image".equals(pullParser.getName())){
- contact.setImage(pullParser.getAttributeValue(0));
- }
- break;
- caseXmlPullParser.END_TAG:
- if("contact".equals(pullParser.getName())){
- contacts.add(contact);
- contact=null;
- }
- }
- event=pullParser.next();
- }
- returncontacts;
- }
- /**
- *获取网络图片,如果图片存在于缓存中,就返回该图片,否则从网络中加载该图片并缓存起来
- *
- *@parampath
- *图片路径
- *@return
- */
- publicstaticUrigetImage(StringimagePath,FilecacheDir)
- throwsException{
- //缓存文件的文件名用MD5进行加密
- FilelocalFile=newFile(cacheDir,MD5.getMD5(imagePath)
- +imagePath.substring(imagePath.lastIndexOf(".")));
- if(localFile.exists()){
- returnUri.fromFile(localFile);
- }else{
- HttpURLConnectionconnection=(HttpURLConnection)newURL(
- imagePath).openConnection();
- connection.setConnectTimeout(5000);
- connection.setRequestMethod("GET");
- //将文件缓存起来
- if(connection.getResponseCode()==200){
- FileOutputStreamoutputStream=newFileOutputStream(localFile);
- InputStreaminputStream=connection.getInputStream();
- byte[]buffer=newbyte[1024];
- intlen=0;
- while((len=inputStream.read(buffer))!=-1){
- outputStream.write(buffer,0,len);
- }
- inputStream.close();
- outputStream.close();
- returnUri.fromFile(localFile);
- }
- }
- returnnull;
- }
- }
step6:写一个Adapter用于对ListView进行数据更新cn.roco.data.adapter.ContactAdapter.java
[java] view plain copy
- packagecn.roco.data.adapter;
- importjava.io.File;
- importjava.util.List;
- importcn.roco.data.R;
- importcn.roco.data.domain.Contact;
- importcn.roco.data.service.ContactService;
- importandroid.content.Context;
- importandroid.net.Uri;
- importandroid.os.AsyncTask;
- importandroid.os.Handler;
- importandroid.os.Message;
- importandroid.view.LayoutInflater;
- importandroid.view.View;
- importandroid.view.ViewGroup;
- importandroid.widget.BaseAdapter;
- importandroid.widget.ImageView;
- importandroid.widget.TextView;
- /**适配器,用于更新View*/
- publicclassContactAdapterextendsBaseAdapter{
- privateList<Contact>data;
- privateintlistviewItem;
- privateFilecache;
- /**
- *LayoutInflater的作用类似于findViewById(),不同点是LayoutInflater是用来找layout文件夹下的xml布局文件,并且实例化!
- *而findViewById()是找具体某一个xml下的具体widget控件(如:Button,TextView等)。
- */
- privateLayoutInflaterlayoutInflater;
- publicContactAdapter(Contextcontext,List<Contact>data,
- intlistviewItem,Filecache){
- 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_SERVICEWindowManager管理打开的窗口程序
- LAYOUT_INFLATER_SERVICELayoutInflater取得xml里定义的view
- ACTIVITY_SERVICEActivityManager管理应用程序的系统状态
- POWER_SERVICEPowerManger电源的服务
- ALARM_SERVICEAlarmManager闹钟的服务
- NOTIFICATION_SERVICENotificationManager状态栏的服务
- KEYGUARD_SERVICEKeyguardManager键盘锁的服务
- LOCATION_SERVICELocationManager位置的服务,如GPS
- SEARCH_SERVICESearchManager搜索的服务
- VEBRATOR_SERVICEVebrator手机震动的服务
- CONNECTIVITY_SERVICEConnectivity网络连接的服务
- WIFI_SERVICEWifiManagerWi-Fi服务
- TELEPHONY_SERVICETeleponyManager电话服务
- */
- }
- /**得到数据的总数*/
- @Override
- publicintgetCount(){
- returndata.size();
- }
- /**根据数据索引,得到集合中所对应的数据*/
- @Override
- publicObjectgetItem(intposition){
- returndata.get(position);
- }
- @Override
- publiclonggetItemId(intposition){
- returnposition;
- }
- @Override
- publicViewgetView(intposition,ViewconvertView,ViewGroupparent){
- ImageViewimageView=null;
- TextViewtextView=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(newDataWrapper(imageView,textView));//将内容包装起来以备以后使用
- }else{
- DataWrapperdataWrapper=(DataWrapper)convertView.getTag();//将包装类取出来
- //从包装类中取数据
- imageView=dataWrapper.getImageView();
- textView=dataWrapper.getTextView();
- }
- Contactcontact=data.get(position);
- textView.setText(contact.getName());
- /**异步加载图片文件*/
- asynchImageLoad(imageView,contact.getImage());
- returnconvertView;
- }
- /*
- //该方法会创建很多的线程,也会很耗资源
- privatevoidasynchImageLoad(finalImageViewimageView,finalStringimagePath){
- finalHandlerhandler=newHandler(){
- @Override
- publicvoidhandleMessage(Messagemsg){//运行在主线程中
- Uriuri=(Uri)msg.obj;
- if(uri!=null&&imageView!=null){
- imageView.setImageURI(uri);
- }
- }
- };
- Runnablerunnable=newRunnable(){
- @Override
- publicvoidrun(){
- try{
- Uriuri=ContactService.getImage(imagePath,cache);
- handler.sendMessage(handler.obtainMessage(10,uri));
- }catch(Exceptione){
- e.printStackTrace();
- }
- }
- };
- newThread(runnable).start();
- }
- */
- /**异步加载图片文件*/
- privatevoidasynchImageLoad(ImageViewimageView,StringimagePath){
- AsycImageTaskasycImageTask=newAsycImageTask(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的实例必须在UIthread中创建;2,Execute方法必须在UIthread中调用
- 3,不要手动的调用onPfreexecute(),onPostExecute(result)Doinbackground(params…),onProgressupdate(progress…)这几个方法;
- 4,该task只能被执行一次,否则多次调用时将会出现异常;
- AsyncTask的整个调用过程都是从execute方法开始的,一旦在主线程中调用execute方法,就可以通过onpreExecute方法,
- 这是一个预处理方法,比如可以在这里开始一个进度框,同样也可以通过onprogressupdate方法给用户一个进度条的显示,增加用户体验;
- 最后通过onpostexecute方法,相当于handler处理UI的方式,在这里可以使用在doinbackground得到的结果处理操作UI。
- 此方法在主线程执行,任务执行的结果作为此方法的参数返回
- */
- privatefinalclassAsycImageTaskextendsAsyncTask<String,Integer,Uri>{
- privateImageViewimageView;
- publicAsycImageTask(ImageViewimageView){
- this.imageView=imageView;
- }
- /**
- *后台执行,比较耗时的操作都可以放在这里。
- 注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作
- ,通常需要较长的时间。在执行过程中可以调用
- Publicprogress(progress…)来更新任务的进度。
- */
- @Override
- protectedUridoInBackground(String...params){//子线程中执行
- try{
- returnContactService.getImage(params[0],cache);
- }catch(Exceptione){
- e.printStackTrace();
- }
- returnnull;
- }
- /**
- *相当于handler处理UI的方式,在这里可以使用在doinbackground得到的结果
- *处理操作UI。此方法在主线程执行,任务执行的结果作为此方法的参数返回。
- */
- @Override
- protectedvoidonPostExecute(Uriresult){//运行在主线程
- if(result!=null&&imageView!=null){
- imageView.setImageURI(result);
- }
- }
- }
- /**数据包装类*/
- privatefinalclassDataWrapper{
- privateImageViewimageView;
- privateTextViewtextView;
- publicImageViewgetImageView(){
- returnimageView;
- }
- publicTextViewgetTextView(){
- returntextView;
- }
- publicDataWrapper(ImageViewimageView,TextViewtextView){
- this.imageView=imageView;
- this.textView=textView;
- }
- }
- }
step7:应用的主程序 cn.roco.data.MainActivity.java
[java] view plain copy
- packagecn.roco.data;
- importjava.io.File;
- importjava.util.List;
- importcn.roco.data.adapter.ContactAdapter;
- importcn.roco.data.domain.Contact;
- importcn.roco.data.service.ContactService;
- importandroid.app.Activity;
- importandroid.os.Bundle;
- importandroid.os.Environment;
- importandroid.os.Handler;
- importandroid.widget.ListView;
- publicclassMainActivityextendsActivity{
- privateListViewlistView;
- /**缓存文件*/
- privateFilecache;
- /**接受消息,处理消息,此Handler会与当前主线程一块运行
- *使用匿名内部类来复写Handler当中的handlerMessage()方法*/
- Handlerhandler=newHandler(){
- //接受数据
- publicvoidhandleMessage(android.os.Messagemsg){
- //设置适配器,将获取的数据使用适配器更新View
- listView.setAdapter(newContactAdapter(MainActivity.this,
- (List<Contact>)msg.obj,R.layout.listview_item,cache));
- };
- };
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- listView=(ListView)this.findViewById(R.id.listView);
- /**在SD卡中生成缓存目录*/
- cache=newFile(Environment.getExternalStorageDirectory(),"cache");
- /**如果目录不存在就新建一个*/
- if(!cache.exists())cache.mkdir();
- newThread(newRunnable(){
- @Override
- publicvoidrun(){
- try{
- //获取联系人数据
- List<Contact>data=ContactService.getContacts();
- //向Handler发送消息,更新UI
- handler.sendMessage(handler.obtainMessage(22,data));
- }catch(Exceptione){
- e.printStackTrace();
- }
- }
- }).start();
- }
- @Override
- protectedvoidonDestroy(){
- /**清除缓存文件*/
- for(Filefile:cache.listFiles()){
- file.delete();
- }
- cache.delete();
- super.onDestroy();
- }
- }
step8:AndroidManifest.xml
[html] view plain copy
- <?xmlversion="1.0"encoding="utf-8"?>
- <manifestxmlns:android="http://schemas.android.com/apk/res/android"
- package="cn.roco.data"android:versionCode="1"android:versionName="1.0">
- <uses-sdkandroid:minSdkVersion="8"/>
- <!--访问Internet权限-->
- <uses-permissionandroid:name="android.permission.INTERNET"/>
- <!--在SD卡中创建和删除文件权限-->
- <uses-permissionandroid:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
- <!--往SD卡中写入数据权限-->
- <uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- <applicationandroid:icon="@drawable/icon"android:label="@string/app_name">
- <activityandroid:name=".MainActivity"android:label="@string/app_name">
- <intent-filter>
- <actionandroid:name="android.intent.action.MAIN"/>
- <categoryandroid:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- </application>
- </manifest>
step9:编写服务器端的代码,主要是一个contact.xml文件
[html] view plain copy
- <?xmlversion="1.0"encoding="UTF-8"?>
- <contacts>
- <contactid="1">
- <name>Roco_1</name>
- <imagesrc="http://192.168.1.100:8080/Hello/images/1.png"/>
- </contact>
- <contactid="2">
- <name>Roco_2</name>
- <imagesrc="http://192.168.1.100:8080/Hello/images/2.png"/>
- </contact>
- <contactid="3">
- <name>Roco_3</name>
- <imagesrc="http://192.168.1.100:8080/Hello/images/3.png"/>
- </contact>
- <contactid="4">
- <name>Roco_4</name>
- <imagesrc="http://192.168.1.100:8080/Hello/images/4.png"/>
- </contact>
- <contactid="5">
- <name>Roco_5</name>
- <imagesrc="http://192.168.1.100:8080/Hello/images/5.png"/>
- </contact>
- <contactid="6">
- <name>Roco_6</name>
- <imagesrc="http://192.168.1.100:8080/Hello/images/6.png"/>
- </contact>
- <contactid="7">
- <name>Roco_7</name>
- <imagesrc="http://192.168.1.100:8080/Hello/images/7.png"/>
- </contact>
- <contactid="8">
- <name>Roco_8</name>
- <imagesrc="http://192.168.1.100:8080/Hello/images/8.png"/>
- </contact>
- <contactid="9">
- <name>Roco_9</name>
- <imagesrc="http://192.168.1.100:8080/Hello/images/9.png"/>
- </contact>
- <contactid="10">
- <name>Roco_10</name>
- <imagesrc="http://192.168.1.100:8080/Hello/images/10.png"/>
- </contact>
- <contactid="11">
- <name>Roco_11</name>
- <imagesrc="http://192.168.1.100:8080/Hello/images/11.png"/>
- </contact>
- <contactid="12">
- <name>Roco_12</name>
- <imagesrc="http://192.168.1.100:8080/Hello/images/12.png"/>
- </contact>
- <contactid="13">
- <name>Roco_13</name>
- <imagesrc="http://192.168.1.100:8080/Hello/images/13.png"/>
- </contact>
- <contactid="14">
- <name>Roco_14</name>
- <imagesrc="http://192.168.1.100:8080/Hello/images/14.png"/>
- </contact>
- <contactid="15">
- <name>Roco_15</name>
- <imagesrc="http://192.168.1.100:8080/Hello/images/15.png"/>
- </contact>
- <contactid="16">
- <name>Roco_16</name>
- <imagesrc="http://192.168.1.100:8080/Hello/images/16.png"/>
- </contact>
- <contactid="17">
- <name>Roco_17</name>
- <imagesrc="http://192.168.1.100:8080/Hello/images/17.png"/>
- </contact>
- <contactid="18">
- <name>Roco_18</name>
- <imagesrc="http://192.168.1.100:8080/Hello/images/18.png"/>
- </contact>
- <contactid="19">
- <name>Roco_19</name>
- <imagesrc="http://192.168.1.100:8080/Hello/images/19.png"/>
- </contact>
- <contactid="20">
- <name>Roco_20</name>
- <imagesrc="http://192.168.1.100:8080/Hello/images/20.png"/>
- </contact>
- </contacts>
以及在images目录下放置了一些图片
step10:将项目部署到模拟器上运行效果如下图:
在SD卡中会生成缓存文件
当应用退出的时候,会将缓存文件删除
有了缓存文件,只要应用没有退出,即使联网不成功,也可以读取缓存中的图片文件
更多相关文章
- Android显示网络图片实例
- 今天开始写android的照片浏览器(一)至返回所有图片文件
- (2019年10月更新) Android 最全的底部导航栏实现方法
- Android工程内嵌资源文件的两种方法
- 解决国行安卓(Android)手机无谷歌(Google)服务的一个参考方法
- 3.NDK Android jni开发 C语言中打印log debug模式下 (相机图片美