转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空)
一、引言 我们知道Android的UI线程主要负责处理用户的按键事件用户触屏事件屏幕绘图事件等,对于其他的操作尽量不要在UI线程中实现,因为这些操作很有可能会阻塞UI线程,比如一些耗时操作,会导致UI界面停止响应,从而降低了用户的体验。所以,为了避免UI线程失去响应的问题,Android建议将耗时操作放在新线程中完成,但新线程也可能需要动态更新UI组件:比如需要从网上获取一个网页,然后在TextView中将其源代码显示出来,此时就应该将连接网络,获取网络数据的操作(耗时)放在新线程中完成。 但是,问题来了:当获取网络数据之后,由于新线程不允许直接更新UI组件,我们该如何更新UI组件数据呢?为了解决新线程不能更新UI组件问题,Android提供了如下几种解决方案: (1)使用Handler消息传递机制实现线程之间的通信(如上一篇文章所述); (2)Activity.runOnUiThread(Runnable); (3)View.post(Runnable); (4)View.postDelayed(Runnable long); (5)异步任务。又由于(2)~(4)方式有可能导致编程有点繁琐,而异步任务则可简化这种操作。 二、AsyncTask简介 Android的类AsyncTask对线程间通讯进行了包装,提供了简易的编程方式使后台线程和UI线程进行通讯:后台线程执行异步任务,并把操作结果通知UI。不再需要子线程和Handler就可以完成异步操作并且刷新用户界面 1.AsyncTask类 AsyncTask<>是一个抽象类,通常用于被继承,继承AsyncTask时需要指定如下三种泛型参数: (1)Params:启动任务执行输入参数的类型; (2)Progress:后台任务完成的进度值(百分比)的类型; (3)Result:后台执行任务完成后返回结果的类型,如String、Integer; 2.Async类中主要方法 (1)onPreExecute():该方法将在执行实际的后台操作前UI线程调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条,或者一些控件的实例化,这个方法可以不用实现。 -----(UI线程调用,后台线程未启动,初始化工作) (2)doInBackground(Params...values):将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些比较耗时的后台处理工作。可以调用 publishProgress()方法来实时更新任务进度。该方法是抽象方法,子类必须实现。 -----(后台线程调用,执行后台任务)
(3)onProgressUpdate(Progress...values):在publishProgress方法被调用后,UI 线程将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。 -----(UI线程调用,展现后台任务进展)
(4)onPostExecute(Result):在doInBackground 执行完成后,onPostExecute 方法将被UI线程调用,后台的计算结果(doInBackground方法返回值)将通过该方法传递到UI线程,并且在界面上展示给用户。 -----(UI线程调用,显示后台线程运行结果) (5) onCancelled():在用户取消线程操作的时候调用。在主线程中调用onCancelled()的时候调用。 -----(UI线程调用,取消后台线程) 三、异步任务处理开发步骤 1.创建AsyncTask的子类,并为三个泛型参数指定类型。如果某个泛型参数不需要指定类型,则将它指定为Void。 2.根据需要实现AsyncTask上述五中方法; 3.调用AsyncTask子类的实例的execute(Params... params)开始执行耗时任务。 另外,使用AsyncTask类需要遵守的以下准则 (1)Task的实例必须在UI线程中创建; (2)execute(Params...)方法必须在UI线程中调用; (3)不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...),onProgressUpdate(Progress...)这几个方法,需要在UI线程中实例化这个task来调用; (4)该task只能被执行一次,否者多次调用时将会出现异常 四、源码实战 1.实现功能 2.源码实现 (1)MainActivity.java 功能:用以获取界面组件,实例化一个AsyncTask子类对象并调用其exeute(Integer....params)方法以指定参数params运行一个任务。
package com.example.android_asynctask;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.ProgressBar;import android.widget.TextView;public class MainActivity extends Activity { private Button downbtn; private TextView textView; private ProgressBar progressBar;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        downbtn = (Button)findViewById(R.id.download);        textView = (TextView)findViewById(R.id.text);        progressBar = (ProgressBar)findViewById(R.id.progressBar);        final DownloadTest download = new DownloadTest(textView,progressBar);//获取一个DownloadTest对象,并传递组件对象参数        downbtn.setOnClickListener(new OnClickListener()        {   @Override   public void onClick(View v) {    download.execute(200);   }        });           }}
(2)DownloadTest.java 功能:继承于AsyncTask的子类,其中onPreExecute()作用是为运行后台线程(子线程)完成初始化工作;doInBackground方法运行后台线程;onProgressUpdate方法更新UI;onPostExecute方法处理后台线程运行结果。
package com.example.android_asynctask;import android.graphics.Color;import android.os.AsyncTask;import android.view.View;import android.widget.ProgressBar;import android.widget.TextView;public class DownloadTest extends AsyncTask<Integer,Integer,String>{ private TextView tv; private ProgressBar pb; //带参数构造方法 DownloadTest(TextView text,ProgressBar bar) {  this.tv = text;  this.pb = bar; } //不带参数构造方法 DownloadTest() { } /*1.onPreExecute方法  * 为子线程(后台)运行初始化相关内容  */ protected void onPreExecute() {      tv.setVisibility(View.VISIBLE); //设置显示文本组件      pb.setVisibility(View.VISIBLE); //设置显示进度条      super.onPreExecute(); } /*2.doInBackground方法  *  运行一个后台线程,该线程实现每arg0[0]毫秒调用一次onProgressUpdate方法  */ protected String doInBackground(Integer... arg0) {  for(int i=0;i<100;i++)  {   publishProgress(i); //调用onProgressUpdate方法并传递参数i   try {    Thread.sleep(arg0[0]);//累加一次,线程休眠argo[0]毫秒   } catch (InterruptedException e) {    e.printStackTrace();   }  }  return "下载完毕"; //后台子线程运行完毕后,返回的值 } /*3.onProgressUpdate方法  * 调用publishProgress(i)时调用该方法,并传递参数i给形参values[0]*/ @Override protected void onProgressUpdate(Integer... values) {  pb.setProgress(values[0]); //设置进度条值  tv.setText("已经下载"+values[0]+"%"); //文本组件显示提示信息  super.onProgressUpdate(values); } /*4.onPostExecute  * 处理后台线程得到的结果  * */ protected void onPostExecute(String result) {  pb.setVisibility(View.INVISIBLE);//隐藏进度条  tv.setVisibility(View.VISIBLE);//显示UI文本显示框组件  tv.setText(result);  tv.setTextSize(20);  tv.setTextColor(Color.RED);  super.onPostExecute(result); }}


效果演示:

源码分析: 通过源码我们可以知道,主线程通过调用AsyncTask子类的execute()方法,进而调用AsyncTask子类的onPreExecute方法,用以再运行后台线程之前为其初始化相关内容。然后,在新创建的子线程中调用doInBackground()方法实现后台线程功能并通过publishProgress()方法调用onProgressUpdate()方法更新UI内容,最后在主线中执行onPostExecute方法来处理后台线程运行的结果。 注意:其中只有doInBackground()方法,以及publishProgress()方法是在子线程中执行的,其他的方法都是在主线程中执行的,所以可以在这些方法中更新界面组件。

更多相关文章

  1. 如何在后台运行Linux命令?
  2. 同程面试经历 android开发工程师
  3. 关于Android混淆的开源框架Mess的学习与分析
  4. Android压缩图片和libjpeg库
  5. Android的单线程模型
  6. 5个顶级的Android开发库
  7. Android(安卓)设计模式 之 单例模式
  8. android开关按钮
  9. Android基础入门教程——3.3 Handler消息传递机制浅析

随机推荐

  1. 【Linux】使得局域网服务器可以上外网:搭
  2. 《Linux命令行与shell脚本》笔记--第5章:
  3. 打开“保存命令历史记录时遇到错误”时的
  4. 假如你不小心干掉了系统,你该怎么办?(一次手
  5. Linux之RHEL7root密码破解(一)
  6. 在Linux下使用命令行安装DB2
  7. top命令输出详解
  8. linux socket网络编程:fcntl select(多个客
  9. Moblin: kernel编译和rpm打包(一):更换kerne
  10. Linux中断处理体系结构分析(二)