android 下的网络图片加载

简介:

Android图片的异步加载,主要原理:

加载图片时先查看缓存中时候存在该图片,如果存在则返回该图片,否则先加载载一个默认的占位图片,同时创建一个通过网络获取图片的任务并添加,任务完成后放松消息给主线程更新界面。

废话少说,先贴上代码:


1 package com.wangge.uumao.http;  
  2   
  3 import java.lang.ref.SoftReference;  
  4 import java.util.ArrayList;  
  5 import java.util.HashMap;  
  6 import java.util.List;  
  7 import java.util.Map;  
  8   
  9 import android.graphics.Bitmap;  
 10 import android.os.Handler;  
 11 import android.os.Message;  
 12 import android.util.Log;  
 13 import android.widget.ImageView;  
 14   
 15 import com.wangge.uumao.util.PicUtil;  
 16   
 17 public class AsynImageLoader {  
 18     private static final String TAG = "AsynImageLoader";  
 19     // 缓存下载过的图片的Map   
 20     private Map<String, SoftReference<Bitmap>> caches;  
 21     // 任务队列   
 22     private List<Task> taskQueue;  
 23     private boolean isRunning = false;  
 24       
 25     public AsynImageLoader(){  
 26         // 初始化变量   
 27         caches = new HashMap<String, SoftReference<Bitmap>>();  
 28         taskQueue = new ArrayList<AsynImageLoader.Task>();  
 29         // 启动图片下载线程   
 30         isRunning = true;  
 31         new Thread(runnable).start();  
 32     }  
 33       
 34     /** 
 35      *  
 36      * @param imageView 需要延迟加载图片的对象 
 37      * @param url 图片的URL地址 
 38      * @param resId 图片加载过程中显示的图片资源 
 39      */  
 40     public void showImageAsyn(ImageView imageView, String url, int resId){  
 41         imageView.setTag(url);  
 42         Bitmap bitmap = loadImageAsyn(url, getImageCallback(imageView, resId));  
 43           
 44         if(bitmap == null){  
 45             imageView.setImageResource(resId);  
 46         }else{  
 47             imageView.setImageBitmap(bitmap);  
 48         }  
 49     }  
 50       
 51     public Bitmap loadImageAsyn(String path, ImageCallback callback){  
 52         // 判断缓存中是否已经存在该图片   
 53         if(caches.containsKey(path)){  
 54             // 取出软引用   
 55             SoftReference<Bitmap> rf = caches.get(path);  
 56             // 通过软引用,获取图片   
 57             Bitmap bitmap = rf.get();  
 58             // 如果该图片已经被释放,则将该path对应的键从Map中移除掉   
 59             if(bitmap == null){  
 60                 caches.remove(path);  
 61             }else{  
 62                 // 如果图片未被释放,直接返回该图片   
 63                 Log.i(TAG, "return image in cache" + path);  
 64                 return bitmap;  
 65             }  
 66         }else{  
 67             // 如果缓存中不常在该图片,则创建图片下载任务   
 68             Task task = new Task();  
 69             task.path = path;  
 70             task.callback = callback;  
 71             Log.i(TAG, "new Task ," + path);  
 72             if(!taskQueue.contains(task)){  
 73                 taskQueue.add(task);  
 74                 // 唤醒任务下载队列   
 75                 synchronized (runnable) {  
 76                     runnable.notify();  
 77                 }  
 78             }  
 79         }  
 80           
 81         // 缓存中没有图片则返回null   
 82         return null;  
 83     }  
 84       
 85     /** 
 86      *  
 87      * @param imageView  
 88      * @param resId 图片加载完成前显示的图片资源ID 
 89      * @return 
 90      */  
 91     private ImageCallback getImageCallback(final ImageView imageView, final int resId){  
 92         return new ImageCallback() {  
 93               
 94             @Override  
 95             public void loadImage(String path, Bitmap bitmap) {  
 96                 if(path.equals(imageView.getTag().toString())){  
 97                     imageView.setImageBitmap(bitmap);  
 98                 }else{  
 99                     imageView.setImageResource(resId);  
100                 }  
101             }  
102         };  
103     }  
104       
105     private Handler handler = new Handler(){  
106   
107         @Override  
108         public void handleMessage(Message msg) {  
109             // 子线程中返回的下载完成的任务   
110             Task task = (Task)msg.obj;  
111             // 调用callback对象的loadImage方法,并将图片路径和图片回传给adapter   
112             task.callback.loadImage(task.path, task.bitmap);  
113         }  
114           
115     };  
116       
117     private Runnable runnable = new Runnable() {  
118           
119         @Override  
120         public void run() {  
121             while(isRunning){  
122                 // 当队列中还有未处理的任务时,执行下载任务   
123                 while(taskQueue.size() > 0){  
124                     // 获取第一个任务,并将之从任务队列中删除   
125                     Task task = taskQueue.remove(0);  
126                     // 将下载的图片添加到缓存   
127                     task.bitmap = PicUtil.getbitmap(task.path);  
128                     caches.put(task.path, new SoftReference<Bitmap>(task.bitmap));  
129                     if(handler != null){  
130                         // 创建消息对象,并将完成的任务添加到消息对象中   
131                         Message msg = handler.obtainMessage();  
132                         msg.obj = task;  
133                         // 发送消息回主线程   
134                         handler.sendMessage(msg);  
135                     }  
136                 }  
137                   
138                 //如果队列为空,则令线程等待   
139                 synchronized (this) {  
140                     try {  
141                         this.wait();  
142                     } catch (InterruptedException e) {  
143                         e.printStackTrace();  
144                     }  
145                 }  
146             }  
147         }  
148     };  
149       
150     //回调接口   
151     public interface ImageCallback{  
152         void loadImage(String path, Bitmap bitmap);  
153     }  
154       
155     class Task{  
156         // 下载任务的下载路径   
157         String path;  
158         // 下载的图片   
159         Bitmap bitmap;  
160         // 回调对象   
161         ImageCallback callback;  
162           
163         @Override  
164         public boolean equals(Object o) {  
165             Task task = (Task)o;  
166             return task.path.equals(path);  
167         }  
168     }  
169 }  

源代码的17-24行是一些变量,数组的声明。


1    private static final String TAG = "AsynImageLoader";  
2     // 缓存下载过的图片的Map   
3     private Map<String, SoftReference<Bitmap>> caches;  
4     // 任务队列   
5     private List<Task> taskQueue;  
6     private boolean isRunning = false;  
7       

值得一提的是的这里的下载过的图片的mAp是软应用了,为什么了。我们查阅资料以后得知:
如果一个对象只具有软引用,那就类似于可有可物的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只 要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。 软引用可以和一个引用队列(ReferenceQueue)联 合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

 由于图片是大对象了,确保没有足够的缓存以后,java虚拟机能够将其回收。

代码的25-33行做了一件事,来初始化变量。


1  public AsynImageLoader(){  
2         // 初始化变量   
3         caches = new HashMap<String, SoftReference<Bitmap>>();  
4         taskQueue = new ArrayList<AsynImageLoader.Task>();  
5         // 启动图片下载线程   
6         isRunning = true;  
7         new Thread(runnable).start();  
8     }  

并且启动图片下载线程。
40行-50行主要是用来启动异步线程来展示图片。


public void showImageAsyn(ImageView imageView, String url, int resId){  
        imageView.setTag(url);  
        Bitmap bitmap = loadImageAsyn(url, getImageCallback(imageView, resId));  
          
        if(bitmap == null){  
            imageView.setImageResource(resId);  
        }else{  
            imageView.setImageBitmap(bitmap);  
        }  
    }  

这个方法,主要调用了本段源代码,最核心的方法loadImageAsyn方法。


  public Bitmap loadImageAsyn(String path, ImageCallback callback){  
        // 判断缓存中是否已经存在该图片   
        if(caches.containsKey(path)){  
            // 取出软引用   
            SoftReference<Bitmap> rf = caches.get(path);  
            // 通过软引用,获取图片   
            Bitmap bitmap = rf.get();  
            // 如果该图片已经被释放,则将该path对应的键从Map中移除掉   
            if(bitmap == null){  
                caches.remove(path);  
            }else{  
                // 如果图片未被释放,直接返回该图片   
                Log.i(TAG, "return image in cache" + path);  
                return bitmap;  
            }  
        }else{  
            // 如果缓存中不常在该图片,则创建图片下载任务   
            Task task = new Task();  
            task.path = path;  
            task.callback = callback;  
            Log.i(TAG, "new Task ," + path);  
            if(!taskQueue.contains(task)){  
                taskQueue.add(task);  
                // 唤醒任务下载队列   
                synchronized (runnable) {  
                    runnable.notify();  
                }  
            }  
        }  
          
        // 缓存中没有图片则返回null   
        return null;  
    }  

 首先判断缓存池中是否包含了这个图片,如果有这个图片,就从缓存中取得这个图片,否则的话,就从网络段来请求。这就是本方法的作用。

而runnable是从网络直接下载图片的方法。


private Runnable runnable = new Runnable() {  
118.          
119.        @Override  
120.        public void run() {  
121.            while(isRunning){  
122.                // 当队列中还有未处理的任务时,执行下载任务   
123.                while(taskQueue.size() > 0){  
124.                    // 获取第一个任务,并将之从任务队列中删除   
125.                    Task task = taskQueue.remove(0);  
126.                    // 将下载的图片添加到缓存   
127.                    task.bitmap = PicUtil.getbitmap(task.path);  
128.                    caches.put(task.path, new SoftReference<Bitmap>(task.bitmap));  
129.                    if(handler != null){  
130.                        // 创建消息对象,并将完成的任务添加到消息对象中   
131.                        Message msg = handler.obtainMessage();  
132.                        msg.obj = task;  
133.                        // 发送消息回主线程   
134.                        handler.sendMessage(msg);  
135.                    }  
136.                }  
137.                  
138.                //如果队列为空,则令线程等待   
139.                synchronized (this) {  
140.                    try {  
141.                        this.wait();  
142.                    } catch (InterruptedException e) {  
143.                        e.printStackTrace();  
144.                    }  
145.                }  
146.            }  
147.        }  
148.    };  

上述的代码告诉我们这样一个意思,通过一个消息的队列来下载图片,如果没有此线程的话,就令线程等待。

这就实现了android异步加载图片的应用。


目录
相关文章
|
30天前
|
数据库 Android开发 开发者
构建高效Android应用:采用Kotlin协程优化网络请求处理
【2月更文挑战第30天】 在移动应用开发领域,网络请求的处理是影响用户体验的关键环节。针对Android平台,利用Kotlin协程能够极大提升异步任务处理的效率和简洁性。本文将探讨如何通过Kotlin协程优化Android应用中的网络请求处理流程,包括协程的基本概念、网络请求的异步执行以及错误处理等方面,旨在帮助开发者构建更加流畅和响应迅速的Android应用。
|
3月前
|
安全 API Android开发
Android网络和数据交互: 解释Retrofit库的作用。
Android网络和数据交互: 解释Retrofit库的作用。
38 0
|
3月前
|
安全 网络协议 API
Android网络和数据交互: 什么是HTTP和HTTPS?在Android中如何进行网络请求?
Android网络和数据交互: 什么是HTTP和HTTPS?在Android中如何进行网络请求?
30 0
|
3月前
|
Android开发 开发者
Android网络和数据交互: 请解释Android中的AsyncTask的作用。
Android网络和数据交互: 请解释Android中的AsyncTask的作用。
21 0
|
4天前
|
Android开发 开发者
Android网络和数据交互: 请解释Android中的AsyncTask的作用。
Android&#39;s AsyncTask simplifies asynchronous tasks for brief background work, bridging UI and worker threads. It involves execute() for starting tasks, doInBackground() for background execution, publishProgress() for progress updates, and onPostExecute() for returning results to the main thread.
5 0
|
4天前
|
网络协议 安全 API
Android网络和数据交互: 什么是HTTP和HTTPS?在Android中如何进行网络请求?
HTTP和HTTPS是网络数据传输协议,HTTP基于TCP/IP,简单快速,HTTPS则是加密的HTTP,确保数据安全。在Android中,过去常用HttpURLConnection和HttpClient,但HttpClient自Android 6.0起被移除。现在推荐使用支持TLS、流式上传下载、超时配置等特性的HttpsURLConnection进行网络请求。
5 0
|
3月前
|
JSON Java Android开发
Android网络和数据交互: 请解释Android中的JSON解析库,如Gson。
Android网络和数据交互: 请解释Android中的JSON解析库,如Gson。
24 0
|
4月前
|
API Android开发
[Android]图片加载库Glide
[Android]图片加载库Glide
54 0
|
4月前
|
XML JSON Android开发
[Android]网络框架之Retrofit(kotlin)
[Android]网络框架之Retrofit(kotlin)
54 0
|
22天前
|
Java Android开发
Android 开发获取通知栏权限时会出现两个应用图标
Android 开发获取通知栏权限时会出现两个应用图标
12 0

热门文章

最新文章