Handler的初级、中级、高级问法,2021年Android常见面试题

本文详细介绍了Android中Handler的工作原理,包括主线程Looper、子线程如何更新UI、消息处理顺序、内存泄漏问题及解决方案、ThreadLocal与内存泄漏的关系、epoll机制在Handler中的应用以及Handler的同步屏障机制。通过分析源码,揭示了Handler如何进行线程切换和消息分发,以及在面试中常见的问题和应用场景。
摘要由CSDN通过智能技术生成

可以看到在Looper.prepareMainLooper()方法中创建了当前线程的Looper,同时将Looper实例存放到线程局部变量sThreadLocal(ThreadLocal)中,也就是每个线程有自己的Looper。在创建Looper的时候也创建了该线程的消息队列,可以看到prepareMainLooper会判断sMainLooper是否有值,如果调用多次,就会抛出异常,所以也就是说主线程的Looper和MessageQueue只会有一个。同理子线程中调用Looper.prepare()时,会调用prepare(true)方法,如果多次调用,也会抛出每个线程只能由一个Looper的异常,总结起来就是每个线程中只有一个Looper和MessageQueue。

//Looper.java

private Looper(boolean quitAllowed) {

mQueue = new MessageQueue(quitAllowed);

mThread = Thread.currentThread();

}

再来看看主线程sMainThreadHandler = thread.getHandler(),getHandler获取到的实际上就是mH这个Handler。

//ActivityThread.java

final H mH = new H();

@UnsupportedAppUsage

final Handler getHandler() {

return mH;

}

mH这个Handler是ActivityThread的内部类,通过查看handMessage方法,可以看到这个Handler处理四大组件,Application等的一些消息,比如创建Service,绑定Service的一些消息。

//ActivityThread.java

class H extends Handler {

···

public void handleMessage(Message msg) {

if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));

switch (msg.what) {

case BIND_APPLICATION:

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “bindApplication”);

AppBindData data = (AppBindData)msg.obj;

handleBindApplication(data);

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

break;

case EXIT_APPLICATION:

if (mInitialApplication != null) {

mInitialApplication.onTerminate();

}

Looper.myLooper().quit();

break;

case RECEIVER:

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “broadcastReceiveComp”);

handleReceiver((ReceiverData)msg.obj);

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

break;

case CREATE_SERVICE:

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));

handleCreateService((CreateServiceData)msg.obj);

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

break;

case BIND_SERVICE:

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “serviceBind”);

handleBindService((BindServiceData)msg.obj);

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

break;

case UNBIND_SERVICE:

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “serviceUnbind”);

handleUnbindService((BindServiceData)msg.obj);

schedulePurgeIdler();

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

break;

case SERVICE_ARGS:

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceStart: " + String.valueOf(msg.obj)));

handleServiceArgs((ServiceArgsData)msg.obj);

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

break;

case STOP_SERVICE:

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “serviceStop”);

handleStopService((IBinder)msg.obj);

schedulePurgeIdler();

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

break;

···

case APPLICATION_INFO_CHANGED:

mUpdatingSystemConfig = true;

try {

handleApplicationInfoChanged((ApplicationInfo) msg.obj);

} finally {

mUpdatingSystemConfig = false;

}

break;

case RUN_ISOLATED_ENTRY_POINT:

handleRunIsolatedEntryPoint((String) ((SomeArgs) msg.obj).arg1,

(String[]) ((SomeArgs) msg.obj).arg2);

break;

case EXECUTE_TRANSACTION:

final ClientTransaction transaction = (ClientTransaction) msg.obj;

mTransactionExecutor.execute(transaction);

if (isSystem()) {

// Client transactions inside system process are recycled on the client side

// instead of ClientLifecycleManager to avoid being cleared before this

// message is handled.

transaction.recycle();

}

// TODO(lifecycler): Recycle locally scheduled transactions.

break;

case RELAUNCH_ACTIVITY:

handleRelaunchActivityLocally((IBinder) msg.obj);

break;

case PURGE_RESOURCES:

schedulePurgeIdler();

break;

}

Object obj = msg.obj;

if (obj instanceof SomeArgs) {

((SomeArgs) obj).recycle();

}

if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));

}

}

最后我们查看Looper.loop()方法

//Looper.java

public static void loop() {

//获取ThreadLocal中的Looper

final Looper me = myLooper();

···

final MessageQueue queue = me.mQueue;

···

for (;😉 { //死循环

//获取消息

Message msg = queue.next(); // might block

if (msg == null) {

// No message indicates that the message queue is quitting.

return;

}

···

msg.target.dispatchMessage(msg);

···

//回收复用

msg.recycleUnchecked();

}

}

在loop方法中是一个死循环,在这里从消息队列中不断的获取消息queue.next(),然后通过Handler(msg.target)进行消息的分发,其实并没有什么具体的绑定,因为Handler在每个线程中对应只有一个Looper和消息队列MessageQueue,自然要靠它来处理,也就是是调用Looper.loop()方法。在Looper.loop()的死循环中不断的取消息,最后回收复用

这里要强调一下Message中的参数target(Handler),正是这个变量,每个Message才能找到对应的Handler进行消息分发,让多个Handler同时工作

再来看看子线程中是如何处理的,首先在子线程中创建一个Handler并发送Runnable

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_three);

new Thread(new Runnable() {

@Override

public void run() {

new Handler().post(new Runnable() {

@Override

public void run() {

Toast.makeText(HandlerActivity.this,“toast”,Toast.LENGTH_LONG).show();

}

});

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值