一、最简单加载网络图片
从网络上取图片数据,显示在应用中,简单不赘述:
- try {
- URL url = new URL(path); //path图片的网络地址
- HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
- if(httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK){
- Bitmap bitmap = BitmapFactory.decodeStream(httpURLConnection.getInputStream());
- imageview.setImageBitmap(bitmap);//加载到ImageView上
- System.out.println("加载网络图片完成");
- }else{
- System.out.println("加载网络图片失败");
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
二、轻量级异步加载图片
不会有人用第一种方法加载,连接网络和从网络取数据,花费部分时间,阻碍主线程,影响UI效果!
解决方案是:异步加载。先给ImageView设置一张图片,在异步任务中取数据,当从网络中取数据中和取数据失败时,就一直显示原来图片,当完成取数据时则再把新图片加载到ImageView上。
根据上面思路,就可以直接动手写了,为了便于代码复用,将加载图片写在一个工具类Utils中:
- package com.lizhen.loadimage;
- import java.io.IOException;
- import java.io.InputStream;
- import java.net.HttpURLConnection;
- import java.net.URL;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.os.Handler;
- import android.os.Message;
- public class Utils {
- public static void onLoadImage(final URL bitmapUrl,final OnLoadImageListener onLoadImageListener){
- final Handler handler = new Handler(){
- public void handleMessage(Message msg){
- onLoadImageListener.OnLoadImage((Bitmap) msg.obj, null);
- }
- };
- new Thread(new Runnable(){
- @Override
- public void run() {
- // TODO Auto-generated method stub
- URL imageUrl = bitmapUrl;
- try {
- HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
- InputStream inputStream = conn.getInputStream();
- Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
- Message msg = new Message();
- msg.obj = bitmap;
- handler.sendMessage(msg);
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }).start();
- }
- public interface OnLoadImageListener{
- public void OnLoadImage(Bitmap bitmap,String bitmapPath);
- }
- }
- Utils.onLoadImage(url, new OnLoadImageListener() {
- @Override
- public void OnLoadImage(Bitmap bitmap, String bitmapPath) {
- // TODO Auto-generated method stub
- if(bitmap!=null){
- imageview.setImageBitmap(bitmap);
- }
- }
- });
三、第二种方法的弊端是,当有大量图片需要加载时,会启动很多线程,避免出现这种情况的方法是,定义线程个数,当线程数达到最多时,不再开启,直到有一个线程结束,再开启一个线程;这种做法相当于
引入ExecutorService接口,于是代码可以优化如下:
在主线程中加入:private ExecutorService executorService = Executors.newFixedThreadPool(5);
在相应位置修改代码如下:
- executorService.submit(new Runnable(){
- @Override
- public void run() {
- // TODO Auto-generated method stub
- URL imageUrl = bitmapUrl;
- try {
- System.out.println(Thread.currentThread().getName() + "线程被调用了。");
- HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
- InputStream inputStream = conn.getInputStream();
- Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
- Message msg = new Message();
- msg.obj = bitmap;
- handler.sendMessage(msg);
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- System.out.println(Thread.currentThread().getName() + "线程结束。");
- }
- });
线程池大小为3,运行5个线程,我的输出结果为:
这里有关线程池的概念用法写在另一篇文章里!
四、关于方法二的改进,考虑到效率问题,可以引入缓存机制,把图片保留在本地,只需在线程run方法最后加上如下代码:
- //缓存
- if(Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)){
- System.out.println("存在sd卡");
- File cacheFile = new File(Environment.getExternalStorageDirectory()+"/cacheFile");
- System.out.println(cacheFile.getPath());
- if(!cacheFile.exists())
- cacheFile.mkdir();
- System.out.println(cacheFile.exists());
- File imageCache = new File(cacheFile.getPath()+"/netwrok.png");
- FileOutputStream fos = new FileOutputStream(imageCache);
- BufferedOutputStream bos = new BufferedOutputStream(fos);
- bitmap.compress(Bitmap.CompressFormat.PNG, 80, bos);
- bos.flush();
- bos.close();
- }
另一种把图片缓存在内存中使用如下步骤:
1、主线程 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之间的转换,在其他文章中将做总结