图片异步加载

实例讲解Android中如何实现图片的异步加载功能

Android开发当中,经常会碰到图片的异步加载问题(也叫延时加载,英文叫 Lazyload)。图片的读取工作是个比较耗时的工作,如果还是从互联网读取图片资源就更加耗时。如果在主线程里处理的时间过长,就会引发著名的应用程序无响应的系统提示(ANR:Application Not Responding)。

本文通过一个名为Demo4FileManager的项目实例来讲解如何实现图片的异步加载功能。该应用的主要功能是列出SD卡下的所有目录和图片文件,用户也可以在此之上修改为读取网络图片的功能。异步加载的实现是通过AsyncTask类来实现的,首先通过一个叫FileLoadTask的类来加载当前目录下的目录或图片文件,在加载完目录或文件数据后,再去执行一个名为ImageLoadTask的类把当前目录下的图片资源解码并通知UI更新这些图片。下面我们一步一步来看看是怎么实现的。

1. 新建一个名为 FileItem.java 的类,封装了基本的目录、文件信息,并且实现Comparable接口,用于目录文件的排序。
  1. public class FileItem implements Comparable<FileItem>{ 
  2.     private String name;
  3.     private String path;
  4.     private int fileType;  //  0:文件,1:目录,2:上级目录
  5.     private Bitmap image;

  6.      // 下面是get和set方法
  7.     .......
  8.     
  9.     // 和其他文件比较
  10.     public int compareTo(FileItem another) {
  11.         return this.name.compareTo(another.getName()); 
  12.     }
  13. }
复制代码
2. 新建一个名为 FileListActivity.java 的类。在该类里实现一个名为listFile的方法,功能就是列出指定目录下的文件。我们可以看到在检查SD卡的状态为插入后,就启动一个文件加载任务。
  1. private void listFile(String path){
  2.         Log.i(TAG, "listFile()");
  3.         Log.d(TAG, "path:" + path);
  4.         
  5.         //  SD卡状态
  6.         String status = Environment.getExternalStorageState();
  7.         Log.d(TAG, "status of sdcard:" + status);
  8.         if (status.equals(Environment.MEDIA_MOUNTED)) {//mounted
  9.             task = new FileLoadTask(this, adapter);
  10.             task.execute(path);
  11.         }
  12.     }
复制代码
在onCreate方法里,加入listFile那个方法,缺省路径为 /sdcard。FileListAdapter为adapter类,这里就不详细介绍了,在附件里有。
  1.   private FileLoadTask task;
  2.     
  3.     @Override
  4.     public void onCreate(Bundle savedInstanceState) {
  5.         super.onCreate(savedInstanceState);
  6.         setContentView(R.layout.file_list);

  7.         adapter = new FileListAdapter(this);
  8.         fileList = (ListView) findViewById(R.id.fileList);
  9.         fileList.setOnItemClickListener(this); //  点击item事件
  10.         fileList.setAdapter(adapter);
  11.         
  12.         listFile(FileItem.ROOT_PATH);
  13.     }
复制代码
3. 新建一个名为 FileLoadTask.java 的类,用来异步加载指定目录下的文件或图片。
  1. public class FileLoadTask extends AsyncTask<String, FileItem, Void>{
  2.     private static final String TAG = FileLoadTask.class.getSimpleName();
  3.     private final static FolderFilter folderFilter = new FolderFilter();
  4.     private final static ImageFilter imageFilter = new ImageFilter();
  5.     
  6.     private Context context;
  7.     private FileListAdapter adapter;
  8.     private Bitmap folderIcon; 
  9.     private Bitmap fileIcon;
  10.     private ImageLoadTask task;
  11.     
  12.     // 初始化
  13.     public FileLoadTask(Context context, FileListAdapter adapter){
  14.         Log.i(TAG, "FileLoadTask()");
  15.         
  16.         this.context = context;
  17.         this.adapter = adapter;
  18.         folderIcon = BitmapFactory.decodeResource(context.getResources(), R.drawable.folder);
  19.         fileIcon = BitmapFactory.decodeResource(context.getResources(), R.drawable.file);
  20.     }
  21.     
  22.     @Override
  23.     protected void onPreExecute() {
  24.         Log.i(TAG, "onPreExecute()");

  25.         // 在执行任务前,先把adapter里的数据清空
  26.         adapter.clear();
  27.     }
  28.     
  29.     @Override
  30.     protected Void doInBackground(String... path) {
  31.         Log.i(TAG, "doInBackground()");
  32.         
  33.         File parent = new File(path[0]);
  34.         if (parent.isDirectory()) {
  35.             //设置返回按钮
  36.             if(!path[0].equals(FileItem.ROOT_PATH)){
  37.                 FileItem root = new FileItem();
  38.                 root.setName(FileItem.ROOT_NAME);
  39.                 root.setFileType(FileItem.FILE_ROOT);
  40.                 publishProgress(root);
  41.             }
  42.             
  43.             // 获取当前目录下的子目录
  44.             File[] files = parent.listFiles(folderFilter);
  45.             Arrays.sort(files);
  46.             for (int i = 0; i < files.length; i++) {
  47.                 if(isCancelled()) return null;
  48.                 
  49.                 File file = files;                    
  50.                 FileItem bean = new FileItem();
  51.                 bean.setName(file.getName());
  52.                 bean.setPath(file.getAbsolutePath());
  53.                 bean.setFileType(FileItem.FILE_DIR);
  54.                 publishProgress(bean);  //处理好一个目录,通知任务去更新UI
  55.             }
  56.             
  57.             // 获取当前目录下的图片文件
  58.             files = parent.listFiles(imageFilter);
  59.             Arrays.sort(files);
  60.             for (int i = 0; i < files.length; i++) {
  61.                 if(isCancelled()) return null;
  62.                 
  63.                 File file = files;                    
  64.                 FileItem bean = new FileItem();
  65.                 bean.setName(file.getName());
  66.                 bean.setPath(file.getAbsolutePath());
  67.                 bean.setFileType(FileItem.FILE_IMAGE);
  68.                 publishProgress(bean);  //处理好一个文件,通知任务去更新UI
  69.             }
  70.         }
  71.         return null;
  72.     }
  73.     
  74.     @Override
  75.     public void onProgressUpdate(FileItem... files) {
  76.         Log.i(TAG, "onProgressUpdate()");
  77.         if(isCancelled()) return;

  78.         //  收到要处理的类,根据目录或文件先设置缺省的图片
  79.         FileItem bean = files[0];
  80.         if(bean.getFileType() == FileItem.FILE_IMAGE){
  81.             bean.setImage(fileIcon);
  82.         }else{
  83.             bean.setImage(folderIcon);
  84.         }
  85.         //  更新数据,列表会显示对应数据
  86.         adapter.add(bean);
  87.         adapter.notifyDataSetChanged();
  88.     }
  89.     
  90.     @Override
  91.     protected void onPostExecute(Void result) {
  92.         Log.i(TAG, "onPostExecute()");
  93.         
  94.        //启动图片加载任务
  95.         if (task != null && task.getStatus() == AsyncTask.Status.RUNNING) {
  96.             task.cancel(true);
  97.         }
  98.         task = new ImageLoadTask(context, adapter);
  99.         task.execute();
  100.     }
  101. }
复制代码
4. 新建一个名为 ImageLoadTask.java 的类,用来加载图片资源。
  1. public class ImageLoadTask extends AsyncTask<Void, Void, Void>{
  2.     private static final String TAG = ImageLoadTask.class.getSimpleName();
  3.     private static int thumbnailWidth = 70;
  4.     private static int thumbnailHeight = 100;
  5.     
  6.     private FileListAdapter adapter;

  7.     // 初始化
  8.     public ImageLoadTask(Context context, FileListAdapter adapter){
  9.         Log.i(TAG, "ImageLoadTask()");
  10.         
  11.         this.adapter = adapter;
  12.     }
  13.         
  14.     @Override
  15.     protected Void doInBackground(Void... voids) {
  16.         Log.i(TAG, "doInBackground()");
  17.         
  18.         BitmapFactory.Options ptions = new BitmapFactory.Options();
  19.         options.inSampleSize = 16;

  20.        // 要处理的文件
  21.         for(int i=0; i<adapter.getCount(); i++){
  22.             FileItem bean = adapter.getItem(i);
  23.             if(bean.getFileType() == FileItem.FILE_DIR){
  24.                 continue;  //  非图片文件
  25.             }
  26.             
  27.             try {
  28.                 //  生成缩略图
  29.                 options.inJustDecodeBounds = true;
  30.                 options.outWidth = 0;
  31.                 options.outHeight = 0;
  32.                 options.inSampleSize = 1;
  33.                 
  34.                 BitmapFactory.decodeFile(bean.getPath(), options);            
  35.                 if (options.outWidth > 0 && options.outHeight > 0) {
  36.                     // Now see how much we need to scale it down.
  37.                     int widthFactor = (options.outWidth + thumbnailWidth - 1) / thumbnailWidth;
  38.                     int heightFactor = (options.outHeight + thumbnailHeight - 1) / thumbnailHeight;
  39.                     widthFactor = Math.max(widthFactor, heightFactor);
  40.                     widthFactor = Math.max(widthFactor, 1);
  41.                     
  42.                     // Now turn it into a power of two.
  43.                     if (widthFactor > 1) {
  44.                         if ((widthFactor & (widthFactor-1)) != 0) {
  45.                             while ((widthFactor & (widthFactor-1)) != 0) {
  46.                                 widthFactor &= widthFactor-1;
  47.                             }
  48.                             widthFactor <<= 1;
  49.                         }
  50.                     }
  51.                     options.inSampleSize = widthFactor;
  52.                     options.inJustDecodeBounds = false;
  53.                     Bitmap bitmap = BitmapFactory.decodeFile(bean.getPath(), options);            
  54.                     if (bitmap != null) {
  55.                         bean.setImage(bitmap); //  读取到图片资源,加入到FileItem对象中
  56.                         publishProgress();  // 通知去更新UI
  57.                     }
  58.                 }
  59.             } catch (Exception e) {
  60.                 // That's okay, guess it just wasn't a bitmap.
  61.             }
  62.         }
  63.         return null;
  64.     }
  65.     
  66.     @Override
  67.     public void onProgressUpdate(Void... voids) {
  68.         Log.i(TAG, "onProgressUpdate()");
  69.         if(isCancelled()) return;
  70.         //更新UI
  71.         adapter.notifyDataSetChanged();
  72.     }
  73. }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值