http://blog.csdn.net/sodino/article/details/7741674

先上效果图。如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"进行替代。

通常子类化声明代码:

[java] view plain copy
  1. publicclassDownloadImgTaskextendsAsyncTask<String,Float,Bitmap>
不需要参数的声明代码:
[java] view plain copy
  1. publicclassDownloadImgTaskextendsAsyncTask<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请各位看官自行实现:

[java] view plain copy
  1. ActAsyncTask.java
  2. packagelab.sodino.asynctask;
  3. importandroid.app.Activity;
  4. importandroid.os.Bundle;
  5. importandroid.view.View;
  6. importandroid.view.View.OnClickListener;
  7. publicclassActAsyncTaskextendsActivityimplementsOnClickListener{
  8. privatePorterDuffViewpViewA,pViewB,pViewC,pViewD;
  9. publicstaticfinalString[]STRING_ARR={//
  10. "http://developer.android.com/images/home/android-jellybean.png",//
  11. "http://developer.android.com/images/home/design.png",//
  12. "http://developer.android.com/images/home/google-play.png",//
  13. "http://developer.android.com/images/home/google-io.png"};
  14. publicvoidonCreate(BundlesavedInstanceState){
  15. super.onCreate(savedInstanceState);
  16. setContentView(R.layout.main);
  17. pViewA=(PorterDuffView)findViewById(R.id.pViewA);
  18. pViewA.setOnClickListener(this);
  19. pViewB=(PorterDuffView)findViewById(R.id.pViewB);
  20. pViewB.setOnClickListener(this);
  21. pViewC=(PorterDuffView)findViewById(R.id.pViewC);
  22. pViewC.setOnClickListener(this);
  23. pViewD=(PorterDuffView)findViewById(R.id.pViewD);
  24. pViewD.setOnClickListener(this);
  25. }
  26. publicvoidonClick(Viewv){
  27. if(vinstanceofPorterDuffView){
  28. PorterDuffViewpdView=(PorterDuffView)v;
  29. if(pdView.isLoading()==false){
  30. DownloadImgTasktask=newDownloadImgTask(pdView);
  31. task.execute(STRING_ARR[pdView.getId()%STRING_ARR.length]);
  32. pdView.setPorterDuffMode(true);
  33. pdView.setLoading(true);
  34. pdView.setProgress(0);
  35. pdView.invalidate();
  36. }
  37. }
  38. }
  39. }


[java] view plain copy
  1. DownloadImgTask.java
  2. packagelab.sodino.asynctask;
  3. importjava.io.ByteArrayOutputStream;
  4. importjava.io.IOException;
  5. importjava.io.InputStream;
  6. importorg.apache.http.Header;
  7. importorg.apache.http.HttpEntity;
  8. importorg.apache.http.HttpResponse;
  9. importorg.apache.http.client.ClientProtocolException;
  10. importorg.apache.http.client.HttpClient;
  11. importorg.apache.http.client.methods.HttpGet;
  12. importorg.apache.http.impl.client.DefaultHttpClient;
  13. importorg.apache.http.params.HttpParams;
  14. importandroid.graphics.Bitmap;
  15. importandroid.graphics.BitmapFactory;
  16. importandroid.os.AsyncTask;
  17. /**
  18. *@authorSodinoE-mail:sodinoopen@hotmail.com
  19. *@versionTime:2012-7-5上午03:34:58
  20. */
  21. publicclassDownloadImgTaskextendsAsyncTask<String,Float,Bitmap>{
  22. privatePorterDuffViewpdView;
  23. publicDownloadImgTask(PorterDuffViewpdView){
  24. this.pdView=pdView;
  25. }
  26. /**下载准备工作。在UI线程中调用。*/
  27. protectedvoidonPreExecute(){
  28. LogOut.out(this,"onPreExecute");
  29. }
  30. /**执行下载。在背景线程调用。*/
  31. protectedBitmapdoInBackground(String...params){
  32. LogOut.out(this,"doInBackground:"+params[0]);
  33. HttpClienthttpClient=newDefaultHttpClient();
  34. HttpGethttpGet=newHttpGet(params[0]);
  35. InputStreamis=null;
  36. ByteArrayOutputStreambaos=null;
  37. try{
  38. HttpResponsehttpResponse=httpClient.execute(httpGet);
  39. printHttpResponse(httpResponse);
  40. HttpEntityhttpEntity=httpResponse.getEntity();
  41. longlength=httpEntity.getContentLength();
  42. LogOut.out(this,"contentlength="+length);
  43. is=httpEntity.getContent();
  44. if(is!=null){
  45. baos=newByteArrayOutputStream();
  46. byte[]buf=newbyte[128];
  47. intread=-1;
  48. intcount=0;
  49. while((read=is.read(buf))!=-1){
  50. baos.write(buf,0,read);
  51. count+=read;
  52. publishProgress(count*1.0f/length);
  53. }
  54. LogOut.out(this,"count="+count+"length="+length);
  55. byte[]data=baos.toByteArray();
  56. Bitmapbit=BitmapFactory.decodeByteArray(data,0,data.length);
  57. returnbit;
  58. }
  59. }catch(ClientProtocolExceptione){
  60. e.printStackTrace();
  61. }catch(IOExceptione){
  62. e.printStackTrace();
  63. }finally{
  64. try{
  65. if(baos!=null){
  66. baos.close();
  67. }
  68. if(is!=null){
  69. is.close();
  70. }
  71. }catch(IOExceptione){
  72. e.printStackTrace();
  73. }
  74. }
  75. returnnull;
  76. }
  77. /**更新下载进度。在UI线程调用。onProgressUpdate*/
  78. protectedvoidonProgressUpdate(Float...progress){
  79. //LogOut.out(this,"onProgressUpdate");
  80. pdView.setProgress(progress[0]);
  81. }
  82. /**通知下载任务完成。在UI线程调用。*/
  83. protectedvoidonPostExecute(Bitmapbit){
  84. LogOut.out(this,"onPostExecute");
  85. pdView.setPorterDuffMode(false);
  86. pdView.setLoading(false);
  87. pdView.setImageBitmap(bit);
  88. }
  89. protectedvoidonCancelled(){
  90. LogOut.out(this,"DownloadImgTaskcancel...");
  91. super.onCancelled();
  92. }
  93. privatevoidprintHttpResponse(HttpResponsehttpResponse){
  94. Header[]headerArr=httpResponse.getAllHeaders();
  95. for(inti=0;i<headerArr.length;i++){
  96. Headerheader=headerArr[i];
  97. LogOut.out(this,"name["+header.getName()+"]value["+header.getValue()+"]");
  98. }
  99. HttpParamsparams=httpResponse.getParams();
  100. LogOut.out(this,String.valueOf(params));
  101. LogOut.out(this,String.valueOf(httpResponse.getLocale()));
  102. }
  103. }


[java] view plain copy
  1. PorterDuffView.java
  2. packagelab.sodino.asynctask;
  3. importjava.text.DecimalFormat;
  4. importandroid.content.Context;
  5. importandroid.content.res.TypedArray;
  6. importandroid.graphics.Bitmap;
  7. importandroid.graphics.Canvas;
  8. importandroid.graphics.Paint;
  9. importandroid.graphics.PorterDuff;
  10. importandroid.graphics.PorterDuffXfermode;
  11. importandroid.graphics.drawable.BitmapDrawable;
  12. importandroid.graphics.drawable.Drawable;
  13. importandroid.util.AttributeSet;
  14. importandroid.widget.ImageView;
  15. /**
  16. *自定义组件实现新浪微博的图片加载效果。<br/>
  17. *
  18. *@authorSodinoE-mail:sodinoopen@hotmail.com
  19. *@versionTime:2012-7-9上午01:55:04
  20. */
  21. publicclassPorterDuffViewextendsImageView{
  22. /**前景Bitmap高度为1像素。采用循环多次填充进度区域。*/
  23. publicstaticfinalintFG_HEIGHT=1;
  24. /**下载进度前景色*/
  25. //publicstaticfinalintFOREGROUND_COLOR=0x77123456;
  26. publicstaticfinalintFOREGROUND_COLOR=0x77ff0000;
  27. /**下载进度条的颜色。*/
  28. publicstaticfinalintTEXT_COLOR=0xff7fff00;
  29. /**进度百分比字体大小。*/
  30. publicstaticfinalintFONT_SIZE=30;
  31. privateBitmapbitmapBg,bitmapFg;
  32. privatePaintpaint;
  33. /**标识当前进度。*/
  34. privatefloatprogress;
  35. /**标识进度图片的宽度与高度。*/
  36. privateintwidth,height;
  37. /**格式化输出百分比。*/
  38. privateDecimalFormatdecFormat;
  39. /**进度百分比文本的锚定Y中心坐标值。*/
  40. privatefloattxtBaseY;
  41. /**标识是否使用PorterDuff模式重组界面。*/
  42. privatebooleanporterduffMode;
  43. /**标识是否正在下载图片。*/
  44. privatebooleanloading;
  45. publicPorterDuffView(Contextcontext,AttributeSetattrs){
  46. super(context,attrs);
  47. init(context,attrs);
  48. }
  49. /**生成一宽与背景图片等同高为1像素的Bitmap,。*/
  50. privatestaticBitmapcreateForegroundBitmap(intw){
  51. Bitmapbm=Bitmap.createBitmap(w,FG_HEIGHT,Bitmap.Config.ARGB_8888);
  52. Canvasc=newCanvas(bm);
  53. Paintp=newPaint(Paint.ANTI_ALIAS_FLAG);
  54. p.setColor(FOREGROUND_COLOR);
  55. c.drawRect(0,0,w,FG_HEIGHT,p);
  56. returnbm;
  57. }
  58. privatevoidinit(Contextcontext,AttributeSetattrs){
  59. if(attrs!=null){
  60. ////////////////////////////////////////////
  61. //intcount=attrs.getAttributeCount();
  62. //for(inti=0;i<count;i++){
  63. //LogOut.out(this,"attrNameRes:"+
  64. //Integer.toHexString(attrs.getAttributeNameResource(i))//
  65. //+"attrName:"+attrs.getAttributeName(i)//
  66. //+"attrResValue:"+attrs.getAttributeResourceValue(i,-1)//
  67. //+"attrValue:"+attrs.getAttributeValue(i)//
  68. //);
  69. //}
  70. ////////////////////////////////////////////
  71. TypedArraytypedArr=context.obtainStyledAttributes(attrs,R.styleable.porterduff_PorterDuffView);
  72. porterduffMode=typedArr.getBoolean(R.styleable.porterduff_PorterDuffView_porterduffMode,false);
  73. }
  74. Drawabledrawable=getDrawable();
  75. if(porterduffMode&&drawable!=null&&drawableinstanceofBitmapDrawable){
  76. bitmapBg=((BitmapDrawable)drawable).getBitmap();
  77. width=bitmapBg.getWidth();
  78. height=bitmapBg.getHeight();
  79. //LogOut.out(this,"width="+width+"height="+height);
  80. bitmapFg=createForegroundBitmap(width);
  81. }else{
  82. //不符合要求,自动设置为false。
  83. porterduffMode=false;
  84. }
  85. paint=newPaint();
  86. paint.setFilterBitmap(false);
  87. paint.setAntiAlias(true);
  88. paint.setTextSize(FONT_SIZE);
  89. //关于FontMetrics的详情介绍,可见:
  90. //http://xxxxxfsadf.iteye.com/blog/480454
  91. Paint.FontMetricsfontMetrics=paint.getFontMetrics();
  92. //注意观察本输出:
  93. //ascent:单个字符基线以上的推荐间距,为负数
  94. LogOut.out(this,"ascent:"+fontMetrics.ascent//
  95. //descent:单个字符基线以下的推荐间距,为正数
  96. +"descent:"+fontMetrics.descent//
  97. //单个字符基线以上的最大间距,为负数
  98. +"top:"+fontMetrics.top//
  99. //单个字符基线以下的最大间距,为正数
  100. +"bottom:"+fontMetrics.bottom//
  101. //文本行与行之间的推荐间距
  102. +"leading:"+fontMetrics.leading);
  103. //在此处直接计算出来,避免了在onDraw()处的重复计算
  104. txtBaseY=(height-fontMetrics.bottom-fontMetrics.top)/2;
  105. decFormat=newDecimalFormat("0.0%");
  106. }
  107. publicvoidonDraw(Canvascanvas){
  108. if(porterduffMode){
  109. inttmpW=(getWidth()-width)/2,tmpH=(getHeight()-height)/2;
  110. //画出背景图
  111. canvas.drawBitmap(bitmapBg,tmpW,tmpH,paint);
  112. //设置PorterDuff模式
  113. paint.setXfermode(newPorterDuffXfermode(PorterDuff.Mode.DARKEN));
  114. //canvas.drawBitmap(bitmapFg,tmpW,tmpH-progress*height,
  115. //paint);
  116. inttH=height-(int)(progress*height);
  117. for(inti=0;i<tH;i++){
  118. canvas.drawBitmap(bitmapFg,tmpW,tmpH+i,paint);
  119. }
  120. //立即取消xfermode
  121. paint.setXfermode(null);
  122. intoriColor=paint.getColor();
  123. paint.setColor(TEXT_COLOR);
  124. paint.setTextSize(FONT_SIZE);
  125. Stringtmp=decFormat.format(progress);
  126. floattmpWidth=paint.measureText(tmp);
  127. canvas.drawText(decFormat.format(progress),tmpW+(width-tmpWidth)/2,tmpH+txtBaseY,paint);
  128. //恢复为初始值时的颜色
  129. paint.setColor(oriColor);
  130. }else{
  131. LogOut.out(this,"onDrawsuper");
  132. super.onDraw(canvas);
  133. }
  134. }
  135. publicvoidsetProgress(floatprogress){
  136. if(porterduffMode){
  137. this.progress=progress;
  138. //刷新自身。
  139. invalidate();
  140. }
  141. }
  142. publicvoidsetBitmap(Bitmapbg){
  143. if(porterduffMode){
  144. bitmapBg=bg;
  145. width=bitmapBg.getWidth();
  146. height=bitmapBg.getHeight();
  147. bitmapFg=createForegroundBitmap(width);
  148. Paint.FontMetricsfontMetrics=paint.getFontMetrics();
  149. txtBaseY=(height-fontMetrics.bottom-fontMetrics.top)/2;
  150. setImageBitmap(bg);
  151. //请求重新布局,将会再次调用onMeasure()
  152. //requestLayout();
  153. }
  154. }
  155. publicbooleanisLoading(){
  156. returnloading;
  157. }
  158. publicvoidsetLoading(booleanloading){
  159. this.loading=loading;
  160. }
  161. publicvoidsetPorterDuffMode(booleanbool){
  162. porterduffMode=bool;
  163. }
  164. }




更多相关文章

  1. Android(安卓)剪切板监听
  2. android 竖屏activity跳转横屏activity返回时数据消失
  3. Android(安卓)获取网络状态及调用网络配置界面(转帖)
  4. Android(安卓)GPS学习 (一) :GPS 启动流程
  5. Android上调用google map api v2
  6. android 使用gdb调试的方式
  7. 浅析android下如何通过jni监控wifi网络连接、dhcpcd执行和power
  8. Android上传文件到Web服务器,PHP接收文件(二)
  9. Android之Input子系统事件分发流程

随机推荐

  1. Android,谁动了我的内存(转)
  2. 第十章、Android的消息机制
  3. RelativeLayout 相对布局
  4. Android之NDK开发修补版
  5. 【译】Google官方推出的Android架构组件
  6. Android中View的事件执行机制
  7. C#/IOS/Android通用加密解密方法
  8. 我的Android NDK之旅(四),android串口通信-m
  9. android之LinearLayout中android:layout_
  10. 通过android代码获取android系统的imei、