07_Flutter使用NestedScrollView+TabBarView滚动位置共享问题修复

07_Flutter使用NestedScrollView+TabBarView滚动位置共享问题修复

一.案发现场

在这里插入图片描述

可以看到,上图中三个列表的滑动位置共享了,滑动其中一个列表,会影响到另外两个,这显然不符合要求,先来看下布局,再说明产生这个问题的原因:

  • 布局整体使用NestedScrollView,顶部banner和TabBar通过headerSliverBuilder创建,body为TabBarView,TabBarView中有三个列表,通过TabController与TabBar实现联动,同时每一个列表通过继承StatefulWidget构建并混入AutomaticKeepAliveClientMixin,重写wantKeepAlive的getter方法返回true,这样可以保证每次切换Tab的时候,ListView不会重新创建,实现懒加载。

    NestedScrollView(headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {return [SliverToBoxAdapter(child: Container(height: 200,color: Colors.red,alignment: Alignment.center,child: const Text("banner",style: TextStyle(color: Colors.white,fontSize: 16),),),),SliverOverlapAbsorber(handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),sliver: StickySliverToBoxAdapter(child: Container(color: Colors.white,child: TabBar(tabs: List.generate(_tabs.length, (index) {return Padding(padding: const EdgeInsets.symmetric(vertical: 15),child: Text(_tabs[index]),);}),unselectedLabelColor: const Color(0xFF7B7B7B),labelColor: const Color(0xFF5E80FF),isScrollable: false,indicatorSize: TabBarIndicatorSize.label,indicator: UnderlineTabIndicator(borderRadius: BorderRadius.circular(3),borderSide: const BorderSide(color: Color(0xFF5E80FF), width: 3),insets: const EdgeInsets.symmetric(horizontal: 3, vertical: 9)),controller: _tabController,),),),),];},body: LayoutBuilder(builder: (context, _) {return Container(padding: EdgeInsets.only(top: NestedScrollView.sliverOverlapAbsorberHandleFor(context).layoutExtent ?? 0),child: NestedTabBarView(controller: _tabController,children: List.generate(_tabs.length, (index) {return _TabInnerListView(tabName: _tabs[index],);})));})
    )class _TabInnerListViewState extends State<_TabInnerListView> with AutomaticKeepAliveClientMixin {final int length = 20;Widget build(BuildContext context) {return CustomScrollView(physics: const ClampingScrollPhysics(),slivers: [...(List.generate(length, (index) {return SliverToBoxAdapter(child: Container(height: 100,margin: const EdgeInsets.only(top: 16, left: 16, right: 16),color: Colors.orange,alignment: Alignment.center,child: Text("${widget.tabName} item $index",style: const TextStyle(color: Colors.white),),),);})),const SliverToBoxAdapter(child: SizedBox(height: 16,),)],);}bool get wantKeepAlive => true;}
    
  • 上述问题产生的原因,需要追踪NestedScrollView的源码,NestedScrollView整体的布局结构如下:

    在这里插入图片描述

    如果没有_NestedScrollCoordinator的加持,那么外层的CustomScrollView和内层的CustomScrollView就会各划各的。_NestedScrollCoordinator处理嵌套滑动是在applyUserOffset方法中完成的:

    class _NestedScrollCoordinator implements ScrollActivityDelegate, ScrollHoldController {void applyUserOffset(double delta) {updateUserScrollDirection(delta > 0.0 ? ScrollDirection.forward : ScrollDirection.reverse,);assert(delta != 0.0);if (_innerPositions.isEmpty) {_outerPosition!.applyFullDragUpdate(delta);} else if (delta < 0.0) {...} else {double innerDelta = delta;if (_floatHeaderSlivers) {innerDelta = _outerPosition!.applyClampedDragUpdate(delta);}if (innerDelta != 0.0) {double outerDelta = 0.0;final List<double> overscrolls = <double>[];final List<_NestedScrollPosition> innerPositions = _innerPositions.toList();for (final _NestedScrollPosition position in innerPositions) {final double overscroll = position.applyClampedDragUpdate(innerDelta);outerDelta = math.max(outerDelta, overscroll);overscrolls.add(overscroll);}if (outerDelta != 0.0) {outerDelta -= _outerPosition!.applyClampedDragUpdate(outerDelta);}for (int i = 0; i < innerPositions.length; ++i) {final double remainingDelta = overscrolls[i] - outerDelta;if (remainingDelta > 0.0) {innerPositions[i].applyFullDragUpdate(remainingDelta);}}}}}
    }
    

    可以看到在applyUserOffset中,是通过_NestedScrollPosition的applyFullDragUpdate响应滑动事件的,如果调用_outerPosition!.applyFullDragUpdate,则外层的CustomScrollView滑动。同理,内层CustomScrollView滑动,只不过applyUserOffset在处理内层滑动时,是遍历innerPositions把所有内层CustomScrollView的_NestedScrollPosition滚动相同的位移。

    _NestedScrollPosition? get _outerPosition {if (!_outerController.hasClients) {return null;}return _outerController.nestedPositions.single;
    }Iterable<_NestedScrollPosition> get _innerPositions {return _innerController.nestedPositions;
    }
    

    这也就解释了上图中,为什么滚动其中一个列表,其他列表也会跟着滑动相同的位置?。

二.解决方案

综上所述,_NestedScrollCoordinator的_innerPositions的返回结果是所有内层CustomScrollView的_NestedScrollPosition,要解决这个问题,我们只需要想办法将_NestedScrollCoordinator的_innerPositions的返回结果改变成只包含当前选中的内层CustomScrollView的_NestedScrollPosition即可,而_innerPositions的取值是来源于_innerController的nestedPositions。_innerController是一个_NestedScrollController对象,接着看_NestedScrollController的源码:

class _NestedScrollController extends ScrollController {...ScrollPosition createScrollPosition(ScrollPhysics physics,ScrollContext context,ScrollPosition? oldPosition,) {return _NestedScrollPosition(coordinator: coordinator,physics: physics,context: context,initialPixels: initialScrollOffset,oldPosition: oldPosition,debugLabel: debugLabel,);}void attach(ScrollPosition position) {assert(position is _NestedScrollPosition);super.attach(position);coordinator.updateParent();coordinator.updateCanDrag();position.addListener(_scheduleUpdateShadow);_scheduleUpdateShadow();}void detach(ScrollPosition position) {assert(position is _NestedScrollPosition);(position as _NestedScrollPosition).setParent(null);position.removeListener(_scheduleUpdateShadow);super.detach(position);_scheduleUpdateShadow();}...Iterable<_NestedScrollPosition> get nestedPositions {// TODO(vegorov): use instance method version of castFrom when it is available.return Iterable.castFrom<ScrollPosition, _NestedScrollPosition>(positions);}
}

可以看到_NestedScrollController是私有类,并且NestedScrollView从头到尾都没有暴露任何可以修改或替换_innerController的方法给我们,因此,想在外部直接修改是不可能的。怎么办呢?

首先,内层的每一个CustomScrollView都是我们在外部人为编写的,我们可以在外部给内层的每一个CustomScrollView重新指定ScrollController,虽然暂时没什么卵用😄,但是别着急。

class _TabInnerListViewState extends State<_TabInnerListView> with AutomaticKeepAliveClientMixin {final int length = 20;late ScrollController _scrollController;void initState() {super.initState();_scrollController = ScrollController();}void dispose() {_scrollController.dispose();super.dispose();}Widget build(BuildContext context) {return CustomScrollView(controller: _scrollController,physics: const ClampingScrollPhysics(),slivers: [...(List.generate(length, (index) {return SliverToBoxAdapter(child: Container(height: 100,margin: const EdgeInsets.only(top: 16, left: 16, right: 16),color: Colors.orange,alignment: Alignment.center,child: Text("${widget.tabName} item $index",style: const TextStyle(color: Colors.white),),),);})),const SliverToBoxAdapter(child: SizedBox(height: 16,),)],);}bool get wantKeepAlive => true;}

在这里插入图片描述

可以看到,此时嵌套滑动失效了,这是因为我们为内层的每一个CustomScrollView单独指定ScrollController后,CustomScrollView的滑动全部交给了这个这个ScrollController处理,跟NestedScrollView的_innerController已经没有半毛钱关系了。既然没有关系,那我们就建立关系,怎么建立:

  • 创建NestedInnerScrollController类继承ScrollController

  • 重写createScrollPosition方法,通过PrimaryScrollController.maybeOf(context)获取NestedScrollView的_innerController,将createScrollPosition转交给_innerController完成

  • 重写attach方法,将attach转交给_innerController完成

  • 重写detach方法,将detach转交给_innerController完成

  • 为每一个内层的CustomScrollView指定controller为NestedInnerScrollController的实例

    class NestedInnerScrollController extends ScrollController {ScrollController? _inner;NestedInnerScrollController();ScrollPosition createScrollPosition(ScrollPhysics physics, ScrollContext context, ScrollPosition? oldPosition) {ScrollPosition scrollPosition;ScrollableState? scrollableState = context as ScrollableState;if(scrollableState != null) {_inner = PrimaryScrollController.maybeOf(scrollableState.context);}if(_inner == null) {scrollPosition = super.createScrollPosition(physics, context, oldPosition);} else {scrollPosition = _inner!.createScrollPosition(physics, context, oldPosition);}return scrollPosition;}void attach(ScrollPosition position) {super.attach(position);_inner?.attach(position);}void detach(ScrollPosition position) {_inner?.detach(position);super.detach(position);}}class _TabInnerListViewState extends State<_TabInnerListView> with AutomaticKeepAliveClientMixin {final int length = 20;late ScrollController _scrollController;void initState() {super.initState();_scrollController = NestedInnerScrollController();}void dispose() {_scrollController.dispose();super.dispose();}Widget build(BuildContext context) {return CustomScrollView(controller: _scrollController,physics: const ClampingScrollPhysics(),slivers: [...(List.generate(length, (index) {return SliverToBoxAdapter(child: Container(height: 100,margin: const EdgeInsets.only(top: 16, left: 16, right: 16),color: Colors.orange,alignment: Alignment.center,child: Text("${widget.tabName} item $index",style: const TextStyle(color: Colors.white),),),);})),const SliverToBoxAdapter(child: SizedBox(height: 16,),)],);}bool get wantKeepAlive => true;}
    

    在这里插入图片描述

可以看到,嵌套滑动它又回来了😄。那么接下来…,就只剩下解决共享滑动了:

  • 将TabBarView单独定义成StatefulWidget,这样我们就可以很方便的为每一个内层的CustomScrollView维护上面定义好的NestedInnerScrollController,同时通过TabController监听TabBar的选中状态。

    class NestedTabBarView extends StatefulWidget {final TabController? controller;final List<Widget> children;final ScrollPhysics? physics;final DragStartBehavior dragStartBehavior;final double viewportFraction;final Clip clipBehavior;const NestedTabBarView({super.key,required this.children,this.controller,this.physics,this.dragStartBehavior = DragStartBehavior.start,this.viewportFraction = 1.0,this.clipBehavior = Clip.hardEdge,});State<StatefulWidget> createState() => _NestedTabBarViewState();
    }class _NestedTabBarViewState extends State<NestedTabBarView> {List<NestedInnerScrollController> _nestedInnerControllers = [];void initState() {super.initState();_initNestedInnerControllers();widget.controller?.addListener(_onTabChange);}void didUpdateWidget(covariant NestedTabBarView oldWidget) {super.didUpdateWidget(oldWidget);if(oldWidget.children.length != widget.children.length) {_initNestedInnerControllers();}}void dispose() {widget.controller?.removeListener(_onTabChange);_disposeNestedInnerControllers();super.dispose();}void _onTabChange() {}void _initNestedInnerControllers() {_disposeNestedInnerControllers();List<NestedInnerScrollController> controllers = List.generate(widget.children.length, (index) {return NestedInnerScrollController();});if(mounted) {setState(() {_nestedInnerControllers = controllers;});} else {_nestedInnerControllers = controllers;}}void _disposeNestedInnerControllers() {_nestedInnerControllers.forEach((element) {element.dispose();});}Widget build(BuildContext context) {return TabBarView(controller: widget.controller,physics: widget.physics,dragStartBehavior: widget.dragStartBehavior,viewportFraction: widget.viewportFraction,clipBehavior: widget.clipBehavior,children: widget.children);}
    }
    
  • 使用InheritedWidget,将NestedInnerScrollController暴露给对应的内层CustomScrollView使用

    class _InheritedInnerScrollController extends InheritedWidget {final ScrollController controller;const _InheritedInnerScrollController({required super.child,required this.controller});bool updateShouldNotify(covariant _InheritedInnerScrollController oldWidget) => controller != oldWidget.controller;}class _NestedTabBarViewState extends State<NestedTabBarView> {...Widget build(BuildContext context) {return TabBarView(controller: widget.controller,physics: widget.physics,dragStartBehavior: widget.dragStartBehavior,viewportFraction: widget.viewportFraction,clipBehavior: widget.clipBehavior,children: List<Widget>.generate(widget.children.length, (index) {return _InheritedInnerScrollController(controller: _nestedInnerControllers[index],child: widget.children[index],);}));}
    }class NestedInnerScrollController extends ScrollController {...static ScrollController of(BuildContext context) {final _InheritedInnerScrollController? target = context.dependOnInheritedWidgetOfExactType<_InheritedInnerScrollController>();assert(target != null,'NestedInnerScrollController.of must be called with a context that contains a NestedTabBarView\'s children.',);return target!.controller;}static ScrollController? maybeOf(BuildContext context) {final _InheritedInnerScrollController? target = context.dependOnInheritedWidgetOfExactType<_InheritedInnerScrollController>();return target?.controller;}}class _TabInnerListViewState extends State<_TabInnerListView> with AutomaticKeepAliveClientMixin {final int length = 20;Widget build(BuildContext context) {return CustomScrollView(controller: NestedInnerScrollController.maybeOf(context),physics: const ClampingScrollPhysics(),slivers: [...],);}bool get wantKeepAlive => true;}
    

    使用的时候

    NestedScrollView(headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {return [...];},body: LayoutBuilder(builder: (context, _) {return Container(padding: EdgeInsets.only(top: NestedScrollView.sliverOverlapAbsorberHandleFor(context).layoutExtent ?? 0),child: NestedTabBarView(controller: _tabController,children: List.generate(_tabs.length, (index) {return _TabInnerListView(tabName: _tabs[index],);})));})
    )
    
  • 监听TabBar的选中状态,然后通过NestedInnerScrollController将NestedScrollView的_innerController中所有的ScrollPosition detach,然后再attach与当前选中的NestedInnerScrollController对应的ScrollPosition。

    class NestedInnerScrollController extends ScrollController {...void attachCurrent() {if(_inner != null) {while(_inner!.positions.isNotEmpty) {_inner!.detach(_inner!.positions.first);}_inner!.attach(position);}}}class _NestedTabBarViewState extends State<NestedTabBarView> {...void _onTabChange() {int index = widget.controller!.index;if (index == widget.controller!.animation?.value) {_nestedInnerControllers[index].attachCurrent();}}...
    }
    

    在这里插入图片描述

搞定。

三.完整代码
class _NestedScrollPageState extends State<NestedScrollPage> with TickerProviderStateMixin {final List<String> _tabs = ["tab1", "tab2", "tab3"];late TabController _tabController;void initState() {super.initState();_tabController = TabController(length: _tabs.length, vsync: this);}void dispose() {_tabController.dispose();super.dispose();}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text("nested scroll"),),body: SafeArea(child: NestedScrollView(headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {return [SliverToBoxAdapter(child: Container(height: 200,color: Colors.red,alignment: Alignment.center,child: const Text("banner",style: TextStyle(color: Colors.white,fontSize: 16),),),),SliverOverlapAbsorber(handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),sliver: StickySliverToBoxAdapter(child: Container(color: Colors.white,child: TabBar(tabs: List.generate(_tabs.length, (index) {return Padding(padding: const EdgeInsets.symmetric(vertical: 15),child: Text(_tabs[index]),);}),unselectedLabelColor: const Color(0xFF7B7B7B),labelColor: const Color(0xFF5E80FF),isScrollable: false,indicatorSize: TabBarIndicatorSize.label,indicator: UnderlineTabIndicator(borderRadius: BorderRadius.circular(3),borderSide: const BorderSide(color: Color(0xFF5E80FF), width: 3),insets: const EdgeInsets.symmetric(horizontal: 3, vertical: 9)),controller: _tabController,),),),),];},body: LayoutBuilder(builder: (context, _) {return Container(padding: EdgeInsets.only(top: NestedScrollView.sliverOverlapAbsorberHandleFor(context).layoutExtent ?? 0),child: NestedTabBarView(controller: _tabController,children: List.generate(_tabs.length, (index) {return _TabInnerListView(tabName: _tabs[index],);})));}))),);}}class _TabInnerListView extends StatefulWidget {final String? tabName;const _TabInnerListView({this.tabName});State<StatefulWidget> createState() => _TabInnerListViewState();}class _TabInnerListViewState extends State<_TabInnerListView> with AutomaticKeepAliveClientMixin {final int length = 20;Widget build(BuildContext context) {return CustomScrollView(controller: NestedInnerScrollController.maybeOf(context),physics: const ClampingScrollPhysics(),slivers: [...(List.generate(length, (index) {return SliverToBoxAdapter(child: Container(height: 100,margin: const EdgeInsets.only(top: 16, left: 16, right: 16),color: Colors.orange,alignment: Alignment.center,child: Text("${widget.tabName} item $index",style: const TextStyle(color: Colors.white),),),);})),const SliverToBoxAdapter(child: SizedBox(height: 16,),)],);}bool get wantKeepAlive => true;}
class NestedTabBarView extends StatefulWidget {final TabController? controller;final List<Widget> children;final ScrollPhysics? physics;final DragStartBehavior dragStartBehavior;final double viewportFraction;final Clip clipBehavior;const NestedTabBarView({super.key,required this.children,this.controller,this.physics,this.dragStartBehavior = DragStartBehavior.start,this.viewportFraction = 1.0,this.clipBehavior = Clip.hardEdge,});State<StatefulWidget> createState() => _NestedTabBarViewState();
}class _NestedTabBarViewState extends State<NestedTabBarView> {List<NestedInnerScrollController> _nestedInnerControllers = [];void initState() {super.initState();_initNestedInnerControllers();widget.controller?.addListener(_onTabChange);}void didUpdateWidget(covariant NestedTabBarView oldWidget) {super.didUpdateWidget(oldWidget);if(oldWidget.children.length != widget.children.length) {_initNestedInnerControllers();}}void dispose() {widget.controller?.removeListener(_onTabChange);_disposeNestedInnerControllers();super.dispose();}void _onTabChange() {int index = widget.controller!.index;if (index == widget.controller!.animation?.value) {_nestedInnerControllers[index].attachCurrent();}}void _initNestedInnerControllers() {_disposeNestedInnerControllers();List<NestedInnerScrollController> controllers = List.generate(widget.children.length, (index) {return NestedInnerScrollController();});if(mounted) {setState(() {_nestedInnerControllers = controllers;});} else {_nestedInnerControllers = controllers;}}void _disposeNestedInnerControllers() {_nestedInnerControllers.forEach((element) {element.dispose();});}Widget build(BuildContext context) {return TabBarView(controller: widget.controller,physics: widget.physics,dragStartBehavior: widget.dragStartBehavior,viewportFraction: widget.viewportFraction,clipBehavior: widget.clipBehavior,children: List<Widget>.generate(widget.children.length, (index) {return _InheritedInnerScrollController(controller: _nestedInnerControllers[index],child: widget.children[index],);}));}
}class _InheritedInnerScrollController extends InheritedWidget {final ScrollController controller;const _InheritedInnerScrollController({required super.child,required this.controller});bool updateShouldNotify(covariant _InheritedInnerScrollController oldWidget) => controller != oldWidget.controller;}class NestedInnerScrollController extends ScrollController {ScrollController? _inner;NestedInnerScrollController();ScrollPosition createScrollPosition(ScrollPhysics physics, ScrollContext context, ScrollPosition? oldPosition) {ScrollPosition scrollPosition;ScrollableState? scrollableState = context as ScrollableState;if(scrollableState != null) {_inner = PrimaryScrollController.maybeOf(scrollableState.context);}if(_inner == null) {scrollPosition = super.createScrollPosition(physics, context, oldPosition);} else {scrollPosition = _inner!.createScrollPosition(physics, context, oldPosition);}return scrollPosition;}void attach(ScrollPosition position) {super.attach(position);_inner?.attach(position);}void detach(ScrollPosition position) {_inner?.detach(position);super.detach(position);}void attachCurrent() {if(_inner != null) {while(_inner!.positions.isNotEmpty) {_inner!.detach(_inner!.positions.first);}_inner!.attach(position);}}static ScrollController of(BuildContext context) {final _InheritedInnerScrollController? target = context.dependOnInheritedWidgetOfExactType<_InheritedInnerScrollController>();assert(target != null,'NestedInnerScrollController.of must be called with a context that contains a NestedTabBarView\'s children.',);return target!.controller;}static ScrollController? maybeOf(BuildContext context) {final _InheritedInnerScrollController? target = context.dependOnInheritedWidgetOfExactType<_InheritedInnerScrollController>();return target?.controller;}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/7684.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【MM32F3270 Micropython】pwm输出

文章目录 前言一、PWM脉宽调制技术介绍二、machine.PWM 类2.1 machine.PWM 类的构造对象2.2 PWM 对象初始化2.3 关闭PWM设备2.4 设置pwm的周期2.5 设置占空比 三、pwm示例代码总结 前言 MicroPython是一种精简的Python 3编程语言实现&#xff0c;旨在在微控制器和嵌入式系统上…

算法分析 KMP算法中next值的计算、0/1背包问题

5.6.1 KMP算法中next值的计算 设模式的长度为m。用蛮力法求解 KMP算法中的 next值时&#xff0c;next[0]可直接给出&#xff0c;计算next[j](1<j<m-1)则需要在 T[0] …T[j-1]中分别取长度为j-1、..、2、1的真前缀和真后缀并比较是否相等&#xff0c;最坏情况下的时间代价…

解析Linux键盘组合键产生信号的完整过程:从硬件中断到信号发送

前言 每一个了解Linux的都知道这样一个知识&#xff0c;CtrlC组合键能够终止一个进程。 个人了解进程相关知识之后知道&#xff0c;一个进程被终止只会有有三种情况&#xff1a; 代码运行完毕&#xff0c;结果正确代码运行完毕&#xff0c;结果不正确代码运行异常&#xff…

鸿蒙OpenHarmony【基于Hi3516DV300开发板(时钟应用开发)】

概述 本文将介绍如何快速搭建基于OpenHarmony标准系统&#xff08;Hi3516DV300开发板&#xff09;的应用开发环境&#xff0c;并基于一个时钟APP示例逐步展示应用的创建、开发、调试和安装等流程。示例代码可以通过本链接获取。 时钟App是一款显示实时时间的应用&#xff0c;…

【GDPU】数据结构实验十 哈夫曼编码

【实验内容】 1、假设用于通信的电文仅由8个字母 {a, b, c, d, e, f, g, h} 构成&#xff0c;它们在电文中出现的概率分别为{ 0.07, 0.19, 0.02, 0.06, 0.32, 0.03, 0.21, 0.10 }&#xff0c;试为这8个字母设计哈夫曼编码。 提示:包含两个过程:&#xff08;1&#xff09;构建…

【iOS】——浅析CALayer

文章目录 一、CALayer介绍二、UIview与CALayer1.区别2.联系 三、CALayer的使用1.初始化方法2.常用属性 四.CALayer坐标系1.position属性和anchorPoint属性2.position和anchorPoint的关系3.position、anchorPoint和frame的关系 五、CALayerDelegate六、CALayer绘图机制1.绘图流程…

利用Jenkins完成Android项目打包

问题和思路 目前存在的问题 打包操作由开发人员完成&#xff0c;这样开发进度容易被打断。 解决问题的思路 将打包操作交测试/产品/开发人员来完成&#xff0c;主要是测试/开发。 按照以上的思路&#xff0c;那么JenkinsGradle的解决方案是比较经济的&#xff0c;实现起来…

鸿蒙内核源码分析(互斥锁篇) | 互斥锁比自旋锁丰满多了

内核中哪些地方会用到互斥锁?看图: 图中是内核有关模块对互斥锁初始化,有文件,有内存,用消息队列等等,使用面非常的广.其实在给内核源码加注的过程中,会看到大量的自旋锁和互斥锁,它们的存在有序的保证了内核和应用程序的正常运行.是非常基础和重要的功能. 概述 自旋锁 和…

5.7 线程

进程&#xff1a;解耦稳定&#xff0c;内容之间是不相关的&#xff0c;通信不便利&#xff0c;理论上进程的软硬件的切换时间以及创建开销非常大。--------》资源共享线程实现 线程的问题&#xff1a;本质就是不解耦&#xff0c;一个出问题别的就很有可能出问题&#xff0c;同…

Scanner中next()、nextInt()、nextLine()、hasNext()、hasNextInt()的使用方法及注意事项

目录 1、next()、nextInt()、nextLine()的使用方法及区分 2、循环时如何使用hasNext方法 3、用hasNextInt()作为判断下一个输入是否为数字需要配合next()方法使用 1、next()、nextInt()、nextLine()的使用方法及区分 三者简单定义 next()&#xff1a;此方法遇见第一个有效字符…

使用AIGC生成软件类图表

文章目录 如何使用 AI 生成软件类图表什么是 MermaidMermaid 的图片如何保存&#xff1f;mermaid.liveDraw.io Mermaid可以画什么图&#xff1f;流程图时序图 / 序列图类图状态图甘特图实体关系图 / ER图 如何使用 AI 生成软件类图表 ChatGPT 大语言模型不能直接生成各类图表。…

linux系统下产生Segmentation fault 与 Segmentation fault (core dumped)!!!

最近在学习的过程中&#xff0c;遇到了Segment fault&#xff08;段错误&#xff09;的问题&#xff0c;经过一番查找资料&#xff0c;学到了一些相关知识&#xff0c;这里做一个梳理&#xff0c;以防以后在遇到类似的问题&#xff0c;并且希望能够帮助到大家一丝丝&#xff01…

python中numpy库使用

array数组 生成array数组 将list转化为array数组 import numpy as np np.array([1,2],typenp.int32)其中dtype定义的是元素类型&#xff0c;np.int32指32位的整形 如果直接定义dtypeint 默认的是32位整形。 zeors和ones方法 zeros()方法&#xff0c;该方法和ones()类似&a…

有什么方便实用的成人口语外教软件?6个软件教你快速进行口语练习

有什么方便实用的成人口语外教软件&#xff1f;6个软件教你快速进行口语练习 口语能力在语言学习中占据着重要的位置&#xff0c;因为它直接关系到我们与他人进行交流和沟通的效果。为了提高口语能力&#xff0c;很多成人选择通过外教软件进行口语练习&#xff0c;这些软件提供…

GNU Radio FFT模块结合stream to vector应用及Rotator频偏模块使用

文章目录 前言一、FFT 模块应用1、stream to vector 介绍2、创建 grc 图测试3、运行结果 二、频偏模块1、Rotator 简介2、创建 grc 图测试3、运行结果 前言 写个博客记录一下自己的蠢劲儿&#xff0c;之前我想用 FFT 模块做一些信号分析的东西&#xff0c;官方的 FFT 模块必须…

营销5.0时代,企业的痛如何解?

进入营销5.0阶段之后&#xff0c;许多企业都需解决连接客户效能低下的问题。针对这个问题&#xff0c;产品经理、软件开发公司包括个人开发者&#xff0c;要怎么找到有效的“解药”&#xff1f; 营销不仅每年都在变化&#xff0c;甚至每天都在变化。 ——现代营销学之父&…

【再探】设计模式—适配器、装饰及外观模式

结构型设计模式是用于设计对象和类之间关系的一组设计模式。一共有7种&#xff1a;适配器模式、装饰器模式、外观模式、桥接模式、组合模式、享元模式及代理模式。 1 适配器模式 需求&#xff1a;在软件维护阶段&#xff0c;已存在的方法与目标接口不匹配&#xff0c;需要个中…

论文阅读:RHO-1:Not All Tokens Are What You Need 选择你需要的 Tokens 参与训练

论文链接&#xff1a;https://arxiv.org/abs/2404.07965 以往的语言模型预训练方法对所有训练 token 统一采用 next-token 预测损失。作者认为“并非语料库中的所有 token 对语言模型训练都同样重要”&#xff0c;这是对这一规范的挑战。作者的初步分析深入研究了语言模型的 t…

记录一个练手的js逆向password

很明显 请求加密了password 全局搜索 有个加密函数(搜不到的可以搜临近的其他的关键字 或者url参数) 搜索的时候一定要仔细分析 我就没有仔细分析 我搞了好久 又是xhr又是hook的(还没hook到) 我当时也是疏忽了 我寻思这个也不是js文件 直到后来 我怎么也找不到 我就猜想 不…

代码随想录算法训练营DAY44|C++动态规划Part6|完全背包理论基础、518.零钱兑换II、377. 组合总和 Ⅳ

文章目录 完全背包理论基础完全背包问题的定义与01背包的核心区别为什么完全背包的循环顺序可以互换&#xff1f;CPP代码 ⭐️518.零钱兑换II思路CPP代码 ⭐️377. 组合总和 Ⅳ思路CPP代码 扩展题 完全背包理论基础 卡码网第52题 文章链接&#xff1a;完全背包理论基础 视频链接…