阿里二面的时候被问到这个问题,自己答的不全,所以总结下,问题是Android多线程中UI线程怎么和其他线程进行交互?
5个方法:
1、handler
2、Activity.runOnUIThread(Runnable)
3、View.Post(Runnable)
4、View.PostDelayed(Runnabe,long)
5、AsyncTask
方法一:handler
假设A线程要传递信息给B线程,我们需要做的就是
1、在B线程中调用Looper.prepare和Looper.loop。(主线程不需要)
2、 编写Handler类,重写其中的handleMessage方法。
3、创建Handler类的实例,并绑定looper
4、调用handler的sentMessage方法发送消息。
1 public class MyHandlerActivity extends Activity {
2 TextView textView;
3 MyHandler myHandler;
4
5 protected void onCreate(Bundle savedInstanceState) {
6 super.onCreate(savedInstanceState);
7 setContentView(R.layout.handlertest);
8
9 //实现创建handler并与looper绑定。这里没有涉及looper与
//线程的关联是因为主线程在创建之初就已有looper
10 myHandler=MyHandler(MyHandlerActivitythis.getMainLooper());
11 textView = (textView) findViewById(R.id.textView);
12
13 MyThread m = new MyThread();
14 new Thread(m).start();
15 }
16
17
18 class MyHandler extends Handler {
19 public MyHandler() {
20 }
21
22 public MyHandler(Looper L) {
23 super(L);
24 }
25
26 // 必须重写这个方法,用于处理message
27 @Override
28 public void handleMessage(Message msg) {
29 // 这里用于更新UI
30 Bundle b = msg.getData();
31 String color = b.getString("color");
32 MyHandlerActivity.this.textView.setText(color);
33 }
34 }
35
36 class MyThread implements Runnable {
37 public void run() {
38 //从消息池中取出一个message
39 Message msg = myHandler.obtainMessage();
40 //Bundle是message中的数据
41 Bundle b = new Bundle();
42 b.putString("color", "我的");
43 msg.setData(b);
44 //传递数据
45 myHandler.sendMessage(msg); // 向Handler发送消息,更新UI
46 }
47 }
方法二:Activity.runOnUIThread(Runnable)
1、编写后台线程,这回你可以直接调用UI控件
2、创建后台线程的实例
3、调用UI线程对应的Activity的runOnUIThread方法,将后台线程实例作为参数传入其中。
注意:无需调用后台线程的start方法
方法三:View.Post(Runnable)
该方法和方法二基本相同,只是在后台线程中能操控的UI控件被限制了,只能是指定的UI控件View。方法如下
1、编写后台线程,这回你可以直接调用UI控件,但是该UI控件只能是View
2、创建后台线程的实例
3、调用UI控件View的post方法,将后台线程实例作为参数传入其中。
方法四:View.PostDelayed(Runnabe,long)
该方法是方法三的补充,long参数用于制定多少时间后运行后台进程
方法五:AsyncTask
AsyncTask是一个专门用来处理后台进程与UI线程的工具。
AsyncTask拥有3个重要参数
1、Params
2、Progress
3、Result
Params是后台线程所需的参数。在后台线程进行作业的时候,他需要外界为其提供必要的参数,就好像是一个用于下载图片的后台进程,他需要的参数就是图片的下载地址。
Progress是后台线程处理作业的进度。依旧上面的例子说,就是下载图片这个任务完成了多少,是20%还是60%。这个数字是由Progress提供。
Result是后台线程运行的结果,也就是需要提交给UI线程的信息。按照上面的例子来说,就是下载完成的图片。
AsyncTask还拥有4个重要的回调方法。
1、onPreExecute
2、doInBackground
3、onProgressUpdate
4、onPostExecute
onPreExecute运行在UI线程,主要目的是为后台线程的运行做准备。当他运行完成后,他会调用doInBackground方法。
doInBackground运行在后台线程,他用来负责运行任务。他拥有参数Params,并且返回Result。在后台线程的运行当中,为了能够更新作业完成的进度,需要在doInbackground方法中调用PublishProgress方法。该方法拥有参数Progress。通过该方法可以更新Progress的数据。然后当调用完PublishProgress方法,他会调用onProgressUpdate方法用于更新进度。
onProgressUpdate运行在UI线程,主要目的是用来更新UI线程中显示进度的UI控件。他拥有Progress参数。在doInBackground中调用PublishProgress之后,就会自动调onProgressUpdate方法
onPostExecute运行在UI线程,当doInBackground方法运行完后,他会调用onPostExecute方法,并传入Result。在onPostExecute方法中,就可以将Result更新到UI控件上。
AsyncTask使用方法:
1、编写一个继承AsyncTask的类,并声明3个参数的类型,编写4个回调方法的内容。
2、然后在UI线程中创建该类(必须在UI线程中创建)。
3、最后调用AsyncTask的execute方法,传入Parmas参数(同样必须在UI线程中调用)。