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 太晚了,没想这问题会花费这么长时间;

时间: 2024-10-06 16:27:52

Android加载网络图片学习过程的相关文章

Android加载网络图片报android.os.NetworkOnMainThreadException异常

Android加载网络图片大致可以分为两种,低版本的和高版本的.低版本比如4.0一下或者更低版本的API直接利用Http就能实现了: 1.main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="

android加载网络图片并保留缓存,随时点击打开

今天工作需要写了一个保留网络图片缓存的类,和大家分享一下 其实实现原理很简单,也就是从网上下载图片数据,一边将数据转成drawable并加载到指定的imageview 一边保存成download_image.jpg,在点击imageview时候用intent将图片打开 我将处理图片的过程写成了类 package com.example.downloadandopenimage; import java.io.File; import java.io.FileOutputStream; impor

Android加载网络图片的工具类

ImageView加载网络的图片 HttpUtil.java package com.eiice.httpuimagetils; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import android.graphics.Bitmap; import android.util.Log; /** *

Android 加载网络图片时 宽度固定 按等比例显示

View v = LayoutInflater.from(TourBuyDetailsActivity.this ).inflate(R.layout.tour_details_header_img_item,null); final ImageView imageView = (ImageView) v.findViewById(R.id.content_pic); ImageLoader.getInstance().displayImage(travelMode.getMedia().ima

Android Volley入门到精通:使用Volley加载网络图片

在上一篇文章中,我们了解了Volley到底是什么,以及它的基本用法.本篇文章中我们即将学习关于Volley更加高级的用法,如何你还没有看过我的上一篇文章的话,建议先去阅读Android Volley完全解析(一),初识Volley的基本用法. 在上篇文章中有提到过,Volley是将AsyncHttpClient和Universal-Image-Loader的优点集成于一身的一个框架.我们都知道,Universal-Image-Loader具备非常强大的加载网络图片的功能,而使用Volley,我们

Android中用双缓存技术,加载网络图片

最近在学校参加一个比赛,写的一个Android应用,里面要加载大量的网络图片,可是用传统的方法图片一多就会造成程序出现内存溢出而崩溃.因为自己也在学习中,所以看了很多博客和视频,然后参照这些大神的写源码,自己写了一个加载网络图片工具类. 里面要用到一个经典的图片缓存库DiskLruCache 下载地址为:  DiskLruCache下载 下面是使用这个类实现的 双缓存网络图片加载 [java] view plain copy public class DiskLruCacheUtils { pr

Android三种基本的加载网络图片方式(转)

Android三种基本的加载网络图片方式,包括普通加载网络方式.用ImageLoader加载图片.用Volley加载图片. 1. [代码]普通加载网络方式 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60

Android之ListView异步加载网络图片(优化缓存机制)【转】

网上关于这个方面的文章也不少,基本的思路是线程+缓存来解决.下面提出一些优化: 1.采用线程池 2.内存缓存+文件缓存 3.内存缓存中网上很多是采用SoftReference来防止堆溢出,这儿严格限制只能使用最大JVM内存的1/4 4.对下载的图片进行按比例缩放,以减少内存的消耗 具体的代码里面说明.先放上内存缓存类的代码MemoryCache.java: public class MemoryCache { private static final String TAG = "MemoryCa

Android-Universal-Image-Loader,android-Volley和Picasso三大Android开源组件加载网络图片的优缺点比较

在android中的加载网络图片是一件十分令人头疼的事情,在网上有着许多关于加载网络图片的开源库,可以让我们十分方便的加载网络图片.在这里我主要介绍一下我自己在使用Volley, Picasso, Universal-Imageloader的一些使用的感悟.以及最基本的用法介绍.1.android-Volley 给ImageView设置图片源 // imageView是一个ImageView实例 // ImageLoader.getImageListener的第二个参数是默认的图片resourc