Android异步任务框架AsyncTask由潜入深

来源:互联网 发布:linux nanosleep使用 编辑:程序博客网 时间:2024/05/17 02:36

一、引子

android中新手比较容易犯的一种错误就是界面响应消息阻塞超时。亦即当界面消息在5秒钟内没有完成响应,android系统将自动判断对应activity已无响应,从而系统报错。

下面来看一个简单的例子

                                      


该按键的响应逻辑为使UI线程休眠10秒,那么当我按了一下按键后再按一下按键,第二次按键在5秒后还没有被响应,所以应用程序报错了。

代码如下:


例1:

public class TimeOutActivity extends Activity {Button mButton;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.time_out_activity);mButton = (Button) findViewById(R.id.btn_timeout);mButton.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {try {TimeUnit.SECONDS.sleep(10);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}});}}


所以往往我们在编写UI后台的响应逻辑时,往往需要启动一个后台的线程来进行复杂好使的处理。
通常我们会使用Thread和header来帮组我们解决该问题。

如下例

例2:

public class UIHandlerActivity extends Activity {private static final int OPER_RESAULT = 0x01;private Button btn_start;private static int time = 0;private TextView tv_resault;private Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch(msg.what) {case OPER_RESAULT:String resault = (String) msg.obj;tv_resault.setText(resault);break;}}};private Runnable operation = new Runnable() {@Overridepublic void run() {for(int i = 1 ; i <= 1000 ; i++) for(int j=1 ; j <= 10000 ; j++);mHandler.sendMessage(mHandler.obtainMessage(OPER_RESAULT, "第" + (++time) + "次运算"));}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.ui_handler_activity);btn_start = (Button) findViewById(R.id.btn_timeout);tv_resault = (TextView) findViewById(R.id.tv_resault);btn_start.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Thread mThread = new Thread(operation);mThread.start();}});}}

二、初窥Async Task

由于后台线程的管理以及对应handler逻辑的维护往往也会比较繁琐,所以android提供了一个异步工具类AsyncTask。它使得UI thread的使用变得异常简单。它使创建需要与用户界面交互的长时间运行的任务变得更简单,不需要借助线程和Handler即可实现。 

根据google关于AsyncTask的参考文档可知,一个AsyncTask的工作流程图如下

2

所以我们在使用AsyncTask时不用关系UI线程阻塞的问题。
我们使用AsycnTask只需要
1)实现doInBackground()接口并将我们需要的计算放在我们实现的doInBackground()方法中。
2)继承onPostExecute()方法并将根据计算结果对应UI的操作放在实现的onPostExecute()方法中。

下面我使用AsyncTask实现上面的例子:

例3:

public class AsyncTaskDemoActivity extends Activity {private Button btn_start;private TextView tv_resault;private static int time = 0;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.ui_handler_activity);                btn_start = (Button) findViewById(R.id.btn_timeout);tv_resault = (TextView) findViewById(R.id.tv_resault);btn_start.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {new Operation().execute();}});    }        class Operation extends AsyncTask {@Overrideprotected Object doInBackground(Object... params) {for(int i = 1 ; i <= 1000 ; i++) for(int j=1 ; j <= 10000 ; j++);return null;}@Overrideprotected void onPostExecute(Object result) {tv_resault.setText( "第" + (++time) + "次运算");}        }}

但是我们使用的时候应该注意以下几个问题:

1)   Task的实例 必须在UI thread中创建 

2)   execute方 法必须在UI thread中调用 

3)   不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法 

4)   该task只能被执行一次,否则多次调用时将会出现异常


注意这几点后,使用AsyncTask将会变得非常简便。



本文中所有代码均能在以下地址下载:


例1-3下载