Android 进阶 - Looper进程内通讯

在Android 入门 -应用启动分析一文中,我们有两处并未详细介绍,Looper进程内通讯及Binder进程间通讯。现在我们来看看Android的进程内异步通讯机制。如果你做过界面(UI)应用,不论是Win32的还是Java的UI应用,或者是iOS的UI,都会涉及前端、后端,多线程等概念。在一个线程内的程序,是从上到下顺序执行,后面的代码必须等前面的代码执行完成才可以执行。但很多时候,一个应用需要处理多个场景,最常用的就是:后台的数据处理与前端的UI显示。在Win32应用里,一个线程处理完数据后,可以post消息给主窗口线程,显示数据。Android应用借用了这种机制,当然,你可以用自己的实现方式,但既然Android已经提供了,我们就应该直接拿来使用,这就是Looper。

1、ThreadLocal线程安全机制

要了解Looper,我们需要先深入理解Java的线程本地化存储机制(TLS),即ThreadLocal。这是Java提供的,非Android独有的,可以在任何Java程序中使用。
ThreadLocal有什么作用?和本地变量有什么区别?考查下面的代码:
public class ThreadLocalTest {
	final static ThreadLocal<Object> tl = new ThreadLocal<>();

	public static void main(String[] args) {
		tl.set(0);
		new Thread(new Runnable() {

			@Override
			public void run() {
				System.out.println("thread:" + tl.get());

			}
		}).start();
		System.out.println("main: " + tl.get());
	}

}
上面的代码中,我们将tl设置为静态变量,按正常思维,在Main中set了,在Thread中get,应该是有值的。但事实上不是,thread中是get不到这个值的。这就说明,你在哪个线程set了值,就只能在哪个线程中get。
所以,ThreadLocal保存的就是线程的本地变量,这个我在Thead内new一个成员变量就行了,这不是多此一举吗?事实上不是这样的,ThreadLocal可以确保保存在线程中的变量不会被另一个线程修改,而成员变量则可以被修改,这对线程安全中防止意外访问的情况发生非常有用。下面举例说明:
import java.util.ArrayList;
import java.util.List;

class MyRunnable implements Runnable {
	// 千万别被static关键字蒙蔽了,tl可以全局使用,但tl.set,tl.get只能是当前线程使用
	final static ThreadLocal<Object> tl = new ThreadLocal<>();
	Object t;

	public MyRunnable() {
	}

	@Override
	public void run() {
		t = Math.random();
		tl.set(t);
		Object pt = null, ptl = null;
		while (Thread.currentThread().isAlive()) {
			if (pt == null || !pt.equals(t)) // 如果t变量变化
				System.out.println(this + ": t " + pt + " -> " + t);
			if (ptl == null || !ptl.equals(tl.get())) // 如果tl.get()变化
				System.out.println(this + ": tl " + ptl + "->" + tl.get());
			pt = t;
			ptl = tl.get();
		}
	}

	public String toString() {
		return Thread.currentThread().getName();
	}

	public Object getTL() {
		return tl.get();
	}

	public Object getT() {
		return t;
	}

	public void setTL(Object v) {
		tl.set(v);
	}

	public void setT(Object v) {
		t = v;
	}

}

public class ThreadLocalTest {

	public static void main(String[] args) {
		List<MyRunnable> ls = new ArrayList<MyRunnable>();
		for (int i = 0; i < 2; i++) {
			MyRunnable thread = new MyRunnable();
			ls.add(thread);
			new Thread(thread, "thread-" + i).start();
		}
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("--------");
		for (int i = 0; i < 2; i++) {
			MyRunnable thread = ls.get(i);

			thread.setT("new-" + i);
			thread.setTL("new-" + i);
		}
	}

}
上面例子的运行结果是:
thread-0: t null -> 0.5093053224347734
thread-0: tl null->0.5093053224347734
thread-1: t null -> 0.7972271387384761
thread-1: tl null->0.7972271387384761
--------
thread-0: t 0.5093053224347734 -> new-0
thread-1: t 0.7972271387384761 -> new-1
可以看到,调用thread.setT方法时,会修改线程内部的t值,但调用thread.setTL时,不会修改线程内部的tl.get()值?为什么呢?其实,thread.setTL修改的是main线程的tl.get()值,thread.setTL是在main线程中运行,不是在真正的thread中运行的,所以,ThreadLocal可以确保线程内部的变量,无论在任何情况下,不被其他线程修改,这点成员变量做不到,只要引出方法,就可以被任意修改,你必须要做同步处理。网上的资料基本未说到点子上,看的我云里雾里。

2. Looper消息机制

Looper是一个可以处理消息循环的类,任何线程都可以使用Looper,来处理消息。基本使用方法如下:
class LooperThread extends Thread {
    public Handler mHandler;

    public void run() {
        Looper.prepare();

        mHandler = new Handler() {
            public void handleMessage(Message msg) {
                // 真正的消息在这里处理
        
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值