一、注意:要看懂这篇文章,前提是你已经会java可变参数和java泛型相关知识, 可变参数知识点请参考我写的博客java可变参数.
二、Android中Activity运行在主进程的主线程中,由于该线程主要用界面与用户交互,所以其线程又叫UI线程,要想更新UI(UI就是界面的意思),只能在UI线程中,一般办法去新开辟的线程中是无法更新UI的,当在UI线程中更新UI,但是使用时间操作5秒钟又要报错,为了解决更新UI而时间很长所情况,Android提供了以下几个办法,Handler更新UI;广播中更新UI;Activity runOnUiThread(Runnable run);View:post();View:postDelayed();AsyncTask。其中Handler和AsyncTask是用得最多的方式,本篇讲解AsyncTask的使用。
三、AsyncTask是抽象类,继承该类要使用泛型AsyncTask<Params, Progress, Result>,其中Params, Progress, Result是任意类名
* 泛型Params对应execute函数中的可变参数类型
* 泛型Progress对应函数publishProgress中的参数和onProgressUpdate函数中的可变参数类型
* 泛型Result对应doInBackground函数的返回值和onPostExecute函数的参数
(函数execute、函数publishProgress、函数onProgressUpdate、函数doInBackground和函数onPostExecute都是AsyncTask类的函数)
eg:
public class MyAsyncTask extends AsyncTask<Short, Integer, String>
{
........
}
* 泛型Short对应(1)execute函数中的可变参数类型
* 泛型Integer对应函数publishProgress中的参数和onProgressUpdate函数中的可变参数类型
* 泛型String对应doInBackground函数的返回值和onPostExecute函数的参数
四、
AsyncTask类有以下方法,其中doInBackground方法是抽象方法。
(1)public final AsyncTask<Params, Progress, Result> execute(Params... params):
该方法由我们自己在UI线程中调用,使用是启动AsyncTask,是该类使用的入口,方法调用后,后台会立刻回调用onPreExecute方法,注意只能在UI线程中调用execute方法。参数params会传到doInBackground方法中作为参数值
(2)protected void onPreExecute():
该方法在UI调用execute方法启动AsyncTask后立刻被回调,主要用于初始化,该方法是在UI线程中执行的,所以执行时间不能操过5秒,onPreExecute方法执行完后,后台立刻自动回调用doInBackground方法
(3)protected abstract Result doInBackground (Params... params):
该方法是在onPreExecute()执行结束后立刻被回调,该方法是在后台新开辟子线程中执行的,所以可以做长时间的工作,如网络下载。参数params接收到的值就是UI线程调用execute(Params... params)方法时传的参数值。doInBackground方法执行完后,会自动调用onPostExecute方法,doInBackground的返回值会作为onPostExecute方法参数值
(4)protected final void publishProgress (Progress... values):
该方法由我们自已手动调用,一般是在子线程中执行的doInBackground方法中调用publishProgress方法,该方法调用后,后台会在UI线程中回调onProgressUpdate (Progress... values)方法,并且publishProgress中参数值会传到onProgressUpdate方法中使用参数值,实际开发中values用于表示doInBackground方法执行的进度
(5)protected void onProgressUpdate (Progress... values)
该方法在publishProgress方法执行后,自动被回调用,该方法在UI线程中执行。一般用于更新UI,显示函数doInBackground执行的进度
(6)protected void onPostExecute (Result result)
该方法是当doInBackground方法执行完后,在UI线程中自动调用,参数接收的值是doInBackground方法的反回值
(7)public final boolean cancel (boolean mayInterruptIfRunning)
该方法由我们自己调用,该方法传参数值true调用后,再去调用isCancelled方法会得到返回值true,cancel方法与isCancelled方法配合使用,可以中断AsyncTask
(8)public final boolean isCancelled ():
一般在publishProgress函数中手动调用,用于判断AsyncTask是否被取消了。
五、举例=========================================
(1)新建项目
(2)布局文件main.xml内容为
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:id="@+id/MyTextView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="show"
android:textSize="40sp"
/>
<Button
android:id="@+id/begin"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="开始"
/>
<Button
android:id="@+id/end"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="结束"
/>
</LinearLayout>
(3)Activity子类代码为
package com.fs.activity;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity implements OnClickListener {
private TextView textView;
private Button begin, end;
private AsyncTask<Short, Integer, String> task = null;
private void init() {
this.textView = (TextView) this.findViewById(R.id.MyTextView);
this.begin = (Button) this.findViewById(R.id.begin);
this.end = (Button) this.findViewById(R.id.end);
this.begin.setOnClickListener(this);
this.end.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v == this.begin) {/*1 点始开始按钮**/
Short param1 = 0;
Short param2 = 10;
/*开启AsyncTask,该代码运行后,在UI线程中,MyAsyncTask类中的onPreExecute函数会被自动回调用*/
this.task = new MyAsyncTask().execute(param1, param2); /*2*/
} else if (v == this.end) {
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
this.init();
}
/***
* 泛型Short对应(1)execute函数中的可变参数类型
* 泛型Integer对应函数publishProgress中的参数和onProgressUpdate函数中的可变参数类型
* 泛型String对应doInBackground函数的返回值和onPostExecute函数的参数
* @author Administrator
*
*/
public class MyAsyncTask extends AsyncTask<Short, Integer, String> {
/**该函数执行完后,系统会自动开辟子线程,并在子程中自动回调用doInBackground函数**/
@Override
protected void onPreExecute() {/*3*/
Toast.makeText(MainActivity.this, "开始更新界面", Toast.LENGTH_LONG).show();
}
/**(1)当onPreExecute函数执行完后,立刻创建子线程,并回调doInBackground函数,参数params接收到的值就是前面代码this.task = new MyAsyncTask().execute(param1, param2); 中param1,和param2,该函数可以做长时间的事情
* (2)当onPreExecute函数全部执行完成后,UI线程中会自动回调onPostExecute函数,并且doInBackground函数的返回值会成为 onPostExecute函数的参数值。
* (3)由于doInBackground函数是在子线程(不是UI线程)中执行的,所以该函数不能更新UI
* */
@Override
protected String doInBackground(Short... params) {/*4*/
Short param1 = params[0];
Short param2 = params[1];
for (int i = param1; i < param2; i++) {
/*publishProgress调用后,onProgressUpdate函数在UI线程中被自动回调,并且onProgressUpdate函数接收到的参数就是param2-i但由于onProgressUpdate函数的执行是在UI线程中执行的,所以不会阻赛doInBackground函数的继续执行。*/
this.publishProgress(param2 - i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "更新完毕了!";
}
@Override
protected void onProgressUpdate(Integer... values) {
MainActivity.this.textView.setText("还差" + values[0] + "秒");
}
/**
* (1)doInBackground函数执行完成后,onPostExecute函数会被自动回调用
* (2)onPostExecute函数是在UI线程中执行的,所以可以更新UI
* (3)onPostExecute函数的参数值是doInBackground线程的返回值
*/
@Override
protected void onPostExecute(String result) {/*5*/
MainActivity.this.textView.setText(result);
}
}
}
上面项目的效果
(1)项目运行后界面显示为
(2)点击开始按钮后界面显示为,可以看到界面上方的文字在变化即:还差10秒,还差9秒,还差8秒......还差1秒,更新完毕了;
注意事项:
同一个AsyncTask类的对象只能被启动一次,就像同一个Thread类对象只能调用一次start函数启动一次一样