鸿蒙线程基础知识

概述

在操作系统中,线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
我们先来说说Android,一般来说一个APP可以当作一个进程,一个进程可以包含多个线程。Android中的线程一般可以分为主线程和子线程。主线程主要是处理和界面相关的,所以又称之为UI线程,并且不能在主线程中处理非常耗时的任务,否则可能会使得APP卡死,子线程的作用就在于完成耗时的操作,如网络访问、数据读取、文件下载等。
那其实呢,鸿蒙的线程和安卓的线程是差不多的。

线程管理

在启动应用时,系统会为该应用创建一个称为“主线程”的执行线程。该线程随着应用创建或消失,是应用的核心线程。UI界面的显示和更新等操作,都是在主线程上进行。主线程又称UI线程,默认情况下,所有的操作都是在主线程上执行。如果需要执行比较耗时的任务(如下载文件、查询数据库),可创建其他线程来处理。

任务分发器TaskDispatcher

在业务需要处理复杂的操作的时候,可能就需要创建多个线程来执行多个任务。在鸿蒙中开发者就需要使用任务分发器TaskDispatcher来分发不同的任务。
TaskDispatcher是Ability分发任务的基本接口,隐藏任务所在线程的实现细节。
HarmonyOS的TaskDispatcher与Android的ThreadPool有一定的相似之处

线程优先级

为保证应用有更好的响应性,我们需要设计任务的优先级。在UI线程上运行的任务默认以高优先级运行,如果某个任务无需等待结果,则可以用低优先级。

优先级详细描述
HIGH最高任务优先级,比默认优先级、低优先级的任务有更高的几率得到执行。
DEFAULT默认任务优先级, 比低优先级的任务有更高的几率得到执行。
LOW低任务优先级,比高优先级、默认优先级的任务有更低的几率得到执行。

任务分发器TaskDispatcher的多种实现

TaskDispatcher具有多种实现,每种实现对应不同的任务分发器。在分发任务时可以指定任务的优先级,由同一个任务分发器分发出的任务具有相同的优先级。

1、全局并发任务分发器GlobalTaskDispatcher

Ability执行getGlobalTaskDispatcher()获取
适用于任务之间没有联系的情况。一个应用只有一个GlobalTaskDispatcher,它在程序结束时才被销毁。

TaskDispatcher globalTaskDispatcher = getGlobalTaskDispatcher(TaskPriority.DEFAULT);

TaskPriority.DEFAULT是优先级,也可以用null来代替
相似SingleThreadExecutor(Android中单线程化线程池)

2、并发任务分发器ParallelTaskDispatcher

由Ability执行createParallelTaskDispatcher()创建并返回
与GlobalTaskDispatcher不同的是,ParallelTaskDispatcher不具有全局唯一性,可以创建多个。开发者在创建或销毁dispatcher时,需要持有对应的对象引用 。

TaskDispatcher parallelTaskDispatcher = createParallelTaskDispatcher("parallelTaskDispatcher", TaskPriority.DEFAULT);

第一个*“parallelTaskDispatcher”*参数是字符串类型,表示一个并发任务分发器的引用,为了区分不同的并发任务分布器,在销毁的时候需要指定对应的引用来销毁指定的分发器。
相似FixedThreadPool(Android中定长线程池)

3、串行任务分发器SerialTaskDispatcher

由Ability执行createSerialTaskDispatcher()创建并返回
由该分发器分发的所有的任务都是按顺序执行,但是执行这些任务的线程并不是固定的。如果要执行并行任务,应使用ParallelTaskDispatcher或者GlobalTaskDispatcher,而不是创建多个SerialTaskDispatcher。如果任务之间没有依赖,应使用GlobalTaskDispatcher来实现。它的创建和销毁由开发者自己管理,开发者在使用期间需要持有该对象引用。

TaskDispatcher serialTaskDispatcher = createSerialTaskDispatcher("serialTaskDispatcher", TaskPriority.DEFAULT);

可以理解为一个有序的列表
相似CachedThreadPool(Android中可缓存线程池)

4、专有任务分发器SpecTaskDispatcher

专有任务分发器,绑定到专有线程上的任务分发器。

TaskDispatcher mainTaskDispatcher = getMainTaskDispatcher();//获取主线程任务分发器
TaskDispatcher uiTaskDispatcher = getUITaskDispatcher();//获取UI线程任务分发器

SpecTaskDispatcher有MainTaskDispatcher和UITaskDispatcher,建议使用UITaskDispatcher。
UITaskDispatcher:绑定到应用主线程的专有任务分发器, 由Ability执行getUITaskDispatcher()创建并返回。 由该分发器分发的所有的任务都是在主线程上按顺序执行,它在应用程序结束时被销毁。
相似ScheduledThreadPool(Android中定时线程池)

派发任务

1、同步派发任务(syncDispatch)

派发任务并在当前线程等待任务执行完成。在返回前,当前线程会被阻塞。

    private void syncDispatch() {
        mGlobalTaskDispatcher.syncDispatch(new Runnable() {
            @Override
            public void run() {
                HiLog.info(LABEL_LOG, "%{public}s", "sync task1 run,同步任务1执行");
            }
        });
        HiLog.info(LABEL_LOG, "%{public}s", "after sync task1,同步任务1执行完毕");

        mGlobalTaskDispatcher.syncDispatch(() -> HiLog.info(LABEL_LOG, "%{public}s", "sync task2 run,同步任务2执行"));
        HiLog.info(LABEL_LOG, "%{public}s", "after sync task2,同步任务2执行完毕");

        mGlobalTaskDispatcher.syncDispatch(() -> HiLog.info(LABEL_LOG, "%{public}s", "sync task3 run,同步任务3执行"));
        HiLog.info(LABEL_LOG, "%{public}s", "after sync task3,同步任务3执行完毕");
    }

上面的代码派发了三个同步任务,运行后,输出的日志如下:
在这里插入图片描述
通过运行结果可以看出同步任务严格按照任务分配顺序执行
接下来,用不同的分发器使用syncDispatch同步派发任务

    private void syncDispatchTest() {
        mGlobalTaskDispatcher.syncDispatch(() -> HiLog.info(LABEL_LOG, "%{public}s", "sync task1 run"));
        HiLog.info(LABEL_LOG, "%{public}s", "after sync task1");

        mParallelTaskDispatcher.syncDispatch(() -> HiLog.info(LABEL_LOG, "%{public}s", "sync task2 run"));
        HiLog.info(LABEL_LOG, "%{public}s", "after sync task2");

        mSerialTaskDispatcher.syncDispatch(() -> HiLog.info(LABEL_LOG, "%{public}s", "sync task3 run"));
        HiLog.info(LABEL_LOG, "%{public}s", "after sync task3");

        mUITaskDispatcher.syncDispatch(() -> HiLog.info(LABEL_LOG, "%{public}s", "sync task4 run"));
        HiLog.info(LABEL_LOG, "%{public}s", "after sync task4");
    }

在这里插入图片描述
通过运行结果可以看出随便哪一个分发器,使用syncDispatch派发任务,都是同不执行的,最后的UITaskDispatcher没有执行,是因为发生了死锁(就是下面的第一种情况,UITaskDispatcher是专有任务分发器SpecTaskDispatcher)。
如果对syncDispatch使用不当, 将会导致死锁。如下情形可能导致死锁发生:

  • 在专有线程上,利用该专有任务分发器进行syncDispatch。
  • 在被某个串行任务分发器(dispatcher_a)派发的任务中,再次利用同一个串行任务分发器(dispatcher_a)对象派发任务。
  • 在被某个串行任务分发器(dispatcher_a)派发的任务中,经过数次派发任务,最终又利用该(dispatcher_a)串行任务分发器派发任务。例如:dispatcher_a派发的任务使用dispatcher_b进行任务的派发,在dispatcher_b派发的任务中又利用dispatcher_a进行派发任务。
  • 串行任务分发器(dispatcher_a)派发的任务中利用串行任务分发器(dispatcher_b)进行同步派发任务,同时dispatcher_b派发的任务中利用串行任务分发器(dispatcher_a)进行同步派发任务。在特定的线程执行顺序下将导致死锁。
    如果多个线程(或任务分发器)在同时执行相同的任务,使用syncDispatch将会导致死锁,所以这时候就引出了asyncDispatch。
2、异步派发任务(asyncDispatch)

派发任务,并立即返回,返回值是一个可用于取消任务的接口。

    private void asyncDispatch() {
        Revocable revocable1 = mGlobalTaskDispatcher.asyncDispatch(() -> HiLog.info(LABEL_LOG, "%{public}s", "async task1 run,异步任务1执行"));
        HiLog.info(LABEL_LOG, "%{public}s", "我在异步任务1下方");
        Revocable revocable2 = mGlobalTaskDispatcher.asyncDispatch(() -> HiLog.info(LABEL_LOG, "%{public}s", "async task2 run,异步任务2执行"));
        HiLog.info(LABEL_LOG, "%{public}s", "我在异步任务2下方");
    }

上面的代码派发了两个同步任务,运行两次后,输出的日志如下:
在这里插入图片描述通过运行结果可以看出异步任务的执行顺序是随机的
接下来,用不同的分发器使用asyncDispatch异步派发任务

    private void asyncDispatchTest() {
        mGlobalTaskDispatcher.asyncDispatch(() -> HiLog.info(LABEL_LOG, "%{public}s", "async task1 run"));
        HiLog.info(LABEL_LOG, "%{public}s", "after async task1");

        mParallelTaskDispatcher.asyncDispatch(() -> HiLog.info(LABEL_LOG, "%{public}s", "async task2 run"));
        HiLog.info(LABEL_LOG, "%{public}s", "after async task2");

        mSerialTaskDispatcher.asyncDispatch(() -> HiLog.info(LABEL_LOG, "%{public}s", "async task3 run"));
        HiLog.info(LABEL_LOG, "%{public}s", "after async task3");

        mUITaskDispatcher.asyncDispatch(() -> HiLog.info(LABEL_LOG, "%{public}s", "async task4 run"));
        HiLog.info(LABEL_LOG, "%{public}s", "after async task4");
    }

在这里插入图片描述
通过运行结果可以看出随便哪一个分发器,使用asyncDispatch派发任务,都是异步执行的。
那这么多分发器有什么用呢?
下面是并发任务分发器ParallelTaskDispatcher和串行任务分发器SerialTaskDispatcher使用异步派发任务asyncDispatch

    private void asyncDispatchTestParAndSer() {
        mParallelTaskDispatcher.asyncDispatch(() -> HiLog.info(LABEL_LOG, "%{public}s", "ParallelTaskDispatcher async task1 run"));
        HiLog.info(LABEL_LOG, "%{public}s", "ParallelTaskDispatcher after async task1");
        mParallelTaskDispatcher.asyncDispatch(() -> HiLog.info(LABEL_LOG, "%{public}s", "ParallelTaskDispatcher async task2 run"));
        HiLog.info(LABEL_LOG, "%{public}s", "ParallelTaskDispatcher after async task2");

        mSerialTaskDispatcher.asyncDispatch(() -> HiLog.info(LABEL_LOG, "%{public}s", "SerialTaskDispatcher async task1 run"));
        HiLog.info(LABEL_LOG, "%{public}s", "SerialTaskDispatcher after async task1");
        mSerialTaskDispatcher.asyncDispatch(() -> HiLog.info(LABEL_LOG, "%{public}s", "SerialTaskDispatcher async task2 run"));
        HiLog.info(LABEL_LOG, "%{public}s", "SerialTaskDispatcher after async task2");
    }

在这里插入图片描述
通过运行结果可以看出使用syncDispatch和asyncDispatch分发任务的同步和异步是针对主线程而言,使用ParallelTaskDispatcher和SerialTaskDispatcher的区别是派发的任务是并行还是串行

3、异步延迟派发任务(delayDispatch)

异步执行,函数立即返回,内部会在延时指定时间后将任务派发到相应队列中。延时时间参数仅代表在这段时间以后任务分发器会将任务加入到队列中,任务的实际执行时间可能晚于这个时间。具体比这个数值晚多久,取决于队列及内部线程池的繁忙情况。

    private void delayDispatch() {
        final long callTime = System.currentTimeMillis();//获取当前任务开始派发的时间
        final long delayTime = 1000;//设置延迟时间为1s
        Revocable revocable = mGlobalTaskDispatcher.delayDispatch(() -> {
            HiLog.info(LABEL_LOG, "delayDispatch task1 run,异步延迟派发任务1运行");
            final long actualDelayTime = System.currentTimeMillis() - callTime;//实际延迟时间=当前任务执行时间-任务开始派发的时间
            HiLog.info(LABEL_LOG, "actualDelayTime >= delayTime(实际延迟时间 >= 延迟时间): %{public}b", (actualDelayTime >= delayTime));
            HiLog.info(LABEL_LOG, "实际延迟时间为:" + actualDelayTime);
            HiLog.info(LABEL_LOG, "实际延迟时间比理论延迟时间晚了:" + (actualDelayTime - delayTime) + "ms");
        }, delayTime);//设置延迟时间为1s
        HiLog.info(LABEL_LOG, "after delayDispatch task1");
    }

运行后,输出的日志如下:
在这里插入图片描述

4、任务组(Group)

表示一组任务,且该组任务之间有一定的联系,由TaskDispatcher执行createDispatchGroup创建并返回。将任务加入任务组,返回一个用于取消任务的接口。
也就是将线程分组,把几个线程放在一个任务组Group中,并且可以添加这一组线程执行完的回调。

    private void group() {
        //创建任务组
        Group group = mParallelTaskDispatcher.createDispatchGroup();
        //将任务1加入任务组,返回一个用于取消任务的接口。
        mParallelTaskDispatcher.asyncGroupDispatch(group, () -> HiLog.info(LABEL_LOG, "download task1 is running,下载任务1正在运行"));
        //将与任务1相关联的任务2加入任务组。
        mParallelTaskDispatcher.asyncGroupDispatch(group, () -> HiLog.info(LABEL_LOG, "download task2 is running,下载任务2正在运行"));
        //在任务组中的所有任务执行完成后执行指定任务。
        mParallelTaskDispatcher.groupDispatchNotify(group, () -> HiLog.info(LABEL_LOG, "the close task is running after all tasks in the group are completed,完成组中的所有任务后,将运行“关闭”任务"));
    }

上面代码展示了任务组的使用方式:将一系列相关联的下载任务放入一个任务组,执行完下载任务后关闭应用。
运行两次后,输出的日志如下:
在这里插入图片描述
从运行结果中可以看出,运行两次的日志不一样,也就是说,异步任务组中的任务的执行顺序不是固定的(如果异步任务组里的每个任务执行的任务都不一样的话,那耗时长的那个任务肯定是最后才完成的),但是执行异步任务组后需要执行的任务是在异步异步任务组中所有的任务都执行完了以后才执行的。

5、取消任务(Revocable)

返回值Revocable是一个可用于取消一个异步任务的接口
异步任务包括通过 asyncDispatchdelayDispatchasyncGroupDispatch 派发的任务。如果任务已经在执行中或执行完成,则会返回取消失败。
下面使用Revocable取消asyncDispatch

        //撤销任务分发
        revocable1.revoke();

在这里插入图片描述
通过运行结果可以看出异步任务1被撤销了
下面使用Revocable取消delayDispatch

    private void revocable() {
        Revocable revocable = mUITaskDispatcher.delayDispatch(new Runnable() {
            @Override
            public void run() {
                HiLog.info(LABEL_LOG, "delay dispatch");
            }
        }, 10);
        //取消异步延迟派发任务delayDispatch
        boolean revoked = revocable.revoke();
        HiLog.info(LABEL_LOG, "是否取消了:%{public}b", revoked);
    }

在这里插入图片描述通过运行结果可以看出delayDispatch被撤销了

6、同步设置屏障任务(syncDispatchBarrier)

在任务组上设立任务执行屏障,同步等待任务组中的所有任务执行完成,再执行指定任务。
在全局并发任务分发器(GlobalTaskDispatcher)上同步设置任务屏障,将不会起到屏障作用。

    private void syncDispatchBarrier() {
        //创建任务组
        Group group = mParallelTaskDispatcher.createDispatchGroup();
        //将任务加入任务组
        mParallelTaskDispatcher.asyncGroupDispatch(group, new Runnable() {
            @Override
            public void run() {
                HiLog.info(LABEL_LOG, "task1 is running");  // 1
            }
        });
        mParallelTaskDispatcher.asyncGroupDispatch(group, new Runnable() {
            @Override
            public void run() {
                HiLog.info(LABEL_LOG, "task2 is running");  // 2
            }
        });

        mParallelTaskDispatcher.syncDispatchBarrier(new Runnable() {
            @Override
            public void run() {
                HiLog.info(LABEL_LOG, "barrier");  // 3
            }
        });
        HiLog.info(LABEL_LOG, "after syncDispatchBarrier");  // 4
    }

在这里插入图片描述
通过运行结果可以看出,1和2的执行顺序不定,3和4总是在1和2之后按顺序执行。

7、异步设置屏障任务(asyncDispatchBarrier)

在任务组上设立任务执行屏障后直接返回,指定任务将在任务组中的所有任务执行完成后再执行。
在全局并发任务分发器(GlobalTaskDispatcher)上异步设置任务屏障,将不会起到屏障作用。可以使用并发任务分发器(ParallelTaskDispatcher)分离不同的任务组,达到微观并行、宏观串行的行为。

    private void asyncDispatchBarrier() {
        //创建任务组
        Group group = mParallelTaskDispatcher.createDispatchGroup();
        //将任务加入任务组,返回一个用于取消任务的接口
        mParallelTaskDispatcher.asyncGroupDispatch(group, new Runnable() {
            @Override
            public void run() {
                HiLog.info(LABEL_LOG, "task1 is running");  // 1
            }
        });
        mParallelTaskDispatcher.asyncGroupDispatch(group, new Runnable() {
            @Override
            public void run() {
                HiLog.info(LABEL_LOG, "task2 is running");  // 2
            }
        });

        mParallelTaskDispatcher.asyncDispatchBarrier(new Runnable() {
            @Override
            public void run() {
                HiLog.info(LABEL_LOG, "barrier");  // 3
            }
        });
        HiLog.info(LABEL_LOG, "after asyncDispatchBarrier");  // 4
    }

在这里插入图片描述
通过运行结果可以看出,1和2的执行顺序不定,但总在3之前执行,4不需要等待1、2、3执行完成。

8、执行多次任务(applyDispatch)

对指定任务执行多次。

    private void applyDispatch() {
        final int total = 10;//任务de总执行次数
        final CountDownLatch latch = new CountDownLatch(total);//倒数计时器
        final List<Long> indexList = new ArrayList<>(total);//长整形列表数组

        //执行任务 total 次
        mGlobalTaskDispatcher.applyDispatch((index) -> {
            indexList.add(index);
            latch.countDown();//当前线程调用此方法,则计数减一
            HiLog.info(LABEL_LOG, "数字" + index);
        }, total);
        //设置任务超时
        try {
            latch.await();//阻塞当前线程,直到计数器的值为0
        } catch (InterruptedException exception) {
            HiLog.error(LABEL_LOG, "latch exception,任务超时");
        }
        HiLog.info(LABEL_LOG, "list size matches, %{public}b", (total == indexList.size()));//是否全部执行完了
        HiLog.info(LABEL_LOG, "一共执行了" + indexList.size() + "次");
        for (Long aLong : indexList) {
            HiLog.info(LABEL_LOG, "长整形列表数组" + aLong);
        }
    }

在这里插入图片描述

线程间通信

概述

在开发过程中,开发者经常需要在当前线程中处理下载任务等较为耗时的操作,但是又不希望当前的线程受到阻塞。此时,就可以使用EventHandler机制。EventHandler是HarmonyOS用于处理线程间通信的一种机制,可以通过EventRunner创建新线程,将耗时的操作放到新线程上执行。这样既不阻塞原来的线程,任务又可以得到合理的处理。比如:主线程使用EventHandler创建子线程,子线程做耗时的下载图片操作,下载完成后,子线程通过EventHandler通知主线程,主线程再更新UI。
其实HarmonyOS的EventHandler跟Android的 Handler很像

具体可以查看官方文档: 线程间通信开发概述
线程间通信开发指导

使用

MainAbilitySlice.java

public class MainAbilitySlice extends AbilitySlice {

    private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "TC_Log");
    private static final int EVENT_MESSAGE_NORMAL = 1;
    private static final int EVENT_MESSAGE_DELAY = 2;
    private static final int EVENT_MESSAGE_CROSS_THREAD = 3;

    private EventRunner mEventRunner;
    private TestEventHandler mTestEventHandler;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);

        initComponents();
        initHandler();
    }

    private void initComponents() {
        Button innerEventBtn = (Button) findComponentById(ResourceTable.Id_initInnerEvent);
        Button runnableBtn = (Button) findComponentById(ResourceTable.Id_initRunnable);
        Button newToOriginal = (Button) findComponentById(ResourceTable.Id_initNewToOriginal);
        innerEventBtn.setClickedListener(component -> initInnerEvent());
        runnableBtn.setClickedListener(component -> initRunnable());
        newToOriginal.setClickedListener(component -> initNewToOriginal());
    }

    private void initHandler() {
        //1、创建EventHandler的子类,在子类中重写实现方法processEvent()来处理事件
        //EventHandler的主要功能是将InnerEvent事件或者Runnable任务投递到其他的线程进行处理
        //其使用的场景就是本项目的initInnerEvent()方法、initRunnable()方法、initNewToOriginal()方法

        //2、创建EventRunner,以托管模式为例。
        //EventRunner的工作模式可以分为托管模式和手动模式
        mEventRunner = EventRunner.create(true);//create()的参数是false时,则为手动模式
//        mEventRunner = EventRunner.create("mEventRunner");//创建一个拥有新线程的EventRunner,新线程的名字是mEventRunner

//        //6、启动和停止EventRunner,如果为托管模式,则不需要此步骤。
//        mEventRunner.run();
//        //开发者可根据业务需要自行编写待执行操作
//        //停止EventRunner
//        mEventRunner.stop();//开发者根据业务需要在适当时机停止EventRunner

        //EventRunner创建时需要判断是否创建成功,只有确保获取的EventRunner实例非空时,才可以使用EventHandler绑定EventRunner
        //需要对EventRunner的实例进行校验,不是任何线程都可以通过create创建,例如:当线程池已满时,不能再创建线程。
        if (mEventRunner == null) {
            return;
        }
        //3、创建EventHandler子类的实例。
        //一个EventHandler只能同时与一个EventRunner绑定,一个EventRunner可以同时绑定多个EventHandler
        mTestEventHandler = new TestEventHandler(mEventRunner);
    }

    /**
     * EventHandler投递InnerEvent事件
     */
    public void initInnerEvent() {
        //4、获取InnerEvent事件。
        //属性eventId, param, object由开发者确定,代码中只是示例。
        int eventId1 = EVENT_MESSAGE_NORMAL;//eventId事件的ID, 由开发者定义用来辨别事件
        int eventId2 = EVENT_MESSAGE_DELAY;
        long param = 0;//事件携带的long型数据
        Object object = null;//事件携带的Object信息
        //有关InnerEvent的主要接口介绍可参考官方文档
        InnerEvent normalInnerEvent = InnerEvent.get(eventId1, param, object);//获得一个指定的eventId,param和object的事件实例
        InnerEvent delayInnerEvent = InnerEvent.get(eventId2, param, object);

        //5、投递事件,投递的优先级以IMMEDIATE为例,延时选择0ms和2ms。
        //关于优先级的介绍可参考官方文档
        mTestEventHandler.sendEvent(normalInnerEvent, 0, EventHandler.Priority.IMMEDIATE);//优先级IMMEDIATE,投递之后立即处理,延时为0ms
        //下面代码等同于上面的代码
//        mTestEventHandler.sendSyncEvent(normalInnerEvent, EventHandler.Priority.IMMEDIATE);//发送一个指定优先级的同步事件到事件队列,延时为0ms,优先级不可以是IDLE
        mTestEventHandler.sendEvent(delayInnerEvent, 2, EventHandler.Priority.IMMEDIATE);//延时2ms后立即处理
        //EventHandler还有很多接口方法可以调用,sendEvent有很多不同的实现都可参考官方文档
    }

    /**
     * EventHandler投递Runnable任务
     */
    private void initRunnable() {
        //EventHandler投递Runnable任务的步骤1-3与EventHandler投递InnerEvent事件的步骤1-3相同

        //4、创建Runnable任务。
        Runnable normalTask = new Runnable() {
            @Override
            public void run() {
                // 待执行的操作,由开发者定义
                HiLog.info(LABEL_LOG, "task1 running");
            }
        };
        Runnable delayTask = new Runnable() {
            @Override
            public void run() {
                // 待执行的操作,由开发者定义
                HiLog.info(LABEL_LOG, "task2 running");
            }
        };

        //5、投递Runnable任务,投递的优先级以IMMEDIATE为例,延时选择0ms和2ms。
        mTestEventHandler.postTask(normalTask, 0, EventHandler.Priority.IMMEDIATE);
        mTestEventHandler.postTask(delayTask, 2, EventHandler.Priority.IMMEDIATE);
        //EventHandler还有很多接口方法可以调用,postTask有很多不同的实现都可参考官方文档
    }

    /**
     * 在新创建的线程里投递事件到原线程
     */
    private void initNewToOriginal() {
        //EventHandler在新创建的线程里投递事件到原线程的步骤1-3也与EventHandler投递InnerEvent事件的步骤1-3相同

        //4、获取InnerEvent事件。
        //获取事件实例,其属性eventId, param, object由开发者确定,代码中只是示例。
        long param = 0;
        InnerEvent event = InnerEvent.get(EVENT_MESSAGE_CROSS_THREAD, param, mEventRunner);

        //5、投递事件,在新线程上直接处理。
        //将与当前线程绑定的EventRunner投递到与runner创建的新线程中
        mTestEventHandler.sendEvent(event);
    }

    @Override
    public void onActive() {
        super.onActive();
    }

    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }
}

TestEventHandler.java

public class TestEventHandler extends EventHandler {
    private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "TC_Log");
    private static final int EVENT_MESSAGE_NORMAL = 1;
    private static final int EVENT_MESSAGE_DELAY = 2;
    private static final int EVENT_MESSAGE_CROSS_THREAD = 3;

    public TestEventHandler(EventRunner runner) throws IllegalArgumentException {
        super(runner);
    }

    /**
     * 1、创建EventHandler的子类,在子类中重写实现方法processEvent()来处理事件
     *
     * @param event
     */
    @Override
    protected void processEvent(InnerEvent event) {
        super.processEvent(event);

        if (event == null) {
            return;
        }

        int eventId = event.eventId;
        switch (eventId) {
            case EVENT_MESSAGE_NORMAL:
                // 待执行的操作,由开发者定义
                HiLog.info(LABEL_LOG, "111");
                break;

            case EVENT_MESSAGE_DELAY:
                // 待执行的操作,由开发者定义
                HiLog.info(LABEL_LOG, "222");
                break;

            case EVENT_MESSAGE_CROSS_THREAD:
                // 待执行的操作,由开发者定义
                HiLog.info(LABEL_LOG, "333");
                Object object = event.object;
                if (object instanceof EventRunner) {
                    // 将原先线程的EventRunner实例投递给新创建的线程
                    EventRunner eventRunner = (EventRunner) object;//强转
                    // 将原先线程的EventRunner实例与新创建的线程的EventHandler绑定
                    EventHandler eventHandler = new EventHandler(eventRunner) {
                        @Override
                        public void processEvent(InnerEvent event) {
                            // 需要在原先线程执行的操作
                            HiLog.info(LABEL_LOG, "OriginalThread receive a message");
                        }
                    };
                    int testEventId = 1;
                    long testParam = 0;
                    Object testObject = null;
                    InnerEvent innerEvent = InnerEvent.get(testEventId, testParam, testObject);
                    eventHandler.sendEvent(innerEvent); //投递事件到原先的线程
                }
                break;

            default:
                break;
        }
    }
}

运行结果
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值