Code前端首页关于Code前端联系我们

Flutter开发实践五:深入探索一些有趣的原理

terry 2年前 (2023-09-23) 阅读数 66 #移动小程序

1. WidgetsFlutterBinding

这是一个粘合类。

1。Mixins

混入( ̄. ̄)!

是的,Flutter使用Dart来支持Mixin,Mixin可以更好地解决多重继承中容易出现的问题,例如:方法优先级混乱、参数冲突。好复杂等等。

Mixin 的定义解释起来有点混乱,所以我们来看代码。如下代码所示,在Dart中使用进行混合。可以看出,G类超过B与A,A2。执行G的方法a、b、c后,输出A2.a()、A.b()、B.c()。 。所以唯一的结论就是覆盖了同样的方法,后面的方法会覆盖之前的

class A {
  a() {
    print("A.a()");
  }

  b() {
    print("A.b()");
  }
}

class A2 {
  a() {
    print("A2.a()");
  }
}

class B {
  a() {
    print("B.a()");
  }

  b() {
    print("B.b()");
  }

  c() {
    print("B.c()");
  }
}

class G extends B with A, A2 {

}


testMixins() {
  G t = new G();
  t.a();
  t.b();
  t.c();
}

/// ***********************输出***********************
///I/flutter (13627): A2.a()
///I/flutter (13627): A.b()
///I/flutter (13627): B.c()

复制代码

接下来我们继续修改代码。如下所示,我们定义了一个抽象类BaseA、A2、B都被继承,并在之后执行super。 ()操作。

从最后的输入可以看出,A,A2,B

中的所有方法都被执行了,而且只执行了一次,执行顺序也是一样的。大约。如果您从下面代码中的 A.a() 类方法中删除 super,您将看不到 B.a()base a() 的输出。


abstract class Base {
  a() {
    print("base a()");
  }

  b() {
    print("base b()");
  }

  c() {
    print("base c()");
  }
}

class A extends Base {
  a() {
    print("A.a()");
    super.a();
  }

  b() {
    print("A.b()");
    super.b();
  }
}

class A2 extends Base {
  a() {
    print("A2.a()");
    super.a();
  }
}

class B extends Base {
  a() {
    print("B.a()");
    super.a();
  }

  b() {
    print("B.b()");
    super.b();
  }

  c() {
    print("B.c()");
    super.c();
  }
}

class G extends B with A, A2 {

}

testMixins() {
  G t = new G();
  t.a();
  t.b();
  t.c();
}

///I/flutter (13627): A2.a()
///I/flutter (13627): A.a()
///I/flutter (13627): B.a()
///I/flutter (13627): base a()
///I/flutter (13627): A.b()
///I/flutter (13627): B.b()
///I/flutter (13627): base b()
///I/flutter (13627): B.c()
///I/flutter (13627): base c()

复制代码

2。 WidgetsFlutterBinding

说了很多,Mixins在Flutter中还有什么意义呢?此时我们应该看到 Flutter 中的“粘合类”:WidgetsFlutterBinding

WidgetsFlutterBinding 当 Flutter 启动时,runApp 将被调用。作为App的网关,必须承担各种初始化和功能配置。在这种情况下,Mixins的作用就体现出来了。 。Flutter开发实战五:深入探索一些有趣原理Flutter开发实战五:深入探索一些有趣原理

从上图中可以看到,WidgetsFlutterBinding本身没有任何代码。主要继承了BindingBase,然后附加到各种Binding,这就是BindingBindingFlutter开发实战五:深入探索一些有趣原理

您是否注意到,这里的每个Binding都可以单独使用,也可以“粘合”到WidgetFlutterBinding。这样做的效果是不是比Level级别的继承结构更清晰?

最后我们打印执行顺序,如下图。所以,果然如此ヽ( ̄▽ ̄)ノ。 Flutter开发实战五:深入探索一些有趣原理

2。 InheritedWidget

InheritedWidget是一个抽象类,在Flutter中起着重要的作用。也许你没有直接使用过它,但你应该使用与其相关的包。 Flutter开发实战五:深入探索一些有趣原理

如上图所示,Inherited Widget主要实现了两个方法:

  • 创建InheritedElement,Element ❀❀属于特殊Element,主要添加还添加到表映射关系_inheritedWidgets[注1],方便后代获取元素;同时,通过 notifyClients 方法更新依赖项。
  • 添加了方法updateShouldNotify。当该方法返回 true 时,Widget 的依赖实例将被更新。

所以我们只能这样理解:InheritedWidget是通过InheritedElement实现从下往上的搜索支持(因为它是添加到❀❀中的,已经从它的后代Function更新了。? heritedWidget 对应元素之间的映射关系。 Flutter开发实战五:深入探索一些有趣原理

然后我们看BuildContext,如上图,BuildContext其实只是一个接口,而元素。 InheritedElementElement 的子类,因此 的每个 InheritedElement 都是 BuildContext 的实例。同时,我们日常使用的BuildContext也是一个Element。

所以如果我们必须共享状态,那么一层一层地遍历状态来获得共享将是非常困难的。那么知道上面的Legacy Widget后会发生什么呢?

是否可以将所有需要共享的状态都放在InheritedWidget中,然后在使用的widget中直接访问?答案是肯定的!所以代码如下: 通常,像焦点、主题颜色、多语言、用户信息等,App中全局共享的所有数据,都会通过BuildContext(InheritedElement)获取。

///收起键盘
FocusScope.of(context).requestFocus(new FocusNode());

/// 主题色
Theme.of(context).primaryColor

/// 多语言
Localizations.of(context, GSYLocalizations)
 
/// 通过 Redux 获取用户信息
StoreProvider.of(context).userInfo

/// 通过 Redux 获取用户信息
StoreProvider.of(context).userInfo

/// 通过 Scope Model 获取用户信息
ScopedModel.of<UserInfo>(context).userInfo

复制代码

作为总结,让我们从主题开始。

如下代码所示,通过将主题数据设置为MaterialApp,可以通过Theme.of(context)获取并使用主题数据当主题数据MaterialApp发生变化时,对应Widget的颜色也会发生变化。为什么会这样(キ`゚Д゚´)!!?山通过源码搜索层,可以找到这样的嵌套:MateriaLapp->Animatedtheme->Theme->_inheritedTheme Extends InheritedWidget Nested under Inherited小部件

Flutter开发实战五:深入探索一些有趣原理

如上图,通过Theme.from(context)获得的主题数据实际上是通过context.inheritFromWidgetOfExactType(_InheritedTheme(_InheritedTheme),

bool updateShouldNotify(_InheritedTheme old) => theme.data != old.theme.data;
复制代码
Flutter开发实战五:深入探索一些有趣原理

中获得inheritFromWidgetOfExactType ) 方法BuildContext是在Element上实现的,如下图:,记住上面的。tedWidget

?因为InheritedElement 已存在于 _inheritedWidgets 中,

上一篇:InheritedWidget中的InheritedElement,这个元素是一个特殊的Element,主要是把自己添加到映射表_inheritedWidgets

最后如下图,在继承 edElement 在 中定义 › 更新 ClientFlutter开发实战五:深入探索一些有趣原理

updateShouldNotify

方法 Widget 继承,例如,在 主题来自_继承作为主题、Redux、范围模型和本地化的核心,所有继承的小部件

3。内存

近日,闲鱼科技发布了《Flutter之禅 内存优化篇》。文章对Flutter内存做了深入的探索。一个有趣的发现是:Flutter 中的

  • ImageCache 存储 ImageStream 对象。 ,即缓存是一个异步图像对象。
  • 在图像加载和解码之前,无法知道将使用多少内存。
  • 很容易产生很多IO操作,导致内存峰值非常高。
Flutter开发实战五:深入探索一些有趣原理

如上图所示,与图片缓存相关的流程,目前的瓶颈处理是:

  • 页面不可见时无需发送额外图片
  • 限制缓存图片数量
  • 如果合适,CG

可以阅读文章本身以获得更详细的内容。为什么这里提到这个呢?这是因为限制了缓存图像的数量

你还记得WidgetsFlutterBinding这个粘合类吗?其中,Mixins 是PaintingBinding,如下图所示,“粘合”绑定负责图像缓存Flutter开发实战五:深入探索一些有趣原理

ImageCache中存在一个对象PaintingBindingFlutter开发实战五:深入探索一些有趣原理

对象,该对象是一个全局单例,由ImageProvider用来设置图像大小,像图像设置如下:

//缓存个数 100
PaintingBinding.instance.imageCache.maximumSize=100;
//缓存大小 50m
PaintingBinding.instance.imageCache.maximumSizeBytes= 50 << 20;
复制代码

4。线程

深入理解闲鱼Flutter Platform Channel技术 中提到:Flutter中主要有四个线程,Platform Task Runner、UI Task Runner、GPU Task Runner和IO Task Runner。

其中,Platform Task Runner是Android和iOS主线程,UI Task Runner是Flutter UI线程。

如下图,如果你在 Flutter 中做过 Dart 和 Native 端的通信,应该知道,通过 平台通道,通信的两端是 平台任务运行器❀ 以及UI Task Runner ,这里主要总结一下:

  • 因为Platform Task Runner是原来的主线程,所以尽量不要在Platform端进行耗时的操作。
  • 由于Platform Channel不是线程安全的,当消息处理的结果发送回Flutter端时,必须保证回调函数是在Platform Thread(即Android的主线程和iOS)。
Flutter开发实战五:深入探索一些有趣原理

5。热更新

未完成的请求。

  • 1。首先,我们知道Flutter仍然是一个iOS/Android项目。
  • 2。 Flutter 通过在 BuildPhase 中添加 shell(xcode_backend.sh)来生成并嵌入 App.frameworkFlutter.framework 到 IOS 中。
  • 3。通过 Gradle 引用 Flutter flutter.jar 并将 binary 添加到 Android。

编译后的 Android 二进制文件位于 data/data/packagename/app_flutter/flutter_assets/ 下。用过Android的人应该都知道,通过这种方式可以轻松更新,所以你就知道 ̄ω ̄=。

iOS?据我所知,动态库、框架之类的引用好像是不能热更新的,除非你不再需要它们了!

作者:连毛德小果
链接:https://juejin.im/post/5bc450dff265da0a951f032b
来源:掘金商业转载请联系作者授权。非商业转载请注明出处。

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门