http://tech.it168.com/a2012/0312/1323/000001323193.shtml
android提供了一套专门用于异步处理的类。即:AynsTask类。使用这个类可以为耗时程序开辟一个新线程进行处理,处理完时返回。
其实,AsynTask类就是对Thread类的一个封装,并且加入了一些新的方法。编程时,两者都可以实现同样的功能。本文后面将对AsynTask和Thread进行比较。
1、AsynTask类结构
asysTask类主要用到的几个内部回调函数有:
doInBackGround()
onPreExecute()
onPostExecute()
onProgressUpdate()
正是这几个回调函数构成了AsynTask类的使用逻辑结构。
注意:每个AsynTask子类必须至少要重写doInBackGround()方法。
2、回调逻辑关系
1>主线程调用AsynTask子类实例的execute()方法后,首先会调用onPreExecute()方法。onPreExecute()在主线程中运行,可以用来写一些开始提示代码。
2>之后启动新线程,调用doInBackground()方法,进行异步数据处理。
3>处理完毕之后异步线程结束,在主线程中调用onPostExecute()方法。onPostExecute()可以进行一些结束提示处理。
补充:在doInBackground()方法异步处理的时候,如果希望通知主线程一些数据(如:处理进度)。这时,可以调用publishProgress()方法。这时,主线程会调用AsynTask子类的onProgressUpdate()方法进行处理。
3、各个函数间数据的传递
通过上面的调用关系,我们就可以大概看出一些数据传递关系。如下:
execute
()向
doInBackground
()传递。
doInBackground()
的返回值会传递给
onPostExecute()
。
publishProgress()
向
progressUpdate
()传递。
要点:为了调用关系明确及安全,AsynTask类在继承时要传入3个泛型。
第一个泛型对应execute()向doInBackground()的传递类型。
第二个泛型对应doInBackground()的返回类型和传递给onPostExecute()的类型。
第三个泛型对应publishProgress()向progressUpdate()传递的类型。
传递的数据都是对应类型的数组,数组都是可变长的哦。可以根据具体情况使用。
点击按钮,执行异步操作,执行过程中不断刷新显示内容。
开始界面只有一个按钮.点击按钮后,效果如下:
可以看到Progress后面的数字不停改变:
一直到变为100为止。变为100后,界面如下:
首先写一个类用来记录线程信息。方便我们跟踪调试。
package
com
.
example
.
helloAndroid;
import
android.util.Log;
public
class
LogUtils
{
private
static
final
String
TAG
=
"LogUtils";
public
static
final
void
thread()
{
LogUtils
.
thread(
null);
}
public
static
final
void
thread(
String
msg
){
Thread
t
=
Thread
.
currentThread();
Log
.
d(
TAG
,
"<"
+
t
.
getName()
+
">id: "
+
t
.
getId()
+
", Priority: "
+
t
.
getPriority()
+
", Group: "
+
t
.
getThreadGroup
().
getName()
+ (
msg
!=
null
?
",Msg:"
+
msg
:
""));
}
}
接着我们新建一个layout的xml文件。内容如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id=
"@+id/widget33"
android:layout_width=
"fill_parent"
android:layout_height=
"fill_parent"
android:orientation=
"vertical"
xmlns:android=
"http://schemas.android.com/apk/res/android"
>
<Button
android:id=
"@+id/btnNotify"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:text=
"Start"
/>
<TextView
android:id=
"@+id/txt1"
android:layout_width=
"fill_parent"
android:layout_height=
"wrap_content"
android:text=
""
/>
</LinearLayout>
现在我们建一个类用来异步处理数据:
package
com
.
example
.
helloAndroid;
import
java.util.List;
import
android.app.Activity;
import
android.content.Context;
import
android.os.AsyncTask;
import
android.widget.TextView;
public
class
Calculator
extends
AsyncTask
<
List
<
Integer
>,
Integer
,
Integer
>
{
private
static
final
String
TAG
=
"Calculator";
private
Context
context;
private
TextView
txt1;
private
Integer
nResult;
private
Integer
nProgress;
public
Calculator(
Context
context)
{
this
.
setContext(
context);
}
public
void
setContext(
Context
context)
{
this
.
context
=
context;
this
.
txt1
= (
TextView)((
Activity)
this
.
context
).
findViewById(
R
.
id
.
txt1);
this
.
progressUI();
}
//在处理完毕后,修改界面。只修改了一次界面。
public
void
syncUI
(){
//用来看调试信息
LogUtils
.
thread(
"update ui...");
//修改界面显示内容
this
.
txt1
.
setText(
"calculate ..."
+
this
.
nResult);
}
@Override
protected
Integer
doInBackground(
List
<
Integer
>...
params)
{
//用来看调试信息
LogUtils
.
thread(
"execute calculating...");
this
.
nResult
=
0;
Integer p;
for(
int
i
=
0;
i
<
params
[
0
].
size();
i
++)
{
p
=
params
[
0
].
get(
i);
//p为数字1,2,3,...10
this
.
nResult
+= p
.
intValue();
//nResult = 1+2+3+...10
LogUtils
.
thread(
"calculating..."
+
this
.
nResult);
//update progress
this
.
publishProgress(
100
* (
i
+
1
)/
params
[
0
].
size());
try
{
Thread
.
sleep(
1000);
}
catch(
InterruptedException
e)
{}
}
LogUtils
.
thread(
"completed calculator..."
+
this
.
nResult);
return
this
.
nResult;
}
@Override
protected
void
onPreExecute()
{
super
.
onPreExecute();
LogUtils
.
thread(
"before calculating...");
// 在 Main Thread 裡執行,可更新 UI
this
.
nProgress
=
0;
}
@Override
protected
void
onPostExecute(
Integer
result)
{
super
.
onPostExecute(
result);
this
.
nResult
=
result;
LogUtils
.
thread(
"calcuted result..."
+
this
.
nResult);
// 在 Main Thread 裡執行,可更新 UI
this
.
syncUI();
}
@Override
protected
void
onProgressUpdate(
Integer
...
values)
{
super
.
onProgressUpdate(
values);
this
.
nProgress
=
values
[
0
];
LogUtils
.
thread(
"Progress..."
+
this
.
nProgress);
// 在 Main Thread 裡執行,可更新 UI
this
.
progressUI();
}
//在处理过程中,数字不断改变。即不断刷新界面
private
void
progressUI()
{
//用来看调试信息
LogUtils
.
thread(
"Update Progress...");
//修改界面显示内容
this
.
txt1
.
setText(
"Progress:"
+
this
.
nProgress);
}
}
然后就是最直观的界面操作了。新建一个Activity。
public
class Test
Activity
extends
Activity
{
private
Calculator
task;
private
String
TAG
=
"AsyncTask";
@Override
public
void
onCreate(
Bundle
savedInstanceState)
{
super
.
onCreate(
savedInstanceState);
setContentView(
R
.
layout
.
main);
Log
.
d(
TAG
,
"onCreate");
// 重新連線
this
.
task
= (
Calculator)
this
.
getLastNonConfigurationInstance();
if(
this
.
task
!=
null)
{
Log
.
d(
TAG
,
"reconnect with asyncTask");
this
.
task
.
setContext(
this);
// 在 Activity 重起過程中已計算完畢,所以要呼叫 AsyncTask 來更新 UI
if(
this
.
task
.
getStatus()
==
AsyncTask
.
Status
.
FINISHED)
{
this
.
task
.
syncUI();
}
}
else
Log
.
d(
TAG
,
"task is null");
findViewById(
R
.
id
.
btnTest
).
setOnClickListener(
calculatorClick);
}
@Override
public
Object
onRetainNonConfigurationInstance
(){
// 保留 Activity 與 AsyncTask 的關聯
// 供 Activity 因故重起後,可以找回已在執行的 AsyncTask
return
this
.
task;
}
private
View
.
OnClickListener
calculatorClick
=
new
View
.
OnClickListener()
{
public
void
onClick(
View
v)
{
// TODO Auto-generated method stub
executeTask();
}
};
public
void
executeTask()
{
Log
.
d(
TAG
,
"Clicked");
if(
task
!=
null)
{
AsyncTask
.
Status
status
=
task
.
getStatus();
Log
.
d(
TAG
,
"Now status: "
+
status);
if(
status
!=
AsyncTask
.
Status
.
FINISHED)
{
//前一計算未完成,不可重起計算
Log
.
d(
TAG
,
"continue last calculating ...");
return;
}
//前一計算已完成,可重起計算
Log
.
d(
TAG
,
"completed last calculator");
}
Log
.
d(
TAG
,
"new calculator");
task
=
new
Calculator(
this);
List
<
Integer
>
params
=
new
ArrayList
<
Integer
>();
for(
int
i
=
0;
i
<
10;
i
++)
params
.
add(
i);
// 只能呼叫一次 execute(...)
task
.
execute(
params);
}
}
执行后效果如下:
5、总结
初次看到这个异步调用关系可能觉得很复杂,但其实熟悉了之后会发现这种结构很好用。这种结构将所有的线程通信都封装成回调函数,调用逻辑容易书写。
尤其是在异步处理结束之后,有回调函数进行收尾处理。
如果是使用Thread的run()方法,run()结束之后没有返回值。所以必须要自己建立通信机制。
但是,其实使用Handler+Thread机制其实完全可以替代AsynTask的这种调用机制。只要将Handler对象传给Thread,就可以进行方便的异步处理。且这种MVC模式结构更加明显,方便管理。所以我觉得,使用asynTask还是Handler+Thread结构,个人喜好吧。