[Android] AsyncTask使用实例---加载网络图片

先上效果图。如demo_asynctask.gif


对于图片的加载效果,见链接:[Android] PorterDuff使用实例----实现新浪微博图片下载效果

本文参考链接:http://developer.android.com/reference/android/os/AsyncTask.html

AsyncTask被设计成方便编写Thread与Handler交互的辅助类,几秒钟的背景耗时操作是理想的使用场合。
AsyncTask必须被子类化才能使用,在该过程中必须设定3个构造参数:
           1.Params 往背景线程执行时的参数类型
           2.Progress 背景线程发布任务进度的参数类型
           3.Result 背景线程的运行后最后返回的结果的参数类型
如果不需要声明参数类型,可以使用"Void"进行替代。

通常子类化声明代码:

           public class DownloadImgTask extends AsyncTask<String, Float, Bitmap>
不需要参数的声明代码:
           public class DownloadImgTask extends AsyncTask<Void, Void, Void>

当一个AsyncTask被执行后,会有如下4个步骤:
           1.onPreExecute() 在UI线程中调用。这个步骤通常用于一些准备操作,如显示一个进度条
           2.doInBackground(Params ...) 当onPreExecute()执行完毕后,即被背景线程调用执行。这个步骤用于执行耗时的计算。方法中为不定参数,由外部调用AsyncTask.execute(Params...)时设定。本步骤运行的过程可以通过publishProgress(Progress...)发布到onProgressUpdate(Progress...)中,运行结果将return,后被传参至onPostExecute(Result)。
           3.onProgressUpdate(Progress...) 当执行publishProgress(Progress...)后在UI线程中被调用。执行的时间是不确定的。
           4.onPostExecute(Result) 在UI线程中被调用。参数为doInBackground(Params...)的运行结果。

在AsyncTask的执行过程中可以调用cancel(boolean),方法中的参数值为false时允许已经开始工作的背景线程继续工作至任务完成;为true时则强制停止。AsyncTask将不再调用onPostExecute(Result),取而代之的是调用onCancelled(Object)。为了确定当前的AsyncTask是否已经被cancelled,应该在doInBackground(Params...)方法中执行isCancelled()进行检查。


为了AsyncTask顺利工作,必须遵守线程规则:
           1.AsyncTask必须在UI线程中被调用。JELLY_BEAN版本默认已经遵守此规则。
           2.AsyncTask的实例必须在UI线程中被创建。
           3.execute(Params...)必须在UI线程中被调用。
           4.不允许手工调用以下方法:
                      onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...)
           5.AsyncTask的实例只能被执行一次。再次执行时将会抛出异常:
                      java.lang.IllegalStateException: Cannot execute task: the task is already running.


本文为Sodino所有,转载请注明出处:http://blog.csdn.net/sodino/article/details/7741674

Java代码贴上,XML请各位看官自行实现:

ActAsyncTask.java

package lab.sodino.asynctask;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;

public class ActAsyncTask extends Activity implements OnClickListener {
	private PorterDuffView pViewA, pViewB, pViewC, pViewD;
	public static final String[] STRING_ARR = {//
	"http://developer.android.com/images/home/android-jellybean.png",//
			"http://developer.android.com/images/home/design.png",//
			"http://developer.android.com/images/home/google-play.png",//
			"http://developer.android.com/images/home/google-io.png" };

	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		pViewA = (PorterDuffView) findViewById(R.id.pViewA);
		pViewA.setOnClickListener(this);
		pViewB = (PorterDuffView) findViewById(R.id.pViewB);
		pViewB.setOnClickListener(this);
		pViewC = (PorterDuffView) findViewById(R.id.pViewC);
		pViewC.setOnClickListener(this);
		pViewD = (PorterDuffView) findViewById(R.id.pViewD);
		pViewD.setOnClickListener(this);
	}

	public void onClick(View v) {
		if (v instanceof PorterDuffView) {
			PorterDuffView pdView = (PorterDuffView) v;
			if (pdView.isLoading() == false) {
				DownloadImgTask task = new DownloadImgTask(pdView);
				task.execute(STRING_ARR[pdView.getId() % STRING_ARR.length]);
				pdView.setPorterDuffMode(true);
				pdView.setLoading(true);
				pdView.setProgress(0);
				pdView.invalidate();
			}
		}
	}
}


DownloadImgTask.java


package lab.sodino.asynctask;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpParams;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;

/**
 * @author Sodino E-mail:sodinoopen@hotmail.com
 * @version Time:2012-7-5 上午03:34:58
 */
public class DownloadImgTask extends AsyncTask<String, Float, Bitmap> {
	private PorterDuffView pdView;

	public DownloadImgTask(PorterDuffView pdView) {
		this.pdView = pdView;
	}

	/** 下载准备工作。在UI线程中调用。 */
	protected void onPreExecute() {
		LogOut.out(this, "onPreExecute");
	}

	/** 执行下载。在背景线程调用。 */
	protected Bitmap doInBackground(String... params) {
		LogOut.out(this, "doInBackground:" + params[0]);
		HttpClient httpClient = new DefaultHttpClient();
		HttpGet httpGet = new HttpGet(params[0]);
		InputStream is = null;
		ByteArrayOutputStream baos = null;
		try {
			HttpResponse httpResponse = httpClient.execute(httpGet);
			printHttpResponse(httpResponse);
			HttpEntity httpEntity = httpResponse.getEntity();
			long length = httpEntity.getContentLength();
			LogOut.out(this, "content length=" + length);
			is = httpEntity.getContent();
			if (is != null) {
				baos = new ByteArrayOutputStream();
				byte[] buf = new byte[128];
				int read = -1;
				int count = 0;
				while ((read = is.read(buf)) != -1) {
					baos.write(buf, 0, read);
					count += read;
					publishProgress(count * 1.0f / length);
				}
				LogOut.out(this, "count=" + count + " length=" + length);
				byte[] data = baos.toByteArray();
				Bitmap bit = BitmapFactory.decodeByteArray(data, 0, data.length);
				return bit;
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (baos != null) {
					baos.close();
				}
				if (is != null) {
					is.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	/** 更新下载进度。在UI线程调用。onProgressUpdate */
	protected void onProgressUpdate(Float... progress) {
		// LogOut.out(this, "onProgressUpdate");
		pdView.setProgress(progress[0]);
	}

	/** 通知下载任务完成。在UI线程调用。 */
	protected void onPostExecute(Bitmap bit) {
		LogOut.out(this, "onPostExecute");
		pdView.setPorterDuffMode(false);
		pdView.setLoading(false);
		pdView.setImageBitmap(bit);
	}

	protected void onCancelled() {
		LogOut.out(this, "DownloadImgTask cancel...");
		super.onCancelled();
	}

	private void printHttpResponse(HttpResponse httpResponse) {
		Header[] headerArr = httpResponse.getAllHeaders();
		for (int i = 0; i < headerArr.length; i++) {
			Header header = headerArr[i];
			LogOut.out(this, "name[" + header.getName() + "]value[" + header.getValue() + "]");
		}
		HttpParams params = httpResponse.getParams();
		LogOut.out(this, String.valueOf(params));
		LogOut.out(this, String.valueOf(httpResponse.getLocale()));
	}
}


PorterDuffView.java

package lab.sodino.asynctask;

import java.text.DecimalFormat;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;

/**
 * 自定义组件实现新浪微博的图片加载效果。<br/>
 * 
 * @author Sodino E-mail:sodinoopen@hotmail.com
 * @version Time:2012-7-9 上午01:55:04
 */
public class PorterDuffView extends ImageView {
	/** 前景Bitmap高度为1像素。采用循环多次填充进度区域。 */
	public static final int FG_HEIGHT = 1;
	/** 下载进度前景色 */
	// public static final int FOREGROUND_COLOR = 0x77123456;
	public static final int FOREGROUND_COLOR = 0x77ff0000;
	/** 下载进度条的颜色。 */
	public static final int TEXT_COLOR = 0xff7fff00;
	/** 进度百分比字体大小。 */
	public static final int FONT_SIZE = 30;
	private Bitmap bitmapBg, bitmapFg;
	private Paint paint;
	/** 标识当前进度。 */
	private float progress;
	/** 标识进度图片的宽度与高度。 */
	private int width, height;
	/** 格式化输出百分比。 */
	private DecimalFormat decFormat;
	/** 进度百分比文本的锚定Y中心坐标值。 */
	private float txtBaseY;
	/** 标识是否使用PorterDuff模式重组界面。 */
	private boolean porterduffMode;
	/** 标识是否正在下载图片。 */
	private boolean loading;

	public PorterDuffView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context, attrs);
	}

	/** 生成一宽与背景图片等同高为1像素的Bitmap,。 */
	private static Bitmap createForegroundBitmap(int w) {
		Bitmap bm = Bitmap.createBitmap(w, FG_HEIGHT, Bitmap.Config.ARGB_8888);
		Canvas c = new Canvas(bm);
		Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
		p.setColor(FOREGROUND_COLOR);
		c.drawRect(0, 0, w, FG_HEIGHT, p);
		return bm;
	}

	private void init(Context context, AttributeSet attrs) {
		if (attrs != null) {
			// //
			// int count = attrs.getAttributeCount();
			// for (int i = 0; i < count; i++) {
			// LogOut.out(this, "attrNameRes:" +
			// Integer.toHexString(attrs.getAttributeNameResource(i))//
			// + " attrName:" + attrs.getAttributeName(i)//
			// + " attrResValue:" + attrs.getAttributeResourceValue(i, -1)//
			// + " attrValue:" + attrs.getAttributeValue(i)//
			// );
			// }
			// //

			TypedArray typedArr = context.obtainStyledAttributes(attrs, R.styleable.porterduff_PorterDuffView);
			porterduffMode = typedArr.getBoolean(R.styleable.porterduff_PorterDuffView_porterduffMode, false);
		}
		Drawable drawable = getDrawable();
		if (porterduffMode && drawable != null && drawable instanceof BitmapDrawable) {
			bitmapBg = ((BitmapDrawable) drawable).getBitmap();
			width = bitmapBg.getWidth();
			height = bitmapBg.getHeight();
			// LogOut.out(this, "width=" + width + " height=" + height);
			bitmapFg = createForegroundBitmap(width);
		} else {
			// 不符合要求,自动设置为false。
			porterduffMode = false;
		}

		paint = new Paint();
		paint.setFilterBitmap(false);
		paint.setAntiAlias(true);
		paint.setTextSize(FONT_SIZE);

		// 关于FontMetrics的详情介绍,可见:
		// http://xxxxxfsadf.iteye.com/blog/480454
		Paint.FontMetrics fontMetrics = paint.getFontMetrics();
		// 注意观察本输出:
		// ascent:单个字符基线以上的推荐间距,为负数
		LogOut.out(this, "ascent:" + fontMetrics.ascent//
				// descent:单个字符基线以下的推荐间距,为正数
				+ " descent:" + fontMetrics.descent //
				// 单个字符基线以上的最大间距,为负数
				+ " top:" + fontMetrics.top //
				// 单个字符基线以下的最大间距,为正数
				+ " bottom:" + fontMetrics.bottom//
				// 文本行与行之间的推荐间距
				+ " leading:" + fontMetrics.leading);
		// 在此处直接计算出来,避免了在onDraw()处的重复计算
		txtBaseY = (height - fontMetrics.bottom - fontMetrics.top) / 2;

		decFormat = new DecimalFormat("0.0%");
	}

	public void onDraw(Canvas canvas) {
		if (porterduffMode) {
			int tmpW = (getWidth() - width) / 2, tmpH = (getHeight() - height) / 2;
			// 画出背景图
			canvas.drawBitmap(bitmapBg, tmpW, tmpH, paint);
			// 设置PorterDuff模式
			paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN));
			// canvas.drawBitmap(bitmapFg, tmpW, tmpH - progress * height,
			// paint);
			int tH = height - (int) (progress * height);
			for (int i = 0; i < tH; i++) {
				canvas.drawBitmap(bitmapFg, tmpW, tmpH + i, paint);
			}

			// 立即取消xfermode
			paint.setXfermode(null);
			int oriColor = paint.getColor();
			paint.setColor(TEXT_COLOR);
			paint.setTextSize(FONT_SIZE);
			String tmp = decFormat.format(progress);
			float tmpWidth = paint.measureText(tmp);
			canvas.drawText(decFormat.format(progress), tmpW + (width - tmpWidth) / 2, tmpH + txtBaseY, paint);
			// 恢复为初始值时的颜色
			paint.setColor(oriColor);
		} else {
			LogOut.out(this, "onDraw super");
			super.onDraw(canvas);
		}
	}

	public void setProgress(float progress) {
		if (porterduffMode) {
			this.progress = progress;
			// 刷新自身。
			invalidate();
		}
	}

	public void setBitmap(Bitmap bg) {
		if (porterduffMode) {
			bitmapBg = bg;
			width = bitmapBg.getWidth();
			height = bitmapBg.getHeight();

			bitmapFg = createForegroundBitmap(width);

			Paint.FontMetrics fontMetrics = paint.getFontMetrics();
			txtBaseY = (height - fontMetrics.bottom - fontMetrics.top) / 2;
			
			setImageBitmap(bg);
			// 请求重新布局,将会再次调用onMeasure()
			// requestLayout();
		}
	}

	public boolean isLoading() {
		return loading;
	}

	public void setLoading(boolean loading) {
		this.loading = loading;
	}

	public void setPorterDuffMode(boolean bool) {
		porterduffMode = bool;
	}
}





评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值