Android中使用Handler和异步任务(AsyncTack)来为UI线程执行费时操作

时间:2022-08-27 15:28:51

出于性能优化的考虑,Android的UI线程不是线程安全的。这致使我们不能在Android的UI线程中执行一些费时的操作,如下载、刷新等。Android中只允许UI线程对Activity中的UI组件进行修改。

不过我们可以新建一条线程来代替UI线程执行这一操作,在Android中可以借助于Handler的消息传递机制来实现。

Handler类的两个主要作用:

1)在新启的线程中发送消息;

2)在主线程中获取和处理消息。

我们利用Handler的这两个作用,可以先在主线程中新建一条新的辅助线程,并且在这条新的线程中执行发送消息。这个消息就是我们通知系统,说现在需要更新UI界面了。如下:

new Timer().schedule(new TimerTask() {
@Override
public void run() {
handler.sendEmptyMessage(0x1233);
}
}, 0, 1000);

上面的代码重写了Handler的sendMessage(Message msg),不过在这里使用的是sendEmptyMessage(int what),因为这里只是通知主线程更新界面,没有过多的其他操作,所以只需要发送一条空的消息即可。若是更新的内容比较多或是一些其它的限制不能只发送一条空消息就能解决,那就应该发送一些有实质内容的东西,而这咱消息内容是Object的类型。对于Object这种类型的消息,是一个很宽泛的类型,它能装载的内容太多了。这个时候需要使用sendMessage(Message msg)。废话有点多,见谅。。。

那么当主线程拿到这条消息时,就会对其进行处理:

Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 0x1233) {
((ImageView) findViewById(R.id.imageView1)).setImageResource(imageId[(currentImg++) % imageId.length]);
}
}
};
以上就是简单地使用Handler来处理UI线程不安全问题。具体的代码实现还有不发送空消息来更新界面的代码以及AsyncTask的代码,我会在下面的给出连接。

-------------------------------------------------------------------------------------------------------------------------------------------------------

下面我们再来看看异步任务(AsyncTask)的简单用例。

使用AsyncTask需要有如下三个步骤:

1)创建AsyncTask的子类,并为其三个泛型参数指定类型。如果某个泛型参数不需要指定类型,则用void代替;

2)根据需要,实现AsyncTask的以下几个方法:

Ⅰ.doInBackground(Params...)这个方法,就是AsyncTask子类执行异步任务内容的方法;

Ⅱ.onProgressUpdate(Progress...)这个方法,会在执行完上一个方法后,被调用;

Ⅲ.onPreExecute()这个方法会在我们执行费时操作之前被调用,用于处理一些准备工作,如初始进度条什么的;

Ⅳ.onPostExecute()当doInBackground()执行完成之后,系统会自动调用该方法,并把doInBackground()执行的结果返回给该方法。

3)最后一步就是,我们在主线程中调用AsyncTask实例的execute(Params ... param)方法,表示开始执行费时操作。

如下代码:

class DownTask extends AsyncTask<URL, Integer, String> {
// 可变长的输入参数,与AsyncTask.exucute()对应
ProgressDialog pdialog;
// 定义记录已经读取行的数量
int hasRead = 0;
Context mContext;

public DownTask(Context ctx) {
mContext = ctx;
}

@Override
protected void onPreExecute() {
pdialog = new ProgressDialog(mContext);
pdialog.setTitle("任务正在执行中");
pdialog.setMessage("任务正在执行中,敬请等待...");
// 设置对话框不能用“取消”按钮关闭
pdialog.setCancelable(false);
// 设置该进度条的最大进度值
pdialog.setMax(202);
// 设置对话框的进度条风格
pdialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
// 设置对话框的进度条是否显示进度
pdialog.setIndeterminate(false);
pdialog.show();
}

@Override
protected String doInBackground(URL... params) {
StringBuilder sb = new StringBuilder();
try {
URLConnection conn = params[0].openConnection();
// 打开conn连接对应的输入流,并将它包装成BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(
conn.getInputStream(), "utf-8"));
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
hasRead++;
publishProgress(hasRead);
}
return sb.toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

@Override
protected void onProgressUpdate(Integer... values) {
// 更新进度
show.setText("已经读取了【" + values[0] + "】行!");
pdialog.setProgress(values[0]);
}

@Override
protected void onPostExecute(String result) {
// 返回HTML页面的内容
show.setText(result);
pdialog.dismiss();
}
}

关于Handler和AsyncTack的使用就简单介绍到这里。 本篇博客主要参考资料是《疯狂Android讲义》第3章内容。

----------------------------------------------------------点击进行源码的下载连接 -----------------------------------------------------------