重要的话写在前面,关于线程知识的掌握,一定要看源码!一定要看源码!一定要看源码!一定要看源码!一定要看源码!
主要有三个java类之间的关系一定要理解清楚:LooperHandlerMessagesQueue,这三个类之间一一对应,看了源码才知道Google设计的精妙之处,不然写代码只知其然不知其所以然。本文先讲讲’其然’,’所以然’之后细说。


基本概念

进程(Process)是一块包含了某些资源的内存区域。
进程中所包含的一个或多个执行单元为线程(Thread)
标准的解释如上所属,但是概念很难被理解。通俗地说,进程和线程最大的区别在于,进程是一块独立的内存空间,而线程运行在公共的内存空间中。
具体来说,每个应用都至少会开辟自己的一个进程,一个进程内可以包含多个线程。重要的是,线程可以做进程做的任何任务,所以线程可以当作“轻量级”的进程。一般来说线程处理一些小任务,“重量级”的任务会交给进程。
而且,进程之间是独立的,一个进程内的多个线程是共享内存的。所以线程间就可以共同处理一块数据,线程间的通讯比进程间的通讯容易很多。
打个比方,进程就好比一棵大树,线程就是这颗树上的树枝,所有树枝共享根部提供的养分(内存)。进程是个大工厂,线程是工厂内具体进行操作的工人。

在安卓应用程序中,主线程用于接收用户的输入,以及反馈结果。因为一旦主线程阻塞,程序就会暂停运行。所以一些会产生阻塞的操作,比如从网络上下载数据,就会放在worker thread中进行。主线程之外(worker thread)不允许修改UI属性,但是processing bar除外。


从Worker Thread到Main Thread传送数据

Worker ThreadMain Thread传送数据一般用于从网络中获取数据,然后显示在界面反馈给用户。主要有三个操作步骤:

  • 继承Thread类,使用worker thread获取网络中的数据,发送message
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class MyThread extends Thread{
@Override
public void run() {
try {
Thread.sleep(2 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}

//实用s模拟网络中获取的数据
System.out.println("MyThreadMessage------>" + Thread.currentThread().getName());
String s = "Data from internet!";

Message msg = handler.obtainMessage();
msg.obj = s;
handler.sendMessage(msg);
}
}

workthread实现过程中,先休眠两秒,模拟网络中获取数据的时间开销。然后创建msg对象,把handlermsg对象相关联,s的值赋给msg,最后用handler发送消息。

  • 实现监听窗口,调用worker thread
1
2
3
4
5
6
7
8
9
10
11
12
13
class OnButtonClick implements View.OnClickListener {

@Override
public void onClick(View view) {
//当用户点击按钮时,穿件一个消息对象,并实用Handler发送该对象
System.out.println("OnClickListener");
// Message msg = handler.obtainMessage();
// msg.what = 2;
// handler.sendMessage(msg);
Thread t = new MyThread();
t.start();
}
}

当用户点击按钮时,监听器监听到这一行为,开启一个worker thread

  • 继承Handler类,实现handlemassges方法获取msg
1
2
3
4
5
6
7
8
9
10
   class MyHandler extends Handler{
@Override
public void handleMessage(Message msg) {
// int what = msg.what;
// System.out.println("What: " + what);
System.out.println("handleMessageThread------>" + Thread.currentThread().getName());
String s = (String)msg.obj;
textView.setText(s);
}
}

handler位于main thread中,故此可以修改UI为msg传过来的消息

  • 顺便附上OnCerate()方法
1
2
3
4
5
6
7
8
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.buttonId);
button.setOnClickListener(new OnButtonClick());
textView = (TextView) findViewById(R.id.textViewId);
handler = new MyHandler();
}
  • logcat中的输出
    在手机上运行程序,并点击按钮。界面中的Hello world!在两秒之后,变成Data from internet!
    logcat中输出如下:

    1
    2
    3
    19112-19112/com.cheryl.handler01 I/System.out: OnClickListener
    19112-21361/com.cheryl.handler01 I/System.out: MyThreadMessage------>Thread-642
    19112-19112/com.cheryl.handler01 I/System.out: handleMessage------>main

可见系统先是在监听器中监听到按钮被点击的行为,然后启动worker thread,最后回到main thread中修改界面。


从Main Thread到Worker Thread传送数据

  • 继承Thread类,准备Looper对象
  • Worker Thread中生成handler对象,重写handleMessage()方法
  • 调用Looper.loop()方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class WorkerThread extends Thread{
@Override
public void run() {
Looper.prepare();
System.out.println("Worker Thread");
handler = new Handler(){
// @Override
public void handleMessage(Message msg){
System.out.println("Worker thread Message received");
}
};
Looper.loop();
}
}

以上几步的使用方法在这里单独拿出来,看起来会有点别扭,但正是Google设计的巧妙之处,一个Looper对应一个handler一个msg对象。

  • ButtonLisener中用handler生成msg对象
1
2
3
4
5
6
7
8
9
10
11
class OnButtonClick implements View.OnClickListener{
@Override
public void onClick(View view) {
// MyThread t = new MyThread();
// t.start();
System.out.println("OnClickListener1");
Message msg = handler.obtainMessage();
handler.sendMessage(msg);
System.out.println("OnClickListener2");
}
}
  • OnCreate方法中启动WorkerThread
1
2
3
4
5
6
7
8
9
10
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.buttonId);
textView = (TextView) findViewById(R.id.textViewId);
WorkerThread wt = new WorkerThread();
wt.start();
button.setOnClickListener(new OnButtonClick());
}

Reference

[1] What is the difference between a process and a thread?
[2] 进程与线程的一个简单解释
[3] What is the difference between a thread and a process?