一、引子
android中新手比较容易犯的一种错误就是界面响应消息阻塞超时。亦即当界面消息在5秒钟内没有完成响应,android系统将自动判断对应activity已无响应,从而系统报错。
下面来看一个简单的例子
该按键的响应逻辑为使UI线程休眠10秒,那么当我按了一下按键后再按一下按键,第二次按键在5秒后还没有被响应,所以应用程序报错了。
代码如下:
例1:
public class TimeOutActivity extends Activity { Button mButton; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.time_out_activity); mButton = (Button) findViewById(R.id.btn_timeout); mButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { try { TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.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() { @Override public 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() { @Override public void run() { for(int i = 1 ; i <= 1000 ; i++) for(int j=1 ; j <= 10000 ; j++); mHandler.sendMessage(mHandler.obtainMessage(OPER_RESAULT, "第" + (++time) + "次运算")); } }; @Override protected 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() { @Override public void onClick(View v) { Thread mThread = new Thread(operation); mThread.start(); } }); } }
二、初窥Async Task
由于后台线程的管理以及对应handler逻辑的维护往往也会比较繁琐,所以android提供了一个异步工具类AsyncTask。它使得UI thread的使用变得异常简单。它使创建需要与用户界面交互的长时间运行的任务变得更简单,不需要借助线程和Handler即可实现。
根据google关于AsyncTask的参考文档可知,一个AsyncTask的工作流程图如下
所以我们在使用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() { @Override public void onClick(View v) { new Operation().execute(); } }); } class Operation extends AsyncTask { @Override protected Object doInBackground(Object... params) { for(int i = 1 ; i <= 1000 ; i++) for(int j=1 ; j <= 10000 ; j++) ; return null; } @Override protected 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将会变得非常简便。
本文中所有代码均能在以下地址下载: