Android异步下载图片并且缓存图片到本地DEMO详解

在Android开发中我们经常有这样的需求,从服务器上下载xml或者JSON类型的数据,其中包括一些图片资源,本demo模拟了这个需求,从网络上加载XML资源,其中包括图片,我们要做的解析XML里面的数据,并且把图片缓存到本地一个cache目录里面,并且用一个自定义的Adapter去填充到LIstView,demo运行效果见下图:

通过这个demo,要学会有一下几点

1.怎么解析一个XML

2.demo中用到的缓存图片到本地一个临时目录的思想是怎样的?

3.AsyncTask类的使用,因为要去异步的加载数据,就必须开启线程,但是在开启线程的时有时候不能很好的控制线程的数量,线程数量太大的时候手机会很快被卡死 这里就采用AsynsTask类的去解决这个问题,这个类里面封装了线程池的技术,从而保证不会因开启过多的线程而消耗太多的资源

4.本demo中的Handler类的使用情况 5.自定义adapter的使用

下面是demo中的Activity。

public class MainActivity extends Activity {
 protected static final int SUCCESS_GET_CONTACT = 0;
 private ListView mListView;
 private MyContactAdapter mAdapter;
 private File cache;
 private Handler mHandler = new Handler(){
  public void handleMessage(android.os.Message msg) {
   if(msg.what == SUCCESS_GET_CONTACT){
    List<Contact> contacts = (List<Contact>) msg.obj;
    mAdapter = new MyContactAdapter(getApplicationContext(),contacts,cache);
    mListView.setAdapter(mAdapter);
   }
  };
 };
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  mListView = (ListView) findViewById(R.id.listview);
  //创建缓存目录,系统一运行就得创建缓存目录的,
  cache = new File(Environment.getExternalStorageDirectory(), "cache");
  if(!cache.exists()){
   cache.mkdirs();
  }
  //获取数据,主UI线程是不能做耗时操作的,所以启动子线程来做
  new Thread(){
   public void run() {
    ContactService service = new ContactService();
    List<Contact> contacts = null;
    try {
     contacts = service.getContactAll();
    } catch (Exception e) {
     e.printStackTrace();
    }
    //子线程通过Message对象封装信息,并且用初始化好的,
    //Handler对象的sendMessage()方法把数据发送到主线程中,从而达到更新UI主线程的目的
    Message msg = new Message();
    msg.what = SUCCESS_GET_CONTACT;
    msg.obj = contacts;
    mHandler.sendMessage(msg);
   };
  }.start();
 }
 @Override
 protected void onDestroy() {
  super.onDestroy();
  //清空缓存
  File[] files = cache.listFiles();
  for(File file :files){
   file.delete();
  }
  cache.delete();
 }
} 

Activity中,注意以下几点,

1.初始化了一个缓存目录,这个目录最好是应用开启就去创建好,为手续缓存图片做准备,在这里把数据存放在SDCard上

2.要去服务器加载数据,这个耗时操作最好是去开启线程加载数据,加载完毕后去异步的更新UI线程,利用Handler机制能很好的解决这个问题,

3.最后退出应用的时候,要删掉缓存目录和目录里面的数据,避免给手机制造很多的垃圾文件

下面就是一个Service类了,

public class ContactService {
 /*
  * 从服务器上获取数据
  */
 public List<Contact> getContactAll() throws Exception {
  List<Contact> contacts = null;
  String Parth = "http://192.168.1.103:8080/myweb/list.xml";
  URL url = new URL(Parth);
  HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  conn.setConnectTimeout(3000);
  conn.setRequestMethod("GET");
  if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
   InputStream is = conn.getInputStream();
   // 这里获取数据直接放在XmlPullParser里面解析
   contacts = xmlParser(is);
   return contacts;
  } else {
   return null;
  }
 }
 // 这里并没有下载图片下来,而是把图片的地址保存下来了
 private List<Contact> xmlParser(InputStream is) throws Exception {
  List<Contact> contacts = null;
  Contact contact = null;
  XmlPullParser parser = Xml.newPullParser();
  parser.setInput(is, "UTF-8");
  int eventType = parser.getEventType();
  while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
   switch (eventType) {
   case XmlPullParser.START_TAG:
    if (parser.getName().equals("contacts")) {
     contacts = new ArrayList<Contact>();
    } else if (parser.getName().equals("contact")) {
     contact = new Contact();
     contact.setId(Integer.valueOf(parser.getAttributeValue(0)));
    } else if (parser.getName().equals("name")) {
     contact.setName(parser.nextText());
    } else if (parser.getName().equals("image")) {
     contact.setImage(parser.getAttributeValue(0));
    }
    break;
   case XmlPullParser.END_TAG:
    if (parser.getName().equals("contact")) {
     contacts.add(contact);
    }
    break;
   }
  }
  return contacts;
 }
 /*
  * 从网络上获取图片,如果图片在本地存在的话就直接拿,如果不存在再去服务器上下载图片
  * 这里的path是图片的地址
  */
 public Uri getImageURI(String path, File cache) throws Exception {
  String name = MD5.getMD5(path) + path.substring(path.lastIndexOf("."));
  File file = new File(cache, name);
  // 如果图片存在本地缓存目录,则不去服务器下载
  if (file.exists()) {
   return Uri.fromFile(file);//Uri.fromFile(path)这个方法能得到文件的URI
  } else {
   // 从网络上获取图片
   URL url = new URL(path);
   HttpURLConnection conn = (HttpURLConnection) url.openConnection();
   conn.setConnectTimeout(5000);
   conn.setRequestMethod("GET");
   conn.setDoInput(true);
   if (conn.getResponseCode() == 200) {
    InputStream is = conn.getInputStream();
    FileOutputStream fos = new FileOutputStream(file);
    byte[] buffer = new byte[1024];
    int len = 0;
    while ((len = is.read(buffer)) != -1) {
     fos.write(buffer, 0, len);
    }
    is.close();
    fos.close();
    // 返回一个URI对象
    return Uri.fromFile(file);
   }
  }
  return null;
 }
} 

Serivce类中,注意以下几点

1.HttpURLConnection conn = (HttpURLConnection) url.openConnection();获取一个链接,从而进行通讯

2.怎么利用XxmlPullPaser类去解析XML,从而把数据封装成对象

3.getImageURI(String path, File cache) 这个方法具体实现

4.Uri.fromFile(file);这个方法能够直接返回一个Uri来

下面是自定义的Adapter类,

public class MyContactAdapter extends BaseAdapter {
 protected static final int SUCCESS_GET_IMAGE = 0;
 private Context context;
 private List<Contact> contacts;
 private File cache;
 private LayoutInflater mInflater;
 // 自己定义的构造函数
 public MyContactAdapter(Context context, List<Contact> contacts, File cache) {
  this.context = context;
  this.contacts = contacts;
  this.cache = cache;
  mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 }
 @Override
 public int getCount() {
  return contacts.size();
 }
 @Override
 public Object getItem(int position) {
  return contacts.get(position);
 }
 @Override
 public long getItemId(int position) {
  return position;
 }
 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
  // 1获取item,再得到控件
  // 2 获取数据
  // 3绑定数据到item
  View view = null;
  if (convertView != null) {
   view = convertView;
  } else {
   view = mInflater.inflate(R.layout.item, null);
  }
  ImageView iv_header = (ImageView) view.findViewById(R.id.iv_header);
  TextView tv_name = (TextView) view.findViewById(R.id.tv_name);
  Contact contact = contacts.get(position);
  // 异步的加载图片 (线程池 + Handler ) ---> AsyncTask
  asyncloadImage(iv_header, contact.image);
  tv_name.setText(contact.name);
  return view;
 }
 private void asyncloadImage(ImageView iv_header, String path) {
  ContactService service = new ContactService();
  AsyncImageTask task = new AsyncImageTask(service, iv_header);
  task.execute(path);
 }
 private final class AsyncImageTask extends AsyncTask<String, Integer, Uri> {
  private ContactService service;
  private ImageView iv_header;
  public AsyncImageTask(ContactService service, ImageView iv_header) {
   this.service = service;
   this.iv_header = iv_header;
  }
  // 后台运行的子线程子线程
  @Override
  protected Uri doInBackground(String... params) {
   try {
    return service.getImageURI(params[0], cache);
   } catch (Exception e) {
    e.printStackTrace();
   }
   return null;
  }
  // 这个放在在ui线程中执行
  @Override
  protected void onPostExecute(Uri result) {
   super.onPostExecute(result);
   // 完成图片的绑定
   if (iv_header != null && result != null) {
    iv_header.setImageURI(result);
   }
  }
 }
 /**
  * 采用普通方式异步的加载图片
  */
 /*private void asyncloadImage(final ImageView iv_header, final String path) {
  final Handler mHandler = new Handler() {
   @Override
   public void handleMessage(Message msg) {
    super.handleMessage(msg);
    if (msg.what == SUCCESS_GET_IMAGE) {
     Uri uri = (Uri) msg.obj;
     if (iv_header != null && uri != null) {
      iv_header.setImageURI(uri);
     }
    }
   }
  };
  // 子线程,开启子线程去下载或者去缓存目录找图片,并且返回图片在缓存目录的地址
  Runnable runnable = new Runnable() {
   @Override
   public void run() {
    ContactService service = new ContactService();
    try {
     //这个URI是图片下载到本地后的缓存目录中的URI
     Uri uri = service.getImageURI(path, cache);
     Message msg = new Message();
     msg.what = SUCCESS_GET_IMAGE;
     msg.obj = uri;
     mHandler.sendMessage(msg);
    } catch (Exception e) {
     e.printStackTrace();
    }
   }
  };
  new Thread(runnable).start();
 }*/
}

自定义Adapter中,我们要注意 AsyncImageTask这个类继承了AsyncTask类,AsyncTask是Android中常用来做异步任务的类,对线程池进行了封装,详细分析稍后再贴出一篇Blog。

下面是我们从服务器上获取并且解析的Xml文件

<?xml version="1.0" encoding="UTF-8"?>
<contacts>
 <contact id="1">
  <name>张飞</name>
  <image src="http://192.168.1.103:8080/mymyweb/images/1.gif"/>
 </contact>
 <contact id="2">
  <name>博文</name>
  <image src="http://192.168.1.103:8080/myweb/images/2.gif"/>
 </contact>
 <contact id="3">
  <name>张天佑</name>
  <image src="http://192.168.1.103:8080/myweb/images/3.gif"/>
 </contact>
 <contact id="4">
  <name>松德</name>
  <image src="http://192.168.1.103:8080/myweb/images/4.gif"/>
 </contact>
 <contact id="5">
  <name>赵薇</name>
  <image src="http://192.168.1.103:8080/myweb/images/5.gif"/>
 </contact>
 <contact id="6">
  <name>李静</name>
  <image src="http://192.168.1.103:8080/myweb/images/6.gif"/>
 </contact>
 <contact id="7">
  <name>李明</name>
  <image src="http://192.168.1.103:8080/myweb/images/7.gif"/>
 </contact>
 <contact id="8">
  <name>黎明</name>
  <image src="http://192.168.1.103:8080/myweb/images/8.gif"/>
 </contact>
 <contact id="9">
  <name>秦桧</name>
  <image src="http://192.168.1.103:8080/myweb/images/9.gif"/>
 </contact>
 <contact id="10">
  <name>朱德</name>
  <image src="http://192.168.1.103:8080/myweb/images/10.gif"/>
 </contact>
 <contact id="11">
  <name>冯巩</name>
  <image src="http://192.168.1.103:8080/myweb/images/11.gif"/>
 </contact>
 <contact id="12">
  <name>dylan</name>
  <image src="http://192.168.1.103:8080/myweb/images/12.gif"/>
 </contact>
 <contact id="13">
  <name>黄单</name>
  <image src="http://192.168.1.103:8080/myweb/images/13.gif"/>
 </contact>
 <contact id="14">
  <name>含蕊</name>
  <image src="http://192.168.1.103:8080/myweb/images/14.gif"/>
 </contact>
 <contact id="15">
  <name>欣琪</name>
  <image src="http://192.168.1.103:8080/myweb/images/15.jpg"/>
 </contact>
 <contact id="16">
  <name>李忠华</name>
  <image src="http://192.168.1.103:8080/myweb/images/16.jpg"/>
 </contact>
 <contact id="17">
  <name>方产员</name>
  <image src="http://192.168.1.103:8080/myweb/images/17.jpg"/>
 </contact>
 <contact id="18">
  <name>张光</name>
  <image src="http://192.168.1.103:8080/myweb/images/18.jpg"/>
 </contact>
</contacts>

本demo中为了安全起见,还对下载下来的图片的文件名进行了MD5加密,下面是MD5加密的代码,

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

以上省略了Contact.java这个domain类,通过这个demo,可以看出Android中会经常需要进行异步任务的处理,所以我们会常常用到自己手动开启线程,handler机制,或者AsyncTask类等手段来保证应用的性能。

以上所述是小编给大家介绍的Android异步下载图片并且缓存图片到本地DEMO详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Android实现多线程下载图片的方法

    很多时候我们需要在Android设备上下载远程服务器上的图片进行显示,今天整理出两种比较好的方法来实现远程图片的下载. 方法一.直接通过Android提供的Http类访问远程服务器,这里AndroidHttpClient是SDK 2.2中新出的方法,API Level为8,大家需要注意下,静态访问可以直接调用,如果SDK版本较低可以考虑Apache的Http库,当然HttpURLConnection 或URLConnection也可以. static Bitmap downloadBitmapB

  • Android 实现单线程轮循机制批量下载图片

    Android 实现单线程轮循机制批量下载图片 listview 在为item 添加从网上下载下来的图片时, 如果每次都整合一个item时都需要new一个Thread去下载图片,listview长时间滑动时会产生大量线程. 用单线程轮循机制则可以解决这个问题 步骤如下: 1.需要一个任务集合 class imageViewTask{ String path; Bitmap bitmap; int position; } // 任务集合 private List<imageViewTask> i

  • Android带进度条的下载图片示例(AsyncTask异步任务)

    为什么要用异步任务? 在Android中只有在主线程才能对ui进行更新操作,而其它线程不能直接对ui进行操作 android本身是一个多线程的操作系统,我们不能把所有的操作都放在主线程中操作 ,比如一些耗时操作.如果放在主线程中 会造成阻塞 而当阻塞事件过长时 系统会抛出anr异常.所以我们要使用异步任务.android为我们提供了一个封装好的组件asynctask. AsyncTask可以在子线程中更新ui,封装简化了异步操作.适用于简单的异步处理.如果多个后台任务时就要使用Handler了

  • Android使用okHttp(get方式)下载图片

    一.首先下载Jar包 https://github.com/square/okhttp 如果使用android studio只需要加入依赖compile 'com.squareup.okhttp3:okhttp:3.2.0' 二.下载一张图片并显示 使用的是hanlder的方式 package com.liunan.okhttpdemo2; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import

  • Android编程实现下载图片及在手机中展示的方法

    本文实例讲述了Android编程实现下载图片及在手机中展示的方法.分享给大家供大家参考,具体如下: 在项目开发中从互联网上下载图片是经常用到的功能,再次总结一下 1.普通的下载方式 布局文件: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android

  • Android使用AsyncTask下载图片并显示进度条功能

    在Android中实现异步任务机制有两种方式,Handler和AsyncTask.这篇文章给大家介绍Android使用AsyncTask下载图片并显示进度条功能. AsyncTask下载图片并显示下载进度,异步类AsyncTask配合进度条,简练! public class AsyncTaskActivity2 extends Activity { private Button btnDown;//图片框 private ImageView ivImage;//图片URL private sta

  • Android中使用HttpURLConnection实现GET POST JSON数据与下载图片

    Android6.0中把Apache HTTP Client所有的包与类都标记为deprecated不再建议使用所有跟HTTP相关的数据请求与提交操作都通过HttpURLConnection类实现,现实是很多Android开发者一直都Apache HTTP Client来做andoird客户端与后台HTTP接口数据交互,小编刚刚用HttpURLConnection做了一个android的APP,不小心踩到了几个坑,总结下最常用的就通过HttpURLConnection来POST提交JSON数据与

  • Android异步下载图片并且缓存图片到本地DEMO详解

    在Android开发中我们经常有这样的需求,从服务器上下载xml或者JSON类型的数据,其中包括一些图片资源,本demo模拟了这个需求,从网络上加载XML资源,其中包括图片,我们要做的解析XML里面的数据,并且把图片缓存到本地一个cache目录里面,并且用一个自定义的Adapter去填充到LIstView,demo运行效果见下图: 通过这个demo,要学会有一下几点 1.怎么解析一个XML 2.demo中用到的缓存图片到本地一个临时目录的思想是怎样的? 3.AsyncTask类的使用,因为要去异

  • Android异步加载数据和图片的保存思路详解

    把从网络获取的图片数据保存在SD卡上, 先把权限都加上 网络权限 android.permission.INTERNET SD卡读写权限 android.permission.MOUNT_UNMOUNT_FILESYSTEMS android.permission.WRITE_EXTERNAL_STORAGE 总体布局 写界面,使用ListView,创建条目的布局文件,水平摆放的ImageView TextView 在activity中获取到ListView对象,调用setAdapter()方法

  • Android 图片存入系统相册更新显示实例详解

    Android 图片存入系统相册更新显示实例详解 在开发android的过程中,我们避免不了可能会涉及到做一个自定义相册或则会去本地创建一个文件夹来存储我们需要的图片.拿相册来说,比如我们创建一个test的文件夹,拍完一张照片后存储到这个指定的test文件夹里,然后在相册里面显示出来,就像微信的效果一样.拍完即可立即显示.但是,在实际开发过程中我们保存完一张图片后并不能立即更新显示出来这个图片,需要我们重启手机才能在系统相册中显示出来. 这里先提供一个插入系统图库的方法: MediaStore.

  • Android 通过webservice上传多张图片到指定服务器详解

    Android 通过webservice上传多张图片到指定服务器详解 当你浏览这个的时候相信你对webservice的基本应用已经有一定的了解了,若是还没有明白的小伙伴,可以看我前面写的文章点击打开链接,这几天在开发一款app,需要上传图片到指定服务器吧,但是我刚开始以为在网上面应该有这样的好文章的吧,结果我在网络上找了好多代码,在传递图片的过程中,遇到各种bug,真是国人的东西就是喜欢复制别人的,自己不动手检验一下代码的正确性,哎,我也是无语了,然后我决定花点时间来填补一下这个空缺,写了这一片

  • Android屏幕锁屏弹窗的正确姿势DEMO详解

    在上篇文章给大家介绍了Android程序开发仿新版QQ锁屏下弹窗功能.今天通过本文给大家分享android锁屏弹窗的正确姿势. 最近在做一个关于屏幕锁屏悬浮窗的功能,于是在网上搜索了很多安卓屏幕锁屏的相关资料,鉴于网上的资料比较零碎,所以我在这里进行整理总结.本文将从以下两点对屏幕锁屏进行解析: 1. 如何监听系统屏幕锁屏 2. 如何在锁屏界面弹出悬浮窗 如何监听系统屏幕锁屏 经过总结,监听系统的锁屏可以通过以下两种方式: 1) 代码直接判定 2) 接收广播 1) 代码直接判定 代码判断方式,也

  • Android 拍照并对照片进行裁剪和压缩实例详解

    Android 拍照并对照片进行裁剪和压缩实例详解 本文主要介绍 Android 调用摄像头拍照并对照片进行裁剪和压缩,文中给出了主要步骤和关键代码. 调用摄像头拍照,对拍摄照片进行裁剪,代码如下. /** * 调用摄像头拍照,对拍摄照片进行裁剪 */ private void showCameraAction() { // 跳转到系统照相机 Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (camera

  • Android自定义进度条的圆角横向进度条实例详解

    1.本文将向你介绍自定义进度条的写法,比较简单,但还是有些知识点是需要注意的: invalidate()方法 RectF方法的应用 onMeasure方法的应用 2.原理 画3层圆角矩形,底层为黑色,第二层为灰色,最上一层为进度条颜色,示例图如下: 3.效果图   实现圆角进度条还有很多其他方法,比如在Progress控件里填充圆角图片,通过拉伸图片来达到预想的效果,虽然听起来很简单,但实现起来还是有些麻烦的. 4.解说方法 (1)invalidate()方法 invalidate()是用来刷新

  • Android开发之保存图片到相册的三种方法详解

    目录 方法一 方法二 方法三 有三种方法如下:三个方法都需要动态申请读写权限否则保存图片到相册也会失败 方法一 /** * 保存bitmap到本地 * * @param bitmap Bitmap */ public static void saveBitmap(Bitmap bitmap, String path) { String savePath; File filePic; if (Environment.getExternalStorageState().equals(Environm

  • Android性能优化之RecyclerView分页加载组件功能详解

    目录 引言 1 分页加载组件 1.1 功能定制 1.2 手写分页列表 1.3 生命周期管理 2 github 引言 在Android应用中,列表有着举足轻重的地位,几乎所有的应用都有列表的身影,但是对于列表的交互体验一直是一个大问题.在性能比较好的设备上,列表滑动几乎看不出任何卡顿,但是放在低端机上,卡顿会比较明显,而且列表中经常会伴随图片的加载,卡顿会更加严重,因此本章从手写分页加载组件入手,并对列表卡顿做出对应的优化 1 分页加载组件 为什么要分页加载,通常列表数据存储在服务端会超过100条

  • Android中用Bmob实现短信验证码功能的方法详解

    这篇文章主要介绍发送验证码和校验验证码的功能,用到一个第三方平台Bmob,那Bmob是什么呢?Bmob可以开发一个云存储的移动应用软件,他提供了大量的标准的API接口,根据需要接入相关服务,开发者可以更加专注于应用的开发,让产品交付更快速,验证码功能就是其中一个. 一.跟其他第三方一样,我们开发之前要做一些准备工作. 1.首先,去官网注册一个帐号:http://www.bmob.cn/: 2.然后就可以创建应用了:具体怎么做Bmob说得很清楚了(官方操作介绍),如果你不想看,我简单说一下:点击右

随机推荐