安卓开发笔记——关于AsyncTask的使用
在安卓开发中,我们经常要进行一些耗时操作,比如数据库操作,获取网络资源,读取内存文件等等,当我们在处理这些耗时操作的时候,如果我们直接在UI主线程进行,那么可能会导致阻塞UI主线程,使得UI界面卡顿,带来很不好的用户体验,因此安卓也给我们提供了2个异步操作的类,Handler和AsyncTask。
今天先讲AsyncTask,AsyncTask类是Andorid提供给我们的一个轻量级异步类,算是一个框架,它对线程之间的通讯进行了封装,并且提供了简易的编程操作,使得我们可以很轻松的实现后台线程和UI主线程之间的通讯。
我写了一个异步获取网络图片的小例子,先来看实现效果:
以上是官网对AsyncTask的一些描述,大致意思是:
AsyncTask是一个易操作线程使用类,它可以帮助我们把后台线程处理程序的结果发送给UI主线程,使UI线程得到更新。
AsyncTask类提供了3个泛型参数(Params,Progress,Result)和4个执行步骤(下文会具体提及)
先来看下3个泛型参数
1、Params:这是一个任务参数,一般我们会定义成String类型的,例如本例子中要获取网络资源的URL地址
2、Progress:任务执行的刻度,一般我们会定义成Integer类型
3、Result:返回结果类型,例如本例中是对网络图片进行获取,那么它的返回类型应该是BitMap
再来看下4个步骤:
当我们的类去实现AsyncTask类的时候至少需要实现doInBackground(Params...)方法,这里作为学习,我把每一个的具体工作任务也说说
它的执行顺序是这样的 onPreExecute-->doInBackground-->onProgressUpdate-->onPostExecute
1、onPreExecute:这是一个预处理方法,在任务开始的时候执行,我们可以在这里进行一些控件的实例化,设置属性等。(非必须)
2、doInBackground:这是一个任务操作方法,也是最重要的一个方法,所有的耗时操作都应该在这里执行。(必须)
3、onProgressUpdate:这是一个进度即时更新方法,在这里我们可以即时更新任务滚动条的进度。(非必须,当在doInBackground里调用publishProgress时触发)
4、onPostExecute:这是一个任务结果处理方法,在doInBackground里执行完任务,会将结果通知给这个类,在这类中我们可以对UI进行更新操作(非必须)
上面的1、3、4是UI主线程触发调用的,所以可以对UI进行更新操作,而第2步是个异步操作,不能在里面进行UI的更新操作。
关于AsyncTask的调用,其实非常简单,我们在AsyncTask类被继承实现的时候,在主线程直接对其对象调用execute(Params..)方法即可。
好了,文字介绍到此结束,上代码:
1、布局文件
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:gravity="center" 6 android:orientation="vertical"> 7 8 <ImageView 9 android:id="@+id/imageView" 10 android:layout_width="wrap_content" 11 android:layout_height="wrap_content" /> 12 13 <Button 14 android:id="@+id/bt_download" 15 android:layout_width="wrap_content" 16 android:layout_height="wrap_content" 17 android:text="下载图片" /> 18 19 </LinearLayout>
2、AsyncTask的实现类
1 package com.example.asynctasktest; 2 3 import java.io.ByteArrayOutputStream; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.OutputStream; 7 8 import org.apache.http.HttpResponse; 9 import org.apache.http.client.ClientProtocolException; 10 import org.apache.http.client.HttpClient; 11 import org.apache.http.client.methods.HttpGet; 12 import org.apache.http.impl.client.DefaultHttpClient; 13 14 import android.app.ProgressDialog; 15 import android.graphics.Bitmap; 16 import android.graphics.BitmapFactory; 17 import android.os.AsyncTask; 18 import android.widget.ImageView; 19 20 public class MyAsyncTask extends AsyncTask<String, Integer, Bitmap> { 21 22 private ImageView imageView; 23 private ProgressDialog progressDialog; 24 25 public MyAsyncTask(ImageView imageView, ProgressDialog progressDialog) { 26 this.imageView = imageView; 27 this.progressDialog = progressDialog; 28 } 29 30 /** 31 * 执行第一步 这里为预处理操作,被UI线程所调用(可以在这里完成进度条的属性设置) 32 */ 33 @Override 34 protected void onPreExecute() { 35 super.onPreExecute(); 36 progressDialog.setTitle("当前任务"); 37 progressDialog.setMessage("正在下载图片,请稍后..."); 38 progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);//设置进度条样式,横项 39 progressDialog.show(); 40 } 41 42 /** 43 * 执行第二步 这里为异步线程,在这里处理耗时任务操作(比如:下载,读取文件) 44 * 通过调用publishProgress方法(传递即时任务进度)可以触发onProgressUpdate的执行 45 */ 46 @Override 47 protected Bitmap doInBackground(String... params) { 48 String path=params[0]; 49 Bitmap bitmap=null; 50 HttpClient httpClient=new DefaultHttpClient(); 51 HttpGet httpGet=new HttpGet(path); 52 InputStream inputStream=null; 53 try { 54 HttpResponse httpResponse=httpClient.execute(httpGet); 55 if(httpResponse.getStatusLine().getStatusCode()==200){ 56 //连接成功 57 // HttpEntity entity=httpResponse.getEntity(); 58 // byte[] data=EntityUtils.toByteArray(entity); 59 // bitmap=BitmapFactory.decodeByteArray(data, 0, data.length); 60 61 inputStream=httpResponse.getEntity().getContent(); 62 ByteArrayOutputStream outputStream=new ByteArrayOutputStream(); 63 long fileSize=httpResponse.getEntity().getContentLength();//文件总大小 64 byte[] data=new byte[1024];//每次读取的大小 65 int len=0;//本次读取的大小 66 int total=0;//累计读取的大小 67 while((len=inputStream.read(data))!=-1){ 68 total+=len;//累计读取的大小 69 int values=(int) ((total/(float)fileSize)*100);//得到当前任务进行百分比 70 publishProgress(values);//触发onProgressUpdate更新即时进度 71 outputStream.write(data, 0, len); 72 } 73 byte[] result=outputStream.toByteArray();//转换为字节数组 74 bitmap=BitmapFactory.decodeByteArray(result, 0, result.length); 75 } 76 } catch (ClientProtocolException e) { 77 e.printStackTrace(); 78 } catch (IOException e) { 79 e.printStackTrace(); 80 }finally{ 81 if(inputStream!=null){ 82 try { 83 inputStream.close(); 84 } catch (IOException e) { 85 e.printStackTrace(); 86 } 87 } 88 } 89 90 return bitmap; 91 92 } 93 94 /** 95 * 执行第三步 这里为实时UI更新操作,被UI线程所调用 在这里可以即时更新(如进度条进度) 96 */ 97 @Override 98 protected void onProgressUpdate(Integer... values) { 99 super.onProgressUpdate(values); 100 progressDialog.setProgress(values[0]); 101 } 102 103 /** 104 * 执行第四步 在这里会返回doInBackground的操作结果,被UI线程调用,更新最后UI结果 105 */ 106 @Override 107 protected void onPostExecute(Bitmap result) { 108 super.onPostExecute(result); 109 progressDialog.dismiss(); 110 imageView.setImageBitmap(result); 111 } 112 113 }
3、主类
1 package com.example.asynctasktest; 2 3 import android.app.ProgressDialog; 4 import android.os.Bundle; 5 import android.support.v7.app.ActionBarActivity; 6 import android.view.View; 7 import android.view.View.OnClickListener; 8 import android.widget.Button; 9 import android.widget.ImageView; 10 11 public class MainActivity extends ActionBarActivity { 12 13 private ImageView imageView; 14 private Button bt_download; 15 private ProgressDialog progressDialog;//进度对话框 16 private String path="http://img.pconline.com.cn/images/photoblog/5/3/7/5/5375781/20096/6/1244302842840.jpg";//下载图片路径 17 18 @Override 19 protected void onCreate(Bundle savedInstanceState) { 20 super.onCreate(savedInstanceState); 21 setContentView(R.layout.activity_main); 22 23 imageView=(ImageView) findViewById(R.id.imageView); 24 bt_download=(Button) findViewById(R.id.bt_download); 25 progressDialog=new ProgressDialog(this); 26 27 bt_download.setOnClickListener(new OnClickListener() { 28 29 @Override 30 public void onClick(View v) { 31 MyAsyncTask myAsyncTask=new MyAsyncTask(imageView,progressDialog); 32 myAsyncTask.execute(path); 33 } 34 }); 35 36 } 37 38 39 }
代码到此结束,注释很详细应该很好理解。
使用AsyncTask类,以下是几条必须遵守的准则:
- Task的实例必须在UI主线程中创建。
- execute方法必须在UI主线程中调用。
- 不要手动的调用onPreExecute(),onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法。
- 该task只能被执行一次,否则多次调用时将会出现异常。
当然AsyncTask类不止这些东西,还有线程池的概念,今天先不讲,过几天连同Handler一起说。
对于简单的异步操作,掌握这些已经够了。
项目代码:http://pan.baidu.com/s/1kTkTgm7
作者:Balla_兔子
出处:http://www.cnblogs.com/lichenwei/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
正在看本人博客的这位童鞋,我看你气度不凡,谈吐间隐隐有王者之气,日后必有一番作为!旁边有“推荐”二字,你就顺手把它点了吧,相得准,我分文不收;相不准,你也好回来找我!