先上效果图。如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.javapackage 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.javapackage 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:[email protected] * @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.javapackage 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:[email protected] * @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; }}