好多应用,像我们公司的《乘友》还有其他的《飞鸽》《陌陌》《啪啪》这些,几乎每一款应用都需要加载网络图片,那ToYueXinShangWan,这是比须熟练掌握的一个点,下面开始学习:

一、最简单加载网络图片

从网络上取图片数据,显示在应用中,简单不赘述:



1.       try {  
2. new URL(path); //path图片的网络地址  
3.     HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();  
4. if(httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK){  
5.         Bitmap bitmap  = BitmapFactory.decodeStream(httpURLConnection.getInputStream());  
6. //加载到ImageView上  
7. "加载网络图片完成");  
8. else{  
9. "加载网络图片失败");  
10.     }  
11. } catch (IOException e) {  
12.     e.printStackTrace();  
13. }


android 将uri加载到imageview中_System


二、轻量级异步加载图片

不会有人用第一种方法加载,连接网络和从网络取数据,花费部分时间,阻碍主线程,影响UI效果!

解决方案是:异步加载。先给ImageView设置一张图片,在异步任务中取数据,当从网络中取数据中和取数据失败时,就一直显示原来图片,当完成取数据时则再把新图片加载到ImageView上。

根据上面思路,就可以直接动手写了,为了便于代码复用,将加载图片写在一个工具类Utils中:



1. package com.lizhen.loadimage;  
2.   
3. import java.io.IOException;  
4. import java.io.InputStream;  
5. import java.net.HttpURLConnection;  
6. import java.net.URL;  
7.   
8. import android.graphics.Bitmap;  
9. import android.graphics.BitmapFactory;  
10. import android.os.Handler;  
11. import android.os.Message;  
12.   
13. public class Utils {  
14. public static void onLoadImage(final URL bitmapUrl,final OnLoadImageListener onLoadImageListener){  
15. final Handler handler = new Handler(){  
16. public void handleMessage(Message msg){  
17. null);  
18.             }  
19.     };  
20. new Thread(new Runnable(){  
21.   
22. @Override  
23. public void run() {  
24. // TODO Auto-generated method stub  
25.                 URL imageUrl = bitmapUrl;  
26. try {  
27.                     HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();  
28.                     InputStream inputStream = conn.getInputStream();  
29.                     Bitmap bitmap = BitmapFactory.decodeStream(inputStream);  
30. new Message();  
31.                     msg.obj = bitmap;  
32.                     handler.sendMessage(msg);  
33. catch (IOException e) {  
34. // TODO Auto-generated catch block  
35.                     e.printStackTrace();  
36.                 }  
37.             }  
38.               
39.         }).start();  
40.   
41.     }  
42. public interface OnLoadImageListener{  
43. public void OnLoadImage(Bitmap bitmap,String bitmapPath);  
44.     }  
45. }


然后在需要加载图片的地方调用调用onLoadImage()方法即可,在接口OnLoadImageListener的回调方法OnLoadImage()中,如:





1.   Utils.onLoadImage(url, new OnLoadImageListener() {  
2. @Override  
3. public void OnLoadImage(Bitmap bitmap, String bitmapPath) {  
4. // TODO Auto-generated method stub  
5. if(bitmap!=null){  
6.             imageview.setImageBitmap(bitmap);  
7.         }  
8.     }  
9. });


wangluo jiazai zhong -->

android 将uri加载到imageview中_java_02

读取完网络数据后,加载图片效果---->

android 将uri加载到imageview中_System


三、第二种方法的弊端是,当有大量图片需要加载时,会启动很多线程,避免出现这种情况的方法是,定义线程个数,当线程数达到最多时,不再开启,直到有一个线程结束,再开启一个线程;这种做法相当于

引入ExecutorService接口,于是代码可以优化如下:

       在主线程中加入:private ExecutorService executorService = Executors.newFixedThreadPool(5); 

在相应位置修改代码如下:



1. executorService.submit(new Runnable(){  
2.   
3. @Override  
4. public void run() {  
5. // TODO Auto-generated method stub  
6.             URL imageUrl = bitmapUrl;  
7. try {  
8. "线程被调用了。");   
9.                 HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();  
10.                 InputStream inputStream = conn.getInputStream();  
11.                 Bitmap bitmap = BitmapFactory.decodeStream(inputStream);  
12. new Message();  
13.                 msg.obj = bitmap;  
14.                 handler.sendMessage(msg);  
15. catch (IOException e) {  
16. // TODO Auto-generated catch block  
17.                 e.printStackTrace();  
18.             }  
19. "线程结束。");   
20.         }  
21.     });


线程池大小为3,运行5个线程,我的输出结果为:


android 将uri加载到imageview中_缓存_04

这里有关线程池的概念用法写在另一篇文章里!



四、关于方法二的改进,考虑到效率问题,可以引入缓存机制,把图片保留在本地,只需在线程run方法最后加上如下代码:



1. //缓存  
2. if(Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)){  
3. "存在sd卡");  
4. new File(Environment.getExternalStorageDirectory()+"/cacheFile");  
5.                         System.out.println(cacheFile.getPath());  
6. if(!cacheFile.exists())  
7.                             cacheFile.mkdir();  
8.                         System.out.println(cacheFile.exists());  
9. new File(cacheFile.getPath()+"/netwrok.png");  
10. new FileOutputStream(imageCache);  
11. new BufferedOutputStream(fos);    
12. 80, bos);     
13.                         bos.flush();     
14.                         bos.close();     
15.                     }


另一种把图片缓存在内存中使用如下步骤:

public Map<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>();

2、如果有缓存则读取缓存中数据,如果没有,则从网络获取数据;

//如果缓存过就从缓存中取出数据
         if (imageCache.containsKey(imageUrl)) {
             SoftReference<Drawable> softReference = imageCache.get(imageUrl);
             if (softReference.get() != null) {
                 return softReference.get();//得到缓存中的Drawable
             }
         }

3、在网络获取数据时,不要忘记添加imageCache信息

imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));

注意:SoftReference<Drawable>就是用来处理解决大量图片下载内存溢出的问题的,还有Bitmap与Drawable之间的转换,在其他文章中将做总结!

2012 /11/18 1:26 太晚了,没想这问题会花费这么长时间;