HarmonyOS 线程讲解(任务分发、线程通信)_鸿蒙开发线程怎么用


**syncTask**方法中中派发三个同步任务,打印日志



** * GlobalTaskDispatcher 派发同步任务 */

private void syncTask() {
globalTaskDispatcher.syncDispatch(new Runnable() {
@Override public void run() {
HiLog.info(label, “sync task1 run”);
}
}
);
HiLog.info(label, “after sync task1”); globalTaskDispatcher.syncDispatch(new Runnable() {
@Override public void run() {
HiLog.info(label,“sync task2 run”);
}
}
);
HiLog.info(label,“after sync task2”); globalTaskDispatcher.syncDispatch(new Runnable() {
@Override public void run() {
HiLog.info(label,“sync task3 run”);
}
}
);
HiLog.info(label,“after sync task3”);
}


运行之后,日志如下所示:


![](https://img-blog.csdnimg.cn/img_convert/3ef8b367c710c29a1b880dd1000d0199.webp?x-oss-process=image/format,png)


虽然现在是没有问题,但是如果对 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)进行同步派发任务。在特定的线程执行顺序下将导致死锁。


#### ⑥ 异步派发任务(asyncDispatch)


写一个asyncTask方法,里面的内容和syncTask差不多。



/** * GlobalTaskDispatcher 派发同步任务
*/
private void asyncTask() {
globalTaskDispatcher.asyncDispatch(new Runnable() {
@Override public void run() {
HiLog.info(label,“sync task1 run”);
}
} );
HiLog.info(label,“after sync task1”);
}


然后在onStart中调用即可


![](https://img-blog.csdnimg.cn/img_convert/9166faf500f6aa1df1ea0f3f23a67588.webp?x-oss-process=image/format,png)


然后再运行。


![](https://img-blog.csdnimg.cn/img_convert/18fa0b76b883b0e659e9f312daefb677.webp?x-oss-process=image/format,png)


同时这个异步派发是任务是可以取消的。Revocable,globalTaskDispatcher.asyncDispatch的返回值就是Revocable,


![](https://img-blog.csdnimg.cn/img_convert/234fca6a9347117faa7f6363b640bbbf.webp?x-oss-process=image/format,png)


那么上面[async]( )中的代码就可以这样写。如下所示:



/**     * GlobalTaskDispatcher 派发同步任务     */    private void asyncTask() {
    Revocable revocable = globalTaskDispatcher.asyncDispatch(new Runnable() { 
       @Override            public void run() {
            HiLog.info(label, "async task1 run");
        }
    });        //撤销任务分发
    revocable.revoke();
    HiLog.info(label, "after async task1"); 

}


在运行一下:


![](https://img-blog.csdnimg.cn/img_convert/2f96bc8ba07993c28f1a0834a7a732db.webp?x-oss-process=image/format,png)


很明显里面的任务已经撤销了


#### ⑦ 异步延迟派发任务(delayDispatch)


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



/**     * 当前时间     */    

final long currentTime = System.currentTimeMillis(); /** * 延迟时间 100ms */
final long delayTime = 100;


![](https://img-blog.csdnimg.cn/img_convert/3b966d23478ea1f55baf307dc58987ab.webp?x-oss-process=image/format,png)


delayTask方法如下:



/** * GlobalTaskDispatcher 派发异步延时任务 */
private void delayTask() {
globalTaskDispatcher.delayDispatch(new Runnable() {
@Override public void run() {
HiLog.info(label, “delay task1 run”);
final long actualDelayMs = System.currentTimeMillis() - currentTime; HiLog.info(label,"actualDelayTime >= delayTime : " + (actualDelayMs >= delayTime));
}
},delayTime); HiLog.info(label, “after delay task1”);
}


日志如下:


![](https://img-blog.csdnimg.cn/img_convert/0f8683fb9f43d1bf5dd24a8f9d7d0759.webp?x-oss-process=image/format,png)


#### ⑧ 任务组(Group)


表示一组任务,且该组任务之间有一定的联系,由 TaskDispatcher 执行createDispatchGroup 创建并返回,代码如下所示。



/** * 任务组 */
private void taskGroup(Context context) {
//创建并发任务分发器
TaskDispatcher dispatcher = context.createParallelTaskDispatcher(“parallelTaskDispatcher”, TaskPriority.DEFAULT);
//创建任务组
Group group = dispatcher.createDispatchGroup();
// 将任务 1 加入任务组,
dispatcher.asyncGroupDispatch(group,new Runnable() {
@Override public void run() {
HiLog.info(label,“download task1 is running”);
}
}
); // 将任务 2 加入任务组, dispatcher.asyncGroupDispatch(group, new Runnable() {
@Override public void run() {
HiLog.info(label,“download task2 is running”); } }); // 在任务组中的所有任务执行完成后执行指定任务。
dispatcher.groupDispatchNotify(group, new Runnable() {
@Override public void run() {
HiLog.info(label, “the close task is running after all tasks in the group are completed”);
}
});
}


onStart方法中调用


![](https://img-blog.csdnimg.cn/img_convert/1518181a0ba82c8e8d9ace37e711e2a0.webp?x-oss-process=image/format,png)


运行效果如下,我运行了两次,两次日志是不一样的,如果里面执行的业务是不一样的,则耗时长的后完成。


![](https://img-blog.csdnimg.cn/img_convert/9eedd71651fa3091dddab8d7f62d21be.webp?x-oss-process=image/format,png)


#### ⑨ 取消任务(Revocable)


Revocable 是取消一个异步任务的接口。异步任务包括通过 asyncDispatch、delayDispatch、asyncGroupDispatch 派发的任务。如果任务已经在执行中或执行完成,则会返回取消失败。



/**     * 取消异步任务     */
private void revocableAsyncTask(Context context) {
    TaskDispatcher dispatcher = context.getUITaskDispatcher();
    Revocable revocable = dispatcher.delayDispatch(new Runnable() {
        @Override
 public void run() {
            HiLog.info(label, "delay dispatch"); 
       } 
   }, 

10);
boolean revoked = revocable.revoke(); HiLog.info(label, “” + revoked);
}


在onStart()中调用



//取消异步任务revocableAsyncTask(MainAbility.this);


运行效果如下:


![](https://img-blog.csdnimg.cn/img_convert/7e512dd11369bab890574cf451445665.webp?x-oss-process=image/format,png)


#### ⑩ 同步设置屏障任务 (syncDispatchBarrier)


在任务组上设立任务执行屏障,同步等待任务组中的所有任务执行完成,再执行指定任务。在全局并发任务分发器(GlobalTaskDispatcher)上同步设置任务屏障,将不会起到屏障作用。就比如说考试提前交卷,A提前20分钟,B提前10分钟,但你只是离开了考室,离不开考场,这个考场的门就是这个屏障,无论你是提前多久,你都要等到所有考生考完,老师收卷之后才能离开考场,就是这么一个理。代码如下:



/** * 同步设置屏障任务 */
private void setSyncDispatchBarrier(Context context) {
TaskDispatcher dispatcher = context.createParallelTaskDispatcher(“parallelTask”,TaskPriority.DEFAULT);
//创建任务组
Group group = dispatcher.createDispatchGroup(); //将任务1加入任务组
dispatcher.asyncGroupDispatch(group, new Runnable() {
@Override public void run() {
HiLog.info(label,“task1 is running”);
}
}); //将任务2加入任务组
dispatcher.asyncGroupDispatch(group, new Runnable() {
@Override public void run() {
HiLog.info(label,“task2 is running”);
}
});
dispatcher.asyncDispatchBarrier(new Runnable() {
@Override public void run() {
HiLog.info(label,“Barrier”);
}
});
HiLog.info(label,“after syncDispatchBarrier”);
}


在onStart()中调用,



//同步设置屏障任务setSyncDispatchBarrier(MainAbility.this);


运行


![](https://img-blog.csdnimg.cn/img_convert/64d516bf8a8e9c898f30efcfe7213a64.webp?x-oss-process=image/format,png)


#### ⑪ 异步设置屏障任务 (asyncDispatchBarrier)


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



/** * 异步设置屏障任务 */
private void setAsyncDispatchBarrier(Context context) {
TaskDispatcher dispatcher = context.createParallelTaskDispatcher(“AsyncParallelTaskDispatcher”, TaskPriority.DEFAULT); // 创建任务组
Group group = dispatcher.createDispatchGroup(); //将任务1加入任务组
dispatcher.asyncGroupDispatch(group, new Runnable() {
@Override public void run() {
HiLog.info(label, “task1 is running”); // 1
}
});
//将任务2加入任务组 dispatcher.asyncGroupDispatch(group, new Runnable() {
@Override public void run() {
HiLog.info(label, “task2 is running”); // 2
} });
dispatcher.asyncDispatchBarrier(new Runnable() {
@Override public void run() {
HiLog.info(label, “barrier”); // 3
} });
HiLog.info(label, “after syncDispatchBarrier”); // 4
}


在onStart()中调用



//异步设置屏障任务setAsyncDispatchBarrier(MainAbility.this);


运行效果


![](https://img-blog.csdnimg.cn/img_convert/5fa49007ed47923b94591cc148e1600c.webp?x-oss-process=image/format,png)


#### ⑫ 执行多次任务(applyDispatch)


对指定任务执行多次



/** * 执行多次任务 */ p
rivate void multipleTasks() { //总执行次数
final int total = 10; //倒数计时器
final CountDownLatch latch = new CountDownLatch(total); //长整形列表数组
final ArrayList indexList = new ArrayList<>(total); TaskDispatcher dispatcher = createParallelTaskDispatcher(“dispatcher”, TaskPriority.DEFAULT); //执行多次任务
dispatcher.applyDispatch((index) -> {
indexList.add(index); latch.countDown();
HiLog.info(label, "long: "+index); },
total);
//设置任务超时
try { latch.await(); }
catch (InterruptedException e) {
HiLog.info(label, “latch exception”);
} //返回true则说明执行了10次
HiLog.info(label, “list size matches,” + (total == indexList.size()));
}


运行效果如下:


![](https://img-blog.csdnimg.cn/img_convert/14cf0c19a2bf762800d57fba97fed62d.webp?x-oss-process=image/format,png)


### 三、线程通信


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


#### ① EventRunner


EventRunner 是一种事件循环器,循环处理从该 EventRunner 创建的新线程的事件队列中获取 InnerEvent 事件或者 Runnable 任务。InnerEvent 是 EventHandler 投递的事件。


EventHandler 是一种用户在当前线程上投递 InnerEvent 事件或者 Runnable 任务到异步线程上处理的机制。每一个 EventHandler 和指定的 EventRunner 所创建的新线程绑定,并且该新线程内部有一个事件队列。EventHandler 可以投递指定的 InnerEvent 事件或 Runnable 任务到这个事件队列。EventRunner 从事件队列里循环地取出事件,如果取出的事件是InnerEvent 事件,将在 EventRunner 所在线程执行 processEvent 回调;如果取出的事件是Runnable 任务,将在 EventRunner 所在线程执行 Runnable 的 run 回调。


#### ② EventHandler


EventHandler 有两个主要作用:


在不同线程间分发和处理 InnerEvent 事件或 Runnable 任务。


延迟处理 InnerEvent 事件或 Runnable 任务。


EventHandler 的运作机制如下图所示:


![](https://img-blog.csdnimg.cn/img_convert/00726f4e1b5b9441c809ccb6c3e58afc.webp?x-oss-process=image/format,png)


使用 EventHandler 实现线程间通信的主要流程:


EventHandler 投递具体的 InnerEvent 事件或者 Runnable 任务到 EventRunner 所创建的线程的事件队列。


EventRunner 循环从事件队列中获取 InnerEvent 事件或者 Runnable 任务。


处理事件或任务:


① 如果 EventRunner 取出的事件为 InnerEvent 事件,则触发 EventHandler 的回调方法并触发 EventHandler 的处理方法,在新线程上处理该事件。


② 如果 EventRunner 取出的事件为 Runnable 任务,则 EventRunner 直接在新线程上处理 Runnable 任务。


##### 1. 约束限制


在进行线程间通信的时候,EventHandler 只能和 EventRunner 所创建的线程进行绑定,EventRunner 创建时需要判断是否创建成功,只有确保获取的 EventRunner 实例非空时,才可以使用 EventHandler 绑定 EventRunner。


一个 EventHandler 只能同时与一个 EventRunner 绑定,一个 EventRunner 上可以创建多个 EventHandler。


##### 2. 开发场景


EventHandler 的主要功能是将 InnerEvent 事件或者 Runnable 任务投递到其他的线程进行处理,其使用的场景包括


开发者需要将 InnerEvent 事件投递到新的线程,按照优先级和延时进行处理。投递时,EventHandler 的优先级可在IMMEDIATE、HIGH、LOW、IDLE 中选择,并设置合适的 delayTime。


开发者需要将 Runnable 任务投递到新的线程,并按照优先级和延时进行处理。投递时,EventHandler 的优先级可在IMMEDIATE、HIGH、LOW、IDLE 中选择,并设置合适的 delayTime。


开发者需要在新创建的线程里投递事件到原线程进行处理。


##### 3. 工作模式


EventRunner 的工作模式可以分为托管模式和手动模式。两种模式是在调用 EventRunner 的create()方法时,通过选择不同的参数来实现的,默认为托管模式。


托管模式:不需要开发者调用 run()和 stop()方法去启动和停止 EventRunner。当 EventRunner 实例化时,系统调用


run()来启动 EventRunner;当 EventRunner 不被引用时,系统调用 stop()来停止 EventRunner。


手动模式:需要开发者自行调用 EventRunner 的 run()方法和 stop()方法来确保线程的启动和停止。


#### ③ 接口说明


##### 1. EventHandler


EventHandler 的属性 Priority(优先级)介绍:


EventRunner 将根据优先级的高低从事件队列中获取事件或者 Runnable 任务进行处理。




| 属性 | 描述 |
| --- | --- |
| Priority.IMMEDIATE | 表示事件被立即投递 |
| Priority.HIGH | 表示事件先于 LOW 优先级投递 |
| Priority.LOW | 表示事件优于 IDLE 优先级投递,事件的默认优先级是 LOW |
| Priority.IDLE | 表示在没有其他事件的情况下,才投递该事件 |


* EventHandler 的主要接口介绍:


![](https://img-blog.csdnimg.cn/img_convert/fe0075e4049390c132df9d33c5ba798b.webp?x-oss-process=image/format,png)


![](https://img-blog.csdnimg.cn/img_convert/2291098d41cf95147517544b1642869f.webp?x-oss-process=image/format,png)


##### 2. EventRunner


* EventRunner 的主要接口介绍:


![](https://img-blog.csdnimg.cn/img_convert/01611c510a42ef8572a7a75780d7623e.webp?x-oss-process=image/format,png)


##### 3. InnerEvent


* InnerEvent 的属性介绍:




| 属性 | 描述 |
| --- | --- |
| eventId | 事件的 ID, 由开发者定义用来辨别事件 |
| object | 事件携带的 Object 信息 |
| param | 事件携带的 long 型数据 |


* InnerEvent 的主要接口介绍:


![](https://img-blog.csdnimg.cn/img_convert/0cebfa3ba50e11a3b1dddadeb1b7af44.webp?x-oss-process=image/format,png)


#### ④ 开发步骤


##### 一、EventHandler 投递 InnerEvent 事件


EventHandler 投递 InnerEvent 事件,并按照优先级和延时进行处理,创建一个MyEventHandler类型继承EventHandler


![](https://img-blog.csdnimg.cn/img_convert/73f637f8f69425c15610fe4c3f988192.webp?x-oss-process=image/format,png)



package com.llw.thread.event;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
public class MyEventHandler extends EventHandler {
/** * 日志 */
private static final HiLogLabel label = new HiLogLabel(3, 0xD001100, “ThreadDemo”);
public MyEventHandler(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;
long param = event.param;
switch ((int) (eventId | param)) {
case 1: HiLog.info(label, “eventId | param —>” + 1);
break;
default: break; }
} /** * EventHandler 投递 InnerEvent 事件 */
private void initInnerEvent() {
//2. 创建 EventRunner,以手动模式为例。
// create()的参数是 true 时,则为托管模式
EventRunner runner = EventRunner.create(false);
if (runner == null) { return; } //3. 创建 EventHandler 子类的实例。
MyEventHandler myHandler = new MyEventHandler(runner); //4. 获取 InnerEvent 事件。
int eventId1 = 0;
int eventId2 = 1;
long param = 0;
Object object = null;
InnerEvent event1 = InnerEvent.get(eventId1, param, object);
InnerEvent event2 = InnerEvent.get(eventId2, param, object); //5. 投递事件,投递的优先级以 IMMEDIATE 为例,延时选择 0ms 和 2ms。
myHandler.sendEvent(event1, 0, EventHandler.Priority.IMMEDIATE); // 延时 2ms 后立即处理
myHandler.sendEvent(event2, 2, EventHandler.Priority.IMMEDIATE); //6. 启动和停止 EventRunner,如果为托管模式,则不需要此步骤。
runner.run(); //待执行操作
// … 执行业务逻辑
// 停止
EventRunner runner.stop();
}
}


##### 二、EventHandler 投递 Runnable 任务



/** * EventHandler 投递 Runnable 任务 */
private void initRunnable() {
//2. 创建 EventRunner,以手动模式为例。
// create()的参数是 true 时,则为托管模式
EventRunner runner = EventRunner.create(false); if (runner == null) { return; }
//3. 创建 EventHandler 子类的实例。
MyEventHandler myHandler = new MyEventHandler(runner);
//2. 创建 Runnable 任务。
Runnable task1 = new Runnable() {
@Override public void run() { HiLog.info(label, “task1 running”); } };
Runnable task2 = new Runnable() {
@Override public void run() {
HiLog.info(label, “task1 running”);
}
}; //3. 投递 Runnable 任务,投递的优先级以 IMMEDIATE 为例,延时选择 0ms 和 2ms。
myHandler.postTask(task1, 0, EventHandler.Priority.IMMEDIATE); // 延时 2ms 后立即执行
myHandler.postTask(task2, 2, EventHandler.Priority.IMMEDIATE); //4. 启动和停止 EventRunner,如果是托管模式,则不需要此步骤。 runner.run();
//待执行操作
// … 执行业务逻辑
// 停止
EventRunner runner.stop();
}


##### 三、在新创建的线程里投递事件到原线程


修改MyEventHandler之后代码如下:



package com.llw.thread.event;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
public class MyEventHandler extends EventHandler {
/** * 日志 */
private static final HiLogLabel label = new HiLogLabel(3, 0xD001100, “ThreadDemo”);
private MyEventHandler myHandler;
private EventRunner runner;
public MyEventHandler(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;
long param = event.param;
Object object = event.object; switch ((int) (eventId | param)) {
case 1: HiLog.info(label, “eventId | param —>” + 1);
break;
case 2: EventRunner runner2 = null; // 将原先线程的 EventRunner 实例投递给新创建的线程
if (object instanceof EventRunner) {
//强转 runner2 = (EventRunner) object;
} // 将原先线程的 EventRunner 实例与新创建的线程的 EventHandler 绑定
EventHandler myHandler2 = new EventHandler(runner2) {
@Override protected void processEvent(InnerEvent event) {
//需要在原先线程执行的操作
}
};
int eventId2 = 1; long param2 = 0;
Object object2 = null;
InnerEvent event2 = InnerEvent.get(eventId2, param2, object2); // 投递事件到原先的线程
myHandler2.sendEvent(event2);
break; default: break; }
} /** * EventHandler 投递 InnerEvent 事件 */
private void initInnerEvent() {
//2. 创建 EventRunner,以手动模式为例。 // create()的参数是 true 时,则为托管模式
runner = EventRunner.create(false);
if (runner == null) { return; } //3. 创建 EventHandler 子类的实例。
myHandler = new MyEventHandler(runner);
//4. 获取 InnerEvent 事件。
int eventId1 = 0;
int eventId2 = 1;
long param = 0;
Object object = null;
InnerEvent event1 = InnerEvent.get(eventId1, param, object);
InnerEvent event2 = InnerEvent.get(eventId2, param, object);
//5. 投递事件,投递的优先级以 IMMEDIATE 为例,延时选择 0ms 和 2ms。
myHandler.sendEvent(event1, 0, EventHandler.Priority.IMMEDIATE); // 延时 2ms 后立即处理
myHandler.sendEvent(event2, 2, EventHandler.Priority.IMMEDIATE); //6. 启动和停止 EventRunner,如果为托管模式,则不需要此步骤。

runner.run();

//待执行操作 // … 执行业务逻辑
// 停止 EventRunner runner.stop(); } /
** * EventHandler 投递 Runnable 任务 */

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数HarmonyOS鸿蒙开发工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年HarmonyOS鸿蒙开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
img

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

大厂,18年进入阿里一直到现在。**

深知大多数HarmonyOS鸿蒙开发工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年HarmonyOS鸿蒙开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-cwm7KbA2-1712844820896)]
[外链图片转存中…(img-2RnVR8Hx-1712844820896)]
[外链图片转存中…(img-qeK7WhTi-1712844820896)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
[外链图片转存中…(img-WfD8nAlj-1712844820897)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值