在Android系统里的线程分为有消息循环的线程和没有消息循环的线程。我们上一节介绍的应用程序主线程就是一个有消息循环的线程,而通过直接继承Thread类的线程是没有消息循环的线程,当然我们也可以通过在线程里调用Looper.prepare(),让系统为该线程建立一个消息队列。
下面我们介绍两种常用的多线程方式。
11.3.1 Thread
通过继承Thread类进行多线程编程是最简单的方式之一。
其基本步骤如下。
(1)继承Thead类生成其子类,并实现其run()方法,该方法就是我们需要线程完成其功能的地方,例如在run()里进行网上图片的下载。
(2)在活动Activity里相应的地方实例化Thread子类并调用start()运行线程。
(3)在线程运行过程中如果需要更新UI,则通过Activity的handler发送消息给主线程。
下面是线程示例。
Threadtest.java
1. class Threadtest extends Activity {
2. Handler handler = new Handler(){
3. @Override
4. public void handleMessage( Message msg ){
5. if( msg.what == 0 ){
6. msg.getData();
7. //update ui
8. }
9. }
10. };
在第2~10行,定了一个handler的消息处理函数,该handler直接绑定到主线程的消息循环上。当其他线程通过handler的sendMessage发送消息给主线程后,主线程的消息循环会派发消息给handleMessage函数处理消息,我们就在此处根据消息msg传来的数据进行相应的UI操作等动作。
11. public void onCreate(Bundle savedInstanceState) {
12. super.onCreate(savedInstanceState);
13. ...
14. t = new myThread();
15. t .start();
16. }
第14~15行是在Activity里实例化myThread类并运行。
17. class myThread extends Thread{
18. public void run() {
19. ...
20. Message msg = new Message();
21. msg.what = 0;
22. Bundle data=new Bundle();
23. ...
24. message.setData(data);
25. handler.sendMessage(msg);
26. }}}
第17~25行,我们的myThread继承自Thread,并实现了run()函数,在run()里进行相应的操作,例如去网上下载图片、MP3等。当完成任务后,我们通过构造一个新消息msg,把运行结果等数据放入msg,并通过上面的handler把消息发送给主线程。至此线程完成功能。
这个例子是个逻辑示例,在第2~10行,定了一个handler的消息处理函数,该handler直接绑定到主线程的消息循环上。当其他线程通过handler的sendMessage发送消息给主线程后,主线程的消息循环会派发消息给handleMessage函数处理消息,我们就在此处根据消息msg传来的数据进行相应的UI操作等动作。
第17~25行,我们的myThread继承自Thread,并实现了run()函数,在run()里进行相应的操作,例如去网上下载图片、MP3等。当完成任务后,我们通过构造一个新消息msg,把运行结果等数据放入msg,并通过上面的handler把消息发送给主线程。至此线程完成功能。
第14~15行是在Activity里实例化myThread类并运行。
11.3.2 AsyncTask
AsyncTask也是实现多线程的一种常用方式,它封装了一些方法方便我们维护线程,并可以解决一些线程安全问题。通过继承AsyncTask类来进行多线程编程,将使得UI thread编程变得非常简单。它不需要借助Handler即可实现UI更新。
其基本步骤如下。
(1)继承AsyncTask生成子类。
(2)实现AsyncTask中定义的下面一个或几个方法。
onPreExecute():该方法将在执行实际的后台操作前被主线程调用,我们可以在该方法中做一些准备工作。
doInBackground(Params...):将在onPreExecute方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些很耗时的后台计算工作。可以调用publishProgress方法来更新实时的任务进度。该方法是子类必须实现的。
onProgressUpdate(Progress...):在publishProgress方法被调用后,主线程将调用这个方法从而在界面上展示任务的进展情况。
onPostExecute(Result):在doInBackground 执行完成后。onPostExecute 方法将被主线程调用,后台的计算结果将通过该方法传递到主线程。
这4个方法都不能手动调用,而且除了doInBackground(Params...)方法,其余3个方法都是被主线程所调用的,所以要求AsyncTask的实例必须在主线程中创建,AsyncTask.execute方法必须在主线程中调用。
下面是一个自定义AsyncTask类的示例。
1. class MyAsyncTask extends AsyncTask {
2. public MyAsyncTask(Activity mActivity) {
3. super();
4. //初始化工作;
5. }
第2~5行是类的构造函数,我们可以通过此函数传递上下文等资源。
6. @Override
7. protected void onPreExecute() {
8. //准备工作,主线程中执行
9. super.onPreExecute();
10. }
第7~10行onPreExecute函数,进行准备工作。
11. @Override
12. protected Object doInBackground(Object... params) {
13. //执行后台操作,即另外的线程中执行
14. return new Object();
15. }
第11~15行doInBackground是后台线程部分,具体执行我们所需要做的工作代码。
16. @Override
17. protected void onPostExecute(Object result) {
18. //doInBackground执行完进入该方法中,此时又回到主线程中
19. }
第16~19行onPostExecute是执行完成后数据反馈部分。
20. }
第2~5行是类的构造函数,我们可以通过此函数传递上下文等资源。
第7~10行onPreExecute函数,进行准备工作。
第11~15行doInBackground是后台线程部分,具体执行我们所需要做的工作代码。
第16~19行onPostExecute是执行完成后数据反馈部分。