赞
踩
概述 | |
---|---|
EventHandler | EventHandler是HarmonyOS用于处理线程间通信的一种机制,一种用户在当前线程上投递InnerEvent事件或者Runnable任务到异步线程上处理的机制,可以通过EventRunner创建新线程,将耗时的操作放到新线程上执行。 |
Handler | Handler是Android中通过线程中的消息队列发送和处理Message或Runnable对象的消息机制。 |
初看EventHandler,很容易联想到Eventbus和Handler,这里InnerEvent其实相当于Android中Handler的Message,所以两者的概述差别不大。
关于两者的定义,相关官方文档中也没有说得很清晰,实际中也不容易说清楚,因为两者的作用太过重要,而定义的存在感没那么高,开发者理解不同,对其定义也就不同,但消息机制的作用则不容忽视:
作用 | |
---|---|
EventHandler | 1. 在不同线程间分发和处理InnerEvent事件或Runnable任务。2.延迟处理InnerEvent事件或Runnable任务。 |
Handler | 1. 执行定时任务 。2.在不同线程中执行任务 |
两者的作用基本相同。当有耗时任务的时候,在主线程中创建子线程,在子线程中做耗时操作,当子线程任务执行完后将结果通过消息机制反馈到主线程中,主线程更新UI。来回切换线程是因为:
EventHandler和Handler运行机制如上图所示:
如果开发者需要切换线程,在不同线程中通信,通常会使用EventHandler或Handler,具体使用如下:
public class HMEventHandler extends EventHandler {
public HMEventHandler(EventRunner runner) throws IllegalArgumentException {
super(runner);
}
@Override
protected void processEvent(InnerEvent event) {
super.processEvent(event);
int id = event.eventId;
long param = event.param;
...
}
}
创建完子类后,在processEvent方法中通常根据event的id消息的来源,根据消息的来源或类型的不同做出相对应的处理。关于EventHandler的创建方式,源代码中关于构造只给出了一个方法:
public class EventHandler {
public EventHandler(EventRunner runner) throws IllegalArgumentException {
throw new RuntimeException("Stub!");
}
...
}
因此要使用EventHandler只有这一种方法,估计这样设计是为了便于消息和线程管理。new EventHandler的时候需要EventRunner对象,所以需要提前创建EventRunner对象:
EventRunner runner = EventRunner.create(false);
EventRunner.create方法中还需要传Boolean类型的值,因为EventRunner的工作模式可以分为托管模式和手动模式。false为手动模式:需要开发者自行调用EventRunner的run()方法和stop()方法来确保线程的启动和停止。true为托管模式:不需要开发者调用run()和stop()方法去启动和停止EventRunner。当EventRunner实例化时,系统调用run()来启动EventRunner;当EventRunner不被引用时,系统调用stop()来停止EventRunner,相当于自动模式。
创建完EventRunner,在使用前还是需要判空:
if (runner == null) {
return;jianzhuang
}
...
判空是因为创建EventRunner可能失败,如创建线程失败时,创建EventRunner失败。只要是Java,在使用对象前基本都需要判空,否则容易出现空指针异常等错误,这估计是Java最大的劣势之一,也成了判断程序健壮性和编写水平高低的标准之一。最终将runner传入,一个EventHandler对象才算创建完毕:
HMEventHandler mHandler = new HMEventHandler(runner);
如果感觉步骤繁琐,可以使用内部类。内部类可能导致程序混乱、重用率低、效率低、容易泄露等问题,根据个人习惯来吧。
int eventId1 = 0;
long param = 0;
Object object = null;
InnerEvent event1 = InnerEvent.get(eventId1, param, object);
消息的创建方式有多种:
public final class InnerEvent implements Sequenceable { ... public static InnerEvent get() { throw new RuntimeException("Stub!"); } public static InnerEvent copyFrom(InnerEvent oldInnerEvent) throws CloneNotSupportedException { throw new RuntimeException("Stub!"); } public static InnerEvent get(int eventId, long param, Object object) { throw new RuntimeException("Stub!"); } public static InnerEvent get(int eventId) { throw new RuntimeException("Stub!"); } ... }
从上述代码中不难发现创建的消息可以是空消息,复制的消息,只要有eventId的其他的可有可无的消息。具体消息体是什么样的却决于实际需要。
Runnable task1 = new Runnable() {
@Override
public void run() {
...// 任务
}
};
具体任务开发者自定义。
mHandler.sendEvent(event1, 0, EventHandler.Priority.IMMEDIATE);
Priority是消息的优先级,优先级分为四种:
public static enum Priority {
IMMEDIATE,
HIGH,
LOW,
IDLE;
...
}
属性 | 描述 |
---|---|
Priority.IMMEDIATE | 立即投递 |
Priority.HIGH | 先于LOW优先级投递 |
Priority.LOW | 优于IDLE优先级投递,事件的默认优先级是LOW |
Priority.IDLE | 在没有其他事件的情况下,才投递该事件 |
发送InnerEvent的形式有多种:
public class EventHandler {
...
public void sendEvent(InnerEvent event, long delayTime, EventHandler.Priority priority) throws IllegalArgumentException {
throw new RuntimeException("Stub!");
}
...
public void sendEvent(int eventId) throws IllegalArgumentException {
throw new RuntimeException("Stub!");
}
...
public void sendEvent(int eventId, long delayTime, EventHandler.Priority priority) throws IllegalArgumentException {
throw new RuntimeException("Stub!");
}
...
}
根据上述代码可以看出消息的优先级, 是否延时,延时时长可灵活配置,实际使用视具体情况而定。
mHandler.postTask(task1,0, EventHandler.Priority.IMMEDIATE);
同样postTask的形式也是多样的:
... public void postTask(Runnable task, long delayTime, EventHandler.Priority priority) throws IllegalArgumentException { throw new RuntimeException("Stub!"); } public void postTask(Runnable task) throws IllegalArgumentException { throw new RuntimeException("Stub!"); } public void postTask(Runnable task, long delayTime) throws IllegalArgumentException { throw new RuntimeException("Stub!"); } public void postTask(Runnable task, EventHandler.Priority priority) throws IllegalArgumentException { throw new RuntimeException("Stub!"); } ...
runner.run(); // 启动EventRunner
...
runner.stop();// 停止EventRunner
除了启动和停止,EventHandler还有其他功能:
...
public void sendEvent(int eventId, long delayTime, EventHandler.Priority priority) throws IllegalArgumentException {
throw new RuntimeException("Stub!");
}
...
public void postSyncTask(Runnable task, EventHandler.Priority priority) throws IllegalArgumentException {
throw new RuntimeException("Stub!");
}
...
...
public void sendTimingEvent(InnerEvent event, long taskTime, EventHandler.Priority priority) throws IllegalArgumentException {
throw new RuntimeException("Stub!");
}
...
public void postTimingTask(Runnable task, long taskTime, EventHandler.Priority priority) throws IllegalArgumentException {
throw new RuntimeException("Stub!");
}
...
public void removeAllEvent() {
throw new RuntimeException("Stub!");
}
...
public void removeEvent(int eventId, long param, Object object) {
throw new RuntimeException("Stub!");
}
...
具体功能还有详细的划分,如果需要仔细了解,请查看EventHandler.class源码或参考HarmonyOS开发文档。
... @Deprecated public Handler() { this(null, false); } @Deprecated public Handler(@Nullable Callback callback) { this(callback, false); } public Handler(@NonNull Looper looper) { this(looper, null, false); } public Handler(@Nullable Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread " + Thread.currentThread() + " that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; } @UnsupportedAppUsage public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) { ... } ...
相对于EventHandler,Handler的构造方法比较丰富,创建方法也是多种多样。一般比较简单的使用方式是使用无参的构造方法:
private Handler mHandler = new Handler(){
{
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if(msg.what == 1){
...
}
}
};
消息逻辑处理在handleMessage方法中进行。如果Handler的创建是在主线程中创建的,这样写是没有问题的,但是如果Handler的创建是在子线程中创建,这样写就会抛出"Cant`t create handler inside thread that has not called Looper.prepare()"异常,因为在主线程中默认实现了 Looper.prepare(),而子线程中没有,所以在子线程中使用要加上 Looper.prepare():
Looper.prepare();
Handler mHandler = new Handler();
Looper.loop();
只有这样才算是开启了消息循环机制,才能查看消息,处理消息,完成消息通讯。当然Looper中还有其他比较有用的方法,比如:
Looper.getMainLooper();
Looper.myLooper();
通过 Looper.getMainLooper()可以在任何地方获取主线程的Looper。通过Looper.myLooper()则获取当前线程的Looper。建议在不需要的时候终止Looper,有两种方案供选择:
Looper.getMainLooper().quit();
Looper.getMainLooper().quitSafely();
使用quit()是直接退出Looper,而quitSafely()是等当前的消息队列中的消息都处理完毕后才会安全退出。在子线程中如果创建了Looper,那么在所有消息都处理完后应该调用quit()终止消息循环,否则这个子线程会一直处于等待状态会造成消息阻塞,因为之前开启消息循环调用loop()是一个死循环,结束死循环的唯一方法就是MessageQueue的next方法(查看是否有新的消息返回)返回了null,当Looper退出后,Handler发送消息时调用send()会返回false,Handler发送消息就会失败,此时next()就会返回null,否在会一直阻塞在那里,具体代码如下:
public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } if (me.mInLoop) { Slog.w(TAG, "Loop again would have the queued messages be executed" + " before this one completed."); } me.mInLoop = true; final MessageQueue queue = me.mQueue; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); // Allow overriding a threshold with a system prop. e.g. // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start' final int thresholdOverride = SystemProperties.getInt("log.looper." + Process.myUid() + "." + Thread.currentThread().getName() + ".slow", 0); boolean slowDeliveryDetected = false; for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } // Make sure the observer won't change while processing a transaction. final Observer observer = sObserver; final long traceTag = me.mTraceTag; long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs; long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs; if (thresholdOverride > 0) { slowDispatchThresholdMs = thresholdOverride; slowDeliveryThresholdMs = thresholdOverride; } final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0); final boolean logSlowDispatch = (slowDispatchThresholdMs > 0); final boolean needStartTime = logSlowDelivery || logSlowDispatch; final boolean needEndTime = logSlowDispatch; if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0; final long dispatchEnd; Object token = null; if (observer != null) { token = observer.messageDispatchStarting(); } long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid); try { msg.target.dispatchMessage(msg); if (observer != null) { observer.messageDispatched(token, msg); } dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0; } catch (Exception exception) { if (observer != null) { observer.dispatchingThrewException(token, msg, exception); } throw exception; } finally { ThreadLocalWorkSource.restore(origWorkSource); if (traceTag != 0) { Trace.traceEnd(traceTag); } } if (logSlowDelivery) { if (slowDeliveryDetected) { if ((dispatchStart - msg.when) <= 10) { Slog.w(TAG, "Drained"); slowDeliveryDetected = false; } } else { if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery", msg)) { // Once we write a slow delivery log, suppress until the queue drains. slowDeliveryDetected = true; } } } if (logSlowDispatch) { showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg); } if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } msg.recycleUnchecked(); } }
当MessageQueue的next()返回新的消息,msg.target.dispatchMessage(msg)就会将消息切换到创建Handler时使用的Looper中去处理。关于MessageQueue的工作原理和源码就不解释了,虽然MessageQueue叫消息队列,但是实际上是通过单链表的数据结构来维护消息队列。
Message message = new Message();
message.what = ...;
message.obj = ...;
Message长相如下:
public final class Message implements Parcelable {
...
public int what;
public int arg1;
public int arg2;
public Object obj;
public Messenger replyTo;
...
}
通常我们会使用what属性来标记消息的来源,what和InnerEvent的eventId基本是一个意思,都是识别消息,然后让开发者进行消息处理,如果一个what无法识别,可以再添加arg1、arg2帮助识别。obj就是我们需要传递的具体消息内容,如果没有内容,可以不传。Messenger就是可以跨进程的信使,详细使用这里就不解释了。
Runnable runnable = new Runnable() {
@Override
public void run() {
...
}
};
run()中一般是具体消息处理的实现。
mHandler.sendMessage(messag);
发送消息也有其他的形式:
public final boolean sendMessage(@NonNull Message msg) {
...
}
public final boolean sendEmptyMessage(int what)
{
...
}
...
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
...
}
public final boolean sendMessageAtFrontOfQueue(@NonNull Message msg) {
...
}
关于消息是否是空消息,是否延时,是否定时,是否先执行,Handler中都给出了选择,开发者可根据实际需要自由组合。
mHandler.post(runnable);
发送runnable形式也不止一种:
public final boolean post(@NonNull Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) { return sendMessageAtTime(getPostMessage(r), uptimeMillis); } public final boolean postAtTime( @NonNull Runnable r, @Nullable Object token, long uptimeMillis) { return sendMessageAtTime(getPostMessage(r, token), uptimeMillis); } ... } public final boolean postDelayed( @NonNull Runnable r, @Nullable Object token, long delayMillis) { return sendMessageDelayed(getPostMessage(r, token), delayMillis); } public final boolean postAtFrontOfQueue(@NonNull Runnable r) { return sendMessageAtFrontOfQueue(getPostMessage(r)); }
关于定时,延时,优先级,标识开发者自由组合。
...
public void dispatchMessage(@NonNull Message msg) {
...
}
...
@NonNull
public static Handler createAsync(@NonNull Looper looper) {
...
}
...
public final boolean runWithScissors(@NonNull Runnable r, long timeout) {
...
}
关于是否同步,是否移除,分发消息,获取消息等等Handler都提供了选择,如何使用根据实际情况来。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。