• Android加载网络图片学习过程


     

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

    一、最简单加载网络图片

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

            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);
    	}
    }
    
    然后在需要加载图片的地方调用调用onLoadImage()方法即可,在接口OnLoadImageListener的回调方法OnLoadImage()中,如:
       Utils.onLoadImage(url, new OnLoadImageListener() {
    		@Override
    		public void OnLoadImage(Bitmap bitmap, String bitmapPath) {
    			// TODO Auto-generated method stub
    			if(bitmap!=null){
    				imageview.setImageBitmap(bitmap);
    			}
    		}
    	});
    wangluo jiazai zhong -->读取完网络数据后,加载图片效果---->
    三、第二种方法的弊端是,当有大量图片需要加载时,会启动很多线程,避免出现这种情况的方法是,定义线程个数,当线程数达到最多时,不再开启,直到有一个线程结束,再开启一个线程;这种做法相当于

    引入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之间的转换,在其他文章中将做总结!

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

     
  • 相关阅读:
    自动机
    C语言文法
    实验报告一:词法分析
    Python的基础综合练习
    Python基础综合练习
    turtle画五星红旗
    熟悉常用的Linux操作
    大数据概述
    对学习编译原理的看法
    LINUX
  • 原文地址:https://www.cnblogs.com/xgjblog/p/4227066.html
Copyright © 2020-2023  润新知