Android异步进程(AsyncTask)
Android异步进程在后台线程中运行,主要用于处理耗时比较长的操作,如:网络操作、文件操作等。Android操作系统规定只能在UI线程中更新界面(特殊情况,如进度条的更新可以在子线程中更新,但为了安全考虑,最好所以更新界面的操作都在UI线程中进行),所以Android提供了各种子线程和UI线程异步通信机制,如Handler的消息机制。AsyncTask也不例外,Android为AsyncTasky异步进程提供了一种用于与UI线程异步通信的机制,publishProgress()方法和onProgressUpdate()方法,该方法将在下面进行详细讲解,这里暂时不展开。下面是Android开发文档对AsyncTask进程执行过程的描述:
The 4 steps
When an asynchronous task is executed, the task goes through 4 steps:
onPreExecute()
, invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.doInBackground(Params...)
, invoked on the background thread immediately afteronPreExecute()
finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also usepublishProgress(Progress...)
to publish one or more units of progress. These values are published on the UI thread, in theonProgressUpdate(Progress...)
step.onProgressUpdate(Progress...)
, invoked on the UI thread after a call topublishProgress(Progress...)
. The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.onPostExecute(Result)
, invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
个人理解:
1.onPreExecute()方法在启动异步进程之前被调用(即UI线程调用了AsyncTask.execute()方法后立刻调用onPreExecute()),它是运行在UI线程中的,它通常被用来设置异步进程,比如显示一个进度条。由于该方法运行在UI线程中,所以在该方法中对界面进行更新的安全的。
2.doInBackground(Params...),该方法在onPreExecute()方法执行结束后被调用,它是运行在后台的(非UI线程),该方法主要用于在后台执行一些花费时间比较长的操作,该方法传入的参数将在后面详细介绍。由于该方法运行于后台,所以不能在该方法中更新界面,可以通过调用publishProgress()方法将后台运行的中间值、状态或结果传递给UI线程(UI线程通过onProgressUpdate()方法接收doInBackground()传来的参数)。
3.onProgressUpdate()方法在后台线程执行publishProgress()时被调用,它运行在UI线程,UI线程通过该方法获取后台线程的状态信息,以便实时更新界面。
4.onPostExecute(Result)方法在后台线程运行结束后被调用(即doInbackground(Progress...)方法运行结束后被调用),它的传人参数即为doInBackground的返回值。
下面通过一个简单的例子来理解一下AsyncTask的工作过程,该例子有一个进度条和按键,进度条默认下是不可见的,当用户点击按键后会调用AsyncTask的execute()方法,以下是使用AsyncTask的一般步骤:
第一步:新建一个类AsyncTaskDemo,该类继承了AsyncTask;
public class AsyncTaskDemo extends AsyncTask<Integer, Integer, String> {...}
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
MainActivity.progressBar.setVisibility(View.VISIBLE);
}
@Override
protected String doInBackground(Integer... params) {
// TODO Auto-generated method stub
for(int i=0; i<=100; i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
publishProgress(i);
}
return params[0] + "";//将execute()方法传人的整型数转换为字符串类型返回
}
@Override
protected void onProgressUpdate(Integer... values) {
int value = values[0];
// TODO Auto-generated method stub
super.onProgressUpdate(values);
MainActivity.progressBar.setProgress(value);
}
第五步:重写onPostExecute()方法;(我们在该方法中使进度条不可见,并打印doInBackground()方法返回的结果)
@Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
MainActivity.progressBar.setVisibility(View.GONE);
Log.d("Zhou", result);
}
第六步:在UI线程中实例化AsyncTaskDemo,并 调用AsyncTask类的execute()方法启动该后台线程。
asyncTaskDemo.execute(123);
关于AsyncTask的参数理解:
本文例子中AsyncTask<Integer, Integer, String>方法有三个参数,该三个参数都是可变长度的(有点像C语言中的可变参数printf(char *arg[])),其中:
第一个参数Integer为doInBackground(Integer...params)的传人参数类型,该值在UI线程调用execute()方法时传人,例如本文中execute(123),那么在doInBackground(Integer...params)方法中就可以就可以通过int value = params[0]获取该值,如果execute()传人了多个参数,就可以params[1]、params[2]、params[n]获取;
第二个参数Integer为publishProgress()方法传给onProgressUpdate()方法的参数类型,该参数类型传入的参数个数也是可变的;
第三个参数String为doInBackground()方法的返回参数类型,同时也是onPostExecute()方法的传人参数类型。
例子源码:
一、布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<ProgressBar
android:id="@+id/progressbar"
android:layout_width="fill_parent"
android:layout_height="10dp"
android:layout_below="@id/textview"
style="@android:style/Widget.ProgressBar.Horizontal"
android:visibility="gone"/>
<Button
android:id="@+id/button"
android:layout_below="@id/progressbar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Button"/>
</RelativeLayout>
二、MainActivity java代码
package com.mycode.asynctaskdemo;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
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 {
public static ProgressBar progressBar = null;
public static TextView textView = null;
private Button button = null;
private AsyncTaskDemo asyncTaskDemo = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView)findViewById(R.id.textview);
asyncTaskDemo = new AsyncTaskDemo();
progressBar = (ProgressBar)findViewById(R.id.progressbar);
button = (Button)findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
asyncTaskDemo.execute(123);
}
});
}
}
三、AsyncTaskDemo java代码
package com.mycode.asynctaskdemo;
import android.os.AsyncTask;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
public class AsyncTaskDemo extends AsyncTask<Integer, Integer, String>{
@Override
protected String doInBackground(Integer... params) {
// TODO Auto-generated method stub
for(int i=0; i<=100; i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
publishProgress(i);
}
return params[0] + "";//将execute()方法传人的整型数转换为字符串类型返回
}
@Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
MainActivity.progressBar.setVisibility(View.GONE);
Log.d("Zhou", result);
}
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
MainActivity.progressBar.setVisibility(View.VISIBLE);
}
@Override
protected void onProgressUpdate(Integer... values) {
int value = values[0];
// TODO Auto-generated method stub
super.onProgressUpdate(values);
MainActivity.progressBar.setProgress(value);
}
}
最后要注意几点:
1、AsyncTaskDemo.execute()只能在UI线程中调用,而且只能执行一次,多次执行将会出错(一些复杂的异步操作需要用Thread或Runnble来实现);
2、不用手动调用AsyncTaskDemo类的其他方法,如onPreExecute()、onPostExecute()等;