loadData();
}
loadData() async {
String dataURL = “https://jsonplaceholder.typicode.com/posts”;
http.Response response = await http.get(dataURL);
setState(() {
widgets = json.decode(response.body);
});
}
}
Future
Future
就是延时操作的一个封装,可以将异步任务封装为Future
对象。获取到Future
对象后,最简单的方法就是用await
修饰,并等待返回结果继续向下执行。正如上面async、await
中讲到的,使用await
修饰时需要配合async
一起使用。
在Dart
中,和时间相关的操作基本都和Future
有关,例如延时操作、异步操作等。下面是一个很简单的延时操作,通过Future
的delayed
方法实现。
loadData() {
// DateTime.now(),获取当前时间
DateTime now = DateTime.now();
print(‘request begin $now’);
Future.delayed(Duration(seconds: 1), (){
now = DateTime.now();
print(‘request response $now’);
});
}
Dart
还支持对Future
的链式调用,通过追加一个或多个then
方法来实现,这个特性非常实用。例如一个延时操作完成后,会调用then
方法,并且可以传递一个参数给then
。调用方式是链式调用,也就代表可以进行很多层的处理。这有点类似于iOS的RAC
框架,链式调用进行信号处理。
Future.delayed(Duration(seconds: 1), (){
int age = 18;
return age;
}).then((onValue){
onValue++;
print(‘age $onValue’);
});
协程
如果想要了解async
、await
的原理,就要先了解协程的概念,async
、await
本质上就是协程的一种语法糖。协程,也叫作coroutine
,是一种比线程更小的单元。如果从单元大小来说,基本可以理解为进程->线程->协程。
任务调度
在弄懂协程之前,首先要明白并发和并行的概念,并发指的是由系统来管理多个IO的切换,并交由CPU去处理。并行指的是多核CPU在同一时间里执行多个任务。
并发的实现由非阻塞操作+事件通知来完成,事件通知也叫做“中断”。操作过程分为两种,一种是CPU对IO进行操作,在操作完成后发起中断告诉IO操作完成。另一种是IO发起中断,告诉CPU可以进行操作。
线程本质上也是依赖于中断来进行调度的,线程还有一种叫做“阻塞式中断”,就是在执行IO操作时将线程阻塞,等待执行完成后再继续执行。但线程的消耗是很大的,并不适合大量并发操作的处理,而通过单线程并发可以进行大量并发操作。当多核CPU出现后,单个线程就无法很好的利用多核CPU的优势了,所以又引入了线程池的概念,通过线程池来管理大量线程。
协程
在程序执行过程中,离开当前的调用位置有两种方式,继续调用其他函数和return
返回离开当前函数。但是执行return
时,当前函数在调用栈中的局部变量、形参等状态则会被销毁。
协程分为无线协程和有线协程,无线协程在离开当前调用位置时,会将当前变量放在堆区,当再次回到当前位置时,还会继续从堆区中获取到变量。所以,一般在执行当前函数时就会将变量直接分配到堆区,而async
、await
就属于无线协程的一种。有线协程则会将变量继续保存在栈区,在回到指针指向的离开位置时,会继续从栈中取出调用。
async、await原理
以async
、await
为例,协程在执行时,执行到async
则表示进入一个协程,会同步执行async
的代码块。async
的代码块本质上也相当于一个函数,并且有自己的上下文环境。当执行到await
时,则表示有任务需要等待,CPU则去调度执行其他IO,也就是后面的代码或其他协程代码。过一段时间CPU就会轮训一次,看某个协程是否任务已经处理完成,有返回结果可以被继续执行,如果可以被继续执行的话,则会沿着上次离开时指针指向的位置继续执行,也就是await
标志的位置。
由于并没有开启新的线程,只是进行IO中断改变CPU调度,所以网络请求这样的异步操作可以使用async
、await
,但如果是执行大量耗时同步操作的话,应该使用isolate
开辟新的线程去执行。
如果用协程和iOS的dispatch_async
进行对比,可以发现二者是比较相似的。从结构定义来看,协程需要将当前await
的代码块相关的变量进行存储,dispatch_async
也可以通过block
来实现临时变量的存储能力。
我之前还在想一个问题,苹果为什么不引入协程的特性呢?后来想了一下,await
和dispatch_async
都可以简单理解为异步操作,OC的线程是基于Runloop
实现的,Dart
本质上也是有事件循环的,而且二者都有自己的事件队列,只是队列数量和分类不同。
我觉得当执行到await
时,保存当前的上下文,并将当前位置标记为待处理任务,用一个指针指向当前位置,并将待处理任务放入当前isolate
的队列中。在每个事件循环时都去询问这个任务,如果需要进行处理,就恢复上下文进行任务处理。
Promise
这里想提一下JS
里的Promise
语法,在iOS中会出现很多if
判断或者其他的嵌套调用,而Promise
可以把之前横向的嵌套调用,改成纵向链式调用。如果能把Promise
引入到OC里,可以让代码看起来更简洁,直观。
isolate
isolate
是Dart
平台对线程的实现方案,但和普通Thread
不同的是,isolate
拥有独立的内存,isolate
由线程和独立内存构成。正是由于isolate
线程之间的内存不共享,所以isolate
线程之间并不存在资源抢夺的问题,所以也不需要锁。
通过isolate
可以很好的利用多核CPU,来进行大量耗时任务的处理。isolate
线程之间的通信主要通过port
来进行,这个port
消息传递的过程是异步的。通过Dart
源码也可以看出,实例化一个isolate
的过程包括,实例化isolate
结构体、在堆中分配线程内存、配置port
等过程。
isolate
看起来其实和进程比较相似,之前请教阿里架构师宗心问题时,宗心也说过“isolate
的整体模型我自己的理解其实更像进程,而async
、await
更像是线程”。如果对比一下isolate
和进程的定义,会发现确实isolate
很像是进程。
代码示例
下面是一个isolate
的例子,例子中新创建了一个isolate
,并且绑定了一个方法进行网络请求和数据解析的处理,并通过port
将处理好的数据返回给调用方。
loadData() async {
// 通过spawn新建一个isolate,并绑定静态方法
ReceivePort receivePort =ReceivePort();
await Isolate.spawn(dataLoader, receivePort.sendPort);
// 获取新isolate的监听port
SendPort sendPort = await receivePort.first;
// 调用sendReceive自定义方法
List dataList = await sendReceive(sendPort, ‘https://jsonplaceholder.typicode.com/posts’);
print(‘dataList $dataList’);
}
// isolate的绑定方法
static dataLoader(SendPort sendPort) async{
// 创建监听port,并将sendPort传给外界用来调用
ReceivePort receivePort =ReceivePort();
sendPort.send(receivePort.sendPort);
// 监听外界调用
await for (var msg in receivePort) {
String requestURL =msg[0];
SendPort callbackPort =msg[1];
Client client = Client();
Response response = await client.get(requestURL);
List dataList = json.decode(response.body);
// 回调返回值给调用者
callbackPort.send(dataList);
}
}
// 创建自己的监听port,并且向新isolate发送消息
Future sendReceive(SendPort sendPort, String url) {
ReceivePort receivePort =ReceivePort();
sendPort.send([url, receivePort.sendPort]);
// 接收到返回值,返回给调用者
return receivePort.first;
}
isolate
和iOS中的线程还不太一样,isolate
的线程更偏底层。当生成一个isolate
后,其内存是各自独立的,相互之间并不能进行访问。但isolate
提供了基于port
的消息机制,通过建立通信双方的sendPort
和receiveport
,进行相互的消息传递,在Dart
中叫做消息传递。
从上面例子中可以看出,在进行isolate
消息传递的过程中,本质上就是进行port
的传递。将port
传递给其他isolate
,其他isolate
通过port
拿到sendPort
,向调用方发送消息来进行相互的消息传递。
Embedder
正如其名,Embedder
是一个嵌入层,将Flutter
嵌入到各个平台上。Embedder
负责范围包括原生平台插件、线程管理、事件循环等。
Embedder
中存在四个Runner
,四个Runner
分别如下。其中每个Flutter Engine
各自对应一个UI Runner
、GPU Runner
、IO Runner
,但所有Engine
共享一个Platform Runner
。
Runner
和isolate
并不是一码事,彼此相互独立。以iOS平台为例,Runner
的实现就是CFRunLoop
,以一个事件循环的方式不断处理任务。并且Runner
不只处理Engine
的任务,还有Native Plugin
带来的原生平台的任务。而isolate
则由Dart VM
进行管理,和原生平台线程并无关系。
Platform Runner
Platform Runner
和iOS平台的Main Thread
非常相似,在Flutter
中除耗时操作外,所有任务都应该放在Platform
中,Flutter
中的很多API并不是线程安全的,放在其他线程中可能会导致一些bug。
但例如IO之类的耗时操作,应该放在其他线程中完成,否则会影响Platform
的正常执行,甚至于被watchdog
干掉。但需要注意的是,由于Embedder Runner
的机制,Platform
被阻塞后并不会导致页面卡顿。
不只是Flutter Engine
的代码在Platform
中执行,Native Plugin
的任务也会派发到Platform
中执行。实际上,在原生侧的代码运行在Platform Runner
中,而Flutter
侧的代码运行在Root Isolate
中,如果在Platform
中执行耗时代码,则会卡原生平台的主线程。
UI Runner
UI Runner
负责为Flutter Engine
执行Root Isolate
的代码,除此之外,也处理来自Native Plugin
的任务。Root Isolate
为了处理自身事件,绑定了很多函数方法。程序启动时,Flutter Engine
会为Root
绑定UI Runner
的处理函数,使Root Isolate
具备提交渲染帧的能力。
当Root Isolate
向Engine
提交一次渲染帧时,Engine
会等待下次vsync,当下次vsync到来时,由Root Isolate
对Widgets
进行布局操作,并生成页面的显示信息的描述,并将信息交给Engine
去处理。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://img-blog.csdnimg.cn/img_convert/ffc1063d4c44f98e621a8cde58c794c7.jpeg)
最后
说一千道一万,不如自己去行动。要想在移动互联网的下半场是自己占有一席之地,那就得从现在开始,从今天开始,马上严格要求自己,既重视业务实现能力,也重视基础和原理。基础夯实好了,高楼才能够平地而起,稳如泰山。
最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的24套腾讯、字节跳动、阿里、百度2020-2021面试真题解析,我把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节。
还有 高级架构技术进阶脑图、Android开发面试专题资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!