慕课网:Android异步加载AsyncTask项目实战中

上一篇,我们完成了使用AsyncTask异步加载获取了网络的数据,并且解析数据,顺利显示在了ListView中,但是其中图片还是使用的是本地的默认图片,并没有从网络获取图片,今天我们完成从网络获取图片的两种方法:

1.使用线程获取网络图片极其优化

ImageLoader.java

package com.xbmu.news;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.widget.ImageView;
public class ImageLoader {
	private ImageView mImageView;
	private Handler mHandler = new Handler(){
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			mImageView.setImageBitmap((Bitmap)msg.obj);
		};
	};
	/**
	 * 通过线程去显示图片
	 * @param imageView
	 * @param url
	 */
	public void showImageByThread(ImageView imageView, final String url) {
		mImageView = imageView;//将imageView的对象传递给引用。没有这条语句,会发生空指针异常
		new Thread() {
			public void run() {
				super.run();
				Bitmap bitmap = getBitmapFromURL(url);
				Message message = Message.obtain();
				message.obj = bitmap;
				mHandler.sendMessage(message);
			};
		}.start();
	}

	public Bitmap getBitmapFromURL(String urlString) {
		Bitmap bitmap;
		InputStream is  = null;
		try {
			URL url = new URL(urlString);
			HttpURLConnection connection = (HttpURLConnection) url.openConnection();
			is = new BufferedInputStream(connection.getInputStream());
			bitmap = BitmapFactory.decodeStream(is);
			connection.disconnect();//断开连接
			return bitmap;
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			try{
				is.close();//关闭流
			}catch(IOException e){
				e.printStackTrace();
			}
		}
		return null;
	}

}
修改适配器:NewsAdapter.java

@Override
public View getView(int position, View convertView, ViewGroup parent) {
	ViewHolder viewHolder = null;
	if(convertView == null){
		viewHolder = new ViewHolder();
		convertView = mInflater.inflate(R.layout.item_layout, null);
		viewHolder.ivIcon = (ImageView) convertView.findViewById(R.id.iv_icon);
		viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.tv_title);
		viewHolder.tvContent = (TextView) convertView.findViewById(R.id.tv_content);
		convertView.setTag(viewHolder);
	}else{
		viewHolder = (ViewHolder) convertView.getTag();
	}
	viewHolder.ivIcon.setImageResource(R.drawable.ic_launcher);//先设置图片为默认本地图片
	//从网络加载图片
	new ImageLoader().showImageByThread(viewHolder.ivIcon,mList.get(position).newsImgae);
	viewHolder.tvTitle.setText(mList.get(position).newsTitle);
	viewHolder.tvContent.setText(mList.get(position).newsContent);
	return convertView;
}

运行效果


仔细观察运行效果,并分析问题所在

出现的问题:看上去完美无缺,所有的图片都显示出来了,但是会发现这里的图片刷新显示的时候,会刷新多次,很多图片并不是一次加载成功。
分析原因:是因为ListView的缓存机制,ListView具有重用convertView的功能,这一条convertView,它可能是前面或后面这样一个缓冲池中的某一个View,当我们切换ListView的选项的时候,它会从缓冲池中取出已经存在的convertView,而这个convertView的图像是已经显示出来的。就会导致新的图片在加载前会先显示一下旧的图片。

解决方法:图片显示错位的原因在于正确的ListView没有显示正确的url。viewHolder.ivIcon.setTag(url)设置tag作为身份表标志,将url设置为身份验证码,
我们给这样的一个imageView设置了一个名为url的tag,也就是将这样的一个imageview和对应的URL中的图片进行了绑定。我们在获取图片的时候,需要进行判断,这样避免了缓存的图片对正确的图片的一个影响。

代码实现:

修改NewsAdapter.java

@Override
public View getView(int position, View convertView, ViewGroup parent) {
	ViewHolder viewHolder = null;
	if(convertView == null){
		viewHolder = new ViewHolder();
		convertView = mInflater.inflate(R.layout.item_layout, null);
		viewHolder.ivIcon = (ImageView) convertView.findViewById(R.id.iv_icon);
		viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.tv_title);
		viewHolder.tvContent = (TextView) convertView.findViewById(R.id.tv_content);
		convertView.setTag(viewHolder);
	}else{
		viewHolder = (ViewHolder) convertView.getTag();
	}
	viewHolder.ivIcon.setImageResource(R.drawable.ic_launcher);//先设置图片为默认本地图片
	String url = mList.get(position).newsImgae;
	viewHolder.ivIcon.setTag(url);//给ImageView设置tag标志,将url设置为身份验证码
	//从网络加载图片
	new ImageLoader().showImageByThread(viewHolder.ivIcon,url);
	viewHolder.tvTitle.setText(mList.get(position).newsTitle);
	viewHolder.tvContent.setText(mList.get(position).newsContent);
	return convertView;
}

修改ImageLoader.java

public class ImageLoader {
	private ImageView mImageView;
	private String mUrl;
	private Handler mHandler = new Handler(){
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			
			if(mImageView.getTag().equals(mUrl)){
				mImageView.setImageBitmap((Bitmap)msg.obj);			
			}
		};
	};
	/**
	 * 通过线程去显示图片
	 * @param imageView
	 * @param url
	 */
	public void showImageByThread(ImageView imageView, final String url) {
		mImageView = imageView;//将imageView的对象传递给引用。没有这条语句,会发生空指针异常
		mUrl = url;
		new Thread() {
			public void run() {
				super.run();
				Bitmap bitmap = getBitmapFromURL(url);
				Message message = Message.obtain();
				message.obj = bitmap;
				mHandler.sendMessage(message);
			};
		}.start();
	}
	.......
}	
运行效果图:


2.使用AsyncTask获取网络图片极其优化

ImageLoader.java
package com.xbmu.news;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.widget.ImageView;
public class ImageLoader {
	/**
	 * 通过AsyncTask异步加载从网络获取图片
	 * @param imageView
	 * @param url
	 */
	public void showImageByAsyncTask(ImageView imageView,String url){
		new NewsAsyncTask(imageView,url).execute(url);
	}
	private class NewsAsyncTask extends AsyncTask<String, Void, Bitmap>{
		private ImageView mImageView;
		private String mUrl;
		public NewsAsyncTask(ImageView imageView,String url) {
			mImageView = imageView;
			mUrl = url;
		}
		@Override
		protected Bitmap doInBackground(String... params) {
			return getBitmapFromURL(params[0]);
		}
		@Override
		protected void onPostExecute(Bitmap bitmap) {
			super.onPostExecute(bitmap);
			if(mImageView.getTag().equals(mUrl)){
				mImageView.setImageBitmap(bitmap);
			}
		}
		
	}
	public Bitmap getBitmapFromURL(String urlString) {
		Bitmap bitmap;
		InputStream is  = null;
		try {
			URL url = new URL(urlString);
			HttpURLConnection connection = (HttpURLConnection) url.openConnection();
			is = new BufferedInputStream(connection.getInputStream());
			bitmap = BitmapFactory.decodeStream(is);
			connection.disconnect();//断开连接
			return bitmap;
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			try{
				is.close();//关闭流
			}catch(IOException e){
				e.printStackTrace();
			}
		}
		return null;
	}
}
修改 NewsAdapter.java
@Override
public View getView(int position, View convertView, ViewGroup parent) {
	ViewHolder viewHolder = null;
	if(convertView == null){
		viewHolder = new ViewHolder();
		convertView = mInflater.inflate(R.layout.item_layout, null);
		viewHolder.ivIcon = (ImageView) convertView.findViewById(R.id.iv_icon);
		viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.tv_title);
		viewHolder.tvContent = (TextView) convertView.findViewById(R.id.tv_content);
		convertView.setTag(viewHolder);
	}else{
		viewHolder = (ViewHolder) convertView.getTag();
	}
	viewHolder.ivIcon.setImageResource(R.drawable.ic_launcher);//先设置图片为默认本地图片
	String url = mList.get(position).newsImgae;
	viewHolder.ivIcon.setTag(url);//给ImageView设置tag标志,将url设置为身份验证码
	//从网络加载图片
	new ImageLoader().showImageByAsyncTask(viewHolder.ivIcon, url);
	viewHolder.tvTitle.setText(mList.get(position).newsTitle);
	viewHolder.tvContent.setText(mList.get(position).newsContent);
	return convertView;
}
其运行效果和上面的一样。

全部代码下载地址:
http://download.csdn.net/detail/btt2013/9336381





你可能感兴趣的:(慕课网:Android异步加载AsyncTask项目实战中)