做移动应用开发,尤其是iOS和安卓,首先要有下面的认知:
在安卓里,除了用Java本身的Runnable和Thread之外,比较推荐的做法是使用下面的Handler和AsyncTask。
其实Handler本身是绑定一个消息循环Looper,主要就是发送处理消息。
默认Handler绑定就是主线程的Looper,可以利用Handler的一些特性,比用下面
//下面这两个一般用来做动画
handler.postAtTime(Runnable r, long uptimeMillis); //定时执行某个Runnable,在绑定的线程
handler.postDelayed(Runnable r, long delayMillis); //延时执行某个Runnable,在绑定的线程
//下面这两个一般用来做后台操作,对应的handler也应该绑定在线程上
handler.sendMessageAtTime(Message msg, long uptimeMillis); //定时发送消息
handler.sendMessageDelayed(Message msg, long delayMillis) //延时发送消息
那么怎么绑定Handler在线程里呢?如下,使用HandlerThread:
class MyHandler extends Handler {
MyHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
case MSG_SOMETHING_THREAD:
//do something in thread
//notify main thread to refresh UI
mainHandler.sendMessage(mainHandler.obtainMessage(MSG_SOMETHING_MAIN);
break;
}
}
};
HandlerThread ht = new HandlerThread("MyHandlerThread");
ht.start();
subHandler = new MyHandler(ht.getLooper());
mainHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
case MSG_SOMETHING_MAIN:
//do something in main thread
//e.g. update UI
break;
}
}
};
通过上面的代码,我们获得了两个Handler对象,mainHandler绑定在主线程,subHandler绑定在子线程。那么我们就可以用这两个对象相互发消息来通讯和做异步操作了。
//比如用户点击了某个按钮,要读取SD卡上的很多数据,那么就用下面的代码发subHandler消息
subHandler.sendMessage(subHandler.obtainMessage(MSG_SOMETHING_THREAD);
//在subHandler处理完后,会调用下面的代码,给mainHandler发消息,刷新UI
mainHandler.sendMessage(mainHandler.obtainMessage(MSG_SOMETHING_MAIN);
使用Handler是可以更加精确的控制,而且可以更加定制化,但是对于普通的应用来讲,只要求把一个耗时操作做成异步的,然后操作前后需要更新UI。这种典型需求,安卓提供了一个非常简单实用的类:AsyncTask。
class DownloadFilesTask extends AsyncTask {
//真正线程里执行的函数,耗时操作
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
//通知主线程,调用onProgressUpdate,刷新进度
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
//主线程,在doInBackground之前执行,可以设置显示进度条之类的UI操作
protected void onPreExecute(){
progress.setVisibility(View.VISIBLE);
}
//主线程,和doInBackground是并行的,一般更新进度
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress);
}
//主线程,在doInBackground之后进行,更新UI
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
};
//执行
new DownloadFilesTask().execute(url1, url2, url3);
由上面可以看到,AsyncTask把异步变的更加清晰和简单了,但是使用AsyncTask也有需要注意的,如下: