android inset 管理

目录

简介

Insets管理架构

Insets相关类图

app侧的类

WMS侧的类

inset show的流程

接口

流程

WMS侧确定InsetsSourceControl的流程

两个问题

窗口显示时不改变现有的inset状态

全屏窗口上的dialog 不显示statusbar问题

View 和 DecorView 设置insets信息

输入法显示流程

1. 在某个app侧点击编辑框

2.输入法app接收到显示输入法消息

3.InputMethodManagerService接收到输入法app的显示状态信息

4.输入法窗口接收到showInsets@IWindow 

监听inset 变化

设置Insetscontroller变化监听

应用WindowInsets变化


简介

android 11上新增一套inset管理方法。

Insets 是指系统边衬区的窗口, 包括statusbar, navigation bar, 输入法等, 都在insets管理中。下面说的这些insets即为这些窗口。 

通过insets相关的接口, app可以控制insets窗口的显示, 隐藏, 沉浸式等。

inset 最基本的控制是show 和hide。 在inset 不同的状态下, 应用区的位置也会发生变化, 这部分的计算也是inset控制的重要内容之一。  

insets完整的实现逻辑, 包含app端和服务端,服务端主要是WMS(window manager service)。 本文梳理insets的管理架构和主要逻辑, 如show insets 等。

下面为dump 出来的insets信息, 使用命令adb shell dumpsys window。 InsetsState 是系统当前所有inset状态的集合,InsetsSource 对应每一个inset, 包括type, frame, visible项: 

 InsetsState
      InsetsSource type=ITYPE_STATUS_BAR frame=[0,0][2776,130] visible=false
      InsetsSource type=ITYPE_NAVIGATION_BAR frame=[0,0][744,1022] visible=false
      InsetsSource type=ITYPE_TOP_GESTURES frame=[0,0][2776,130] visible=true
      InsetsSource type=ITYPE_BOTTOM_GESTURES frame=[0,1017][744,1022] visible=true
      InsetsSource type=ITYPE_LEFT_GESTURES frame=[0,0][0,1022] visible=true
      InsetsSource type=ITYPE_RIGHT_GESTURES frame=[2776,0][2776,1022] visible=true
      InsetsSource type=ITYPE_TOP_TAPPABLE_ELEMENT frame=[0,0][2776,130] visible=true
      InsetsSource type=ITYPE_BOTTOM_TAPPABLE_ELEMENT frame=[0,1017][744,1022] visible=true
      InsetsSource type=ITYPE_IME frame=[0,0][0,0] visible=false

Insets管理架构

Insets相关类图

分为app侧和系统服务侧(wms)侧。 

app侧的类

  • InsetsState:  为Parceble, 在wms和app中互相传递。其中记录了所有系统Insets的InsetsSource。每个InsetsSource描述了Insets的状态。 可以参看简介中dump信息
  • InsetsSource: 为Parceble, 记录一个inset是否显示及frame。可以参看简介中dump信息。
  •  InsetsSourceControl :为Parceble。  InsetsSourceControl 与某一个insets窗口对应, 可以通过其控制inset show 和hide。app持有相应inset的InsetsSourceControl ,就可以控制该inset的显示和隐藏,如果不持有某个类型的InsetsSourceControl, 就不能控制该类型的inset的显示和隐藏  其中mLeash 为surfaceControl, 可由InsetsAnimationControlImpl获取并交给SyncRtSurfaceTransactionApplier 控制动画进度,如surface位置, 隐藏,显示等。app持有哪些inset的InsetsSourceControl,有wms确定并在ddWindow()和 relayoutWindow()时传回给app。

 app侧持有的InsetsSourceControl来自于添加窗口时 addWindow()和 relayoutWindow()时传回的 mTempControls。 实测 addWindow时mTempControls传回值为null. 在relayoutWindow 时传回mTempControls为实际值。WMS在在relayout 过程中, 会寻找inset 的target 窗口, 通过addToControlMaps@ InsetsStateController.java为该类型的窗口添加target, 然后在 relayoutWindow()中通过调用win.getDisplayContent().getInsetsStateController().getControlsForDispatch(win); 获取该win的InsetsSourceControl 传回给app端的mTempControls。

ViewRootImp.setView()-->addWindow(...mTempControls) //获得mTempControlsmInsetsController.onControlsChanged(mTempControls)-->consumer.setControl(control, showTypes, hideTypes);
  • InsetsController: 每个窗口对应一个InsetController。 为app端控制inset显示,隐藏, 更新状态,动画的总调度, 包含 InsetsSourceConsumer map 和 ViewRootInsetsControllerHost。每种insets类型对应一个InsetsSourceConsumer。InsetsController在ViewRootImpl初始化时创建。
创建InsetsController stack, 从下向上at android.view.InsetsController.<init>(InsetsController.java:525)at android.view.ViewRootImpl.<init>(ViewRootImpl.java:768)at android.view.ViewRootImpl.<init>(ViewRootImpl.java:720)at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:401)at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:109)
  • InsetsSourceConsumer: 中记录了InsetState(从wms传入)及InsetsSourceControl。 InsetsSourceControl来自wms中传入, 具体参看InsetsSourceControl说明。 
  • PendingInsetsController:为窗口被加入到wms之前记录APP要求的状态, 在ViewRootImpl.setview时调用mWindowSession.addToDisplayAsUser之后被同步到InsetsController中。 

WMS侧的类

  • InsetsStateController: 控制全局整体inset状态。

 mProviders为insets的provider的集合。

mTypeControlTargetMap为可以控制每种Insets(如显示或隐藏)的窗口的集合。

mState为InsetsState, 当前系统所有inset 的状态。

(注: 每个WindowState通过InsetsStateController.getInsetsForDispatch获取该窗口的state, 通过relayoutWindow或者addWindow 中的outInsetsState.set(win.getInsetsState(), win.isClientLocal())将当前窗口insetState 转给app。app端通过mInsetsController.onStateChanged @ViewRootImpl将状态设置给InsetsController。  app 根据这个insetstate计算内容区域。 app 计算inset区域:mInsetsController.calculateInsets。)

DisplayContent和InsetsPolicy均持有InsetsStateController,为同一实例。

  • InsetsPolicy: 为insets在wms端的总体策略。
  • InsetsControlTarget即为WindowState,如果某个窗口可以控制某种类型inset, 在该窗口addToWindow()和relayoutWindow()函数中, 返回对应inset的InsetsSourceControl。例如, 当前top窗口仅允许控制statusbar, 则statusbar的InsetsControlTarget为当前top窗口, 传回给当前top窗口InsetsSourceControl 仅有statusbar, 没有导航栏的InsetsSourceControl。 
  • InsetsSourceProvider: win: inset 窗口, 例如输入法窗口, 导航栏窗口。 其中mSource为某个 inset的frame及显示状态。 mFrameProvider:计算inset的frame大小的函数,用于设置mSource中的frame。 在updateSourceFrame()中调用。

inset show的流程

inset 基本的控制是show 和hide, inset show和hide流程基本一样,以show流程说明流程。 

  • 接口

app 控制insets显示或者隐藏调用的接口如下, 关于InsetsController参见InsetsController类说明。

getWindow().getInsetsController().show(insetTypeList) //实际对应InsetsController.show()

getWindow().getInsetsController().hide(insetTypeList) //实际对应InsetsController.hide()

  • 流程

调用InsetsController.show/hide的调用stack如下, 从下到上,这个stack只到InsetsController.notifyVisibilityChanged(),该stack只是记录和参考,不作详细说明。 具体需要注意的是InsetsController.notifyVisibilityChanged()之后流程。

//此函数先调用ViewRootInsetsControllerHost.notifyInsetsChanged  后调用updateRequestedStateat android.view.InsetsController.notifyVisibilityChanged(InsetsController.java:1208)  at android.view.InsetsSourceConsumer.setRequestedVisible(InsetsSourceConsumer.java:344)at android.view.InsetsSourceConsumer.show(InsetsSourceConsumer.java:196)at android.view.InsetsController.showDirectly(InsetsController.java:1325)at android.view.InsetsController.controlAnimationUnchecked(InsetsController.java:1013)at android.view.InsetsController.applyAnimation(InsetsController.java:1305)at android.view.InsetsController.show(InsetsController.java:870)at android.view.InsetsController.show(InsetsController.java:826)
  • InsetsController.notifyVisibilityChanged()流程

InsetsController.notifyVisibilityChanged()函数如下, 先调用ViewRootInsetsControllerHost.notifyInsetsChanged  后调用updateRequestedState。

public void notifyVisibilityChanged() {mHost.notifyInsetsChanged();  //实际在viewRootImpl中requestLayout, 也就是在下一个vsync中与wms交互去Relayout()。updateRequestedState();  //调用了ViewRootInsetsControllerHost.onInsetsModified。 交互流程见下面的流程图。}
  • ViewRootInsetsControllerHost.notifyInsetsChanged 实际在viewRootImpl中调用requestLayout, 也就是在下一个vsync中与wms交互去Relayout()。从而获取新的InsetsSourceControl和InsetsState,并刷新界面layout。 这里的notify应该指的是通知本app重新刷新layout。在重新layout后, 会调用mInsetsController.calculateInsets根据inset的显示和占位情况, 计算应用区的大小。 
      at android.view.ViewRootImpl.notifyInsetsChanged(ViewRootImpl.java:1603)  //下一个vsync relayout at android.view.ViewRootInsetsControllerHost.notifyInsetsChanged(ViewRootInsetsControllerHost.java:54) // at android.view.InsetsController.notifyVisibilityChanged(InsetsController.java:1208)
  • updateRequestedState用于通知wms端app请求inset变化,wms处理相应的inset显示和隐藏, 并通知其他app系统inset变化。 调用了ViewRootInsetsControllerHost.onInsetsModified,交互流程见下面的流程图。app端调用IWindowSession.insetsModified(IWindow window, in InsetsState state)通知wms inset变化, 其中InsetsState为修改后的inset状态。 wms通过InsetSourceProvider.setClientVisible设置inset窗口显示状态。 然后发送消息给所有的活动窗口, 通知insetsChanged。 每个活动窗口调用mInsetsController.onStateChanged设置自己的inset窗口状态,onStateChanged也会调用notifyInsetsChanged重新relayout 窗口。而发起show流程的窗口,因为state已经修改为当前的状态, 所以onStateChanged不再执行该操作。
      at android.view.ViewRootInsetsControllerHost.onInsetsModified(ViewRootInsetsControllerHost.java:147) //调用WindowSession.insetsModified()通知wms 修改inset visibilityat android.view.InsetsController.updateRequestedState(InsetsController.java:1287)at android.view.InsetsController.notifyVisibilityChanged(InsetsController.java:1209)

​​

注: app 调用notifyInsetsChanged的几个地方,仅做参考: 

1. 在onStateChanged@InsetsController中调用, 比如在ViewRootImpl.setView中调用onStateChanged, 从下到上: 

ViewRootInsetsControllerHost.notifyInsetsChanged()
 android.view.ViewRootInsetsControllerHost.notifyInsetsChanged(ViewRootInsetsControllerHost.java:54)
      at android.view.InsetsController.onStateChanged(InsetsController.java:630)  //在ViewRootImpl.setView中调用mWindowSession.addToDisplayAsUser后,wms 返回了当前窗口对应的InsetsSourceControl和InsetsState, 调用本函数      at android.view.ViewRootImpl.setView(ViewRootImpl.java:1059) 
      at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:411)
      at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:109)
      

2. 在setFrame@ViewRootImpl中调用, 如在ViewRootImpl.setView中调用setFrame(), 从小到上

ViewRootInsetsControllerHost.notifyInsetsChanged()

 android.view.ViewRootInsetsControllerHost.notifyInsetsChanged(ViewRootInsetsControllerHost.java:54)
      at android.view.InsetsController.onFrameChanged(InsetsController.java:594)
      at android.view.ViewRootImpl.setFrame(ViewRootImpl.java:7493)
      at android.view.ViewRootImpl.setView(ViewRootImpl.java:1036)
      at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:411)
      at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:109)
      

WMS侧确定InsetsSourceControl的流程

WMS侧如何确定某个app 可以持有哪些InsetsSourceControl。 在该窗口relayout中, 根据当前window 的focus情况, 只有focus的窗口可以获取InsetsSourceControl,也就是控制inset的显示和隐藏, 没有focus的窗口不能获取InsetsSourceControl,也就是不能控制inset的显示和隐藏。当一个窗口设置了FLAG_NOT_FOCUSABLE, 就不在能控制inset的显示和隐藏。流程从下到上:


// addToControlMaps 设置了mControlTargetTypeMap@InsetsStateController.java,   设置了mControlTargetTypeMap后, 通过在relayout 中调用getInsetsSourceControls传回给app进程的mTempControls。 
      at com.android.server.wm.InsetsStateController.addToControlMaps(InsetsStateController.java:523)
      at com.android.server.wm.InsetsStateController.onControlChanged(InsetsStateController.java:469)
      at com.android.server.wm.InsetsStateController.onBarControlTargetChanged(InsetsStateController.java:424)
      at com.android.server.wm.InsetsPolicy.updateBarControlTarget(InsetsPolicy.java:150)
      at com.android.server.wm.DisplayPolicy.updateSystemUiVisibilityLw(DisplayPolicy.java:3940)
      at com.android.server.wm.DisplayPolicy.focusChangedLw(DisplayPolicy.java:3736)
      at com.android.server.wm.DisplayContent.updateFocusedWindowLocked(DisplayContent.java:3286)
      at com.android.server.wm.RootWindowContainer.updateFocusedWindowLocked(RootWindowContainer.java:461)
      at com.android.server.wm.WindowManagerService.updateFocusedWindowLocked(WindowManagerService.java:5552)
      at com.android.server.wm.WindowManagerService.relayoutWindow(WindowManagerService.java:2348)

两个问题

窗口显示时不改变现有的inset状态

两种方法:

 一种就是控制inset 和上一个窗口相同,获取当前insets状态方法: getWindowManager().getCurrentWindowMetrics().getWindowInsets。示例

在onCreate 或 onResume中调用以下代码,也就是mWm.addView(mDecorView, l);之前调用。 
WindowInsets windowInsets = getWindowManager().getCurrentWindowMetrics().getWindowInsets();
hideTypeList = getHideTypeList(windowInsets)//获取hide 的type list。 
showTypeList = getShowTypeList(windowInsets)//获取show 的type list。
WindowInsetsController controller = decorView.getWindowInsetsController();
controller.hide(hideTypeList);
controller.show(hideTypeList);

另一种,就是设置窗口为FLAG_NOT_FOCUSABLE。FLAG_NOT_FOCUSABLE, 导致没有focus window 变化, 从而不能设置获取InsetsSourceControl,也就无法控制所有insets窗口的show和hide。 代码:

 l.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH// | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE  // 本句需要注释掉,才能获取InsetsSourceControl。 | WindowManager.LayoutParams.FLAG_FULLSCREEN;

wms中判断应用是否focus的代码: mFindFocusedWindow
          at com.android.server.wm.WindowState.canReceiveKeys(WindowState.java:2877) // 如果设置FLAG_NOT_FOCUSABLE, canReceiveKeys 返回false, 认为改窗口非焦点窗口, 不改变inset设置。

全屏窗口上的dialog 不显示statusbar问题

 受全屏窗口设置影响。 系统单独对status bar做了设置:

​​

View 和 DecorView 设置insets信息

流程如下, DecorView的onApplyWindowInsets 会调用mInsetsController.calculateInsets,计算应用区的大小。

 at com.android.internal.policy.DecorView.onApplyWindowInsets(DecorView.java:1046)//demorview 将inset区域减去,其他的区域作为内容区at android.view.View.dispatchApplyWindowInsets(View.java:11311)at android.view.ViewGroup.dispatchApplyWindowInsets(ViewGroup.java:7320)at android.view.ViewRootImpl.dispatchApplyInsets(ViewRootImpl.java:2311) //会通过calculateInsets 计算当前inset, 将当前inset应用到view。 at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2439)at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1948)at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8179)at android.view.Choreographer$CallbackRecord.run(Choreographer.java:972)at android.view.Choreographer.doCallbacks(Choreographer.java:796)at android.view.Choreographer.doFrame(Choreographer.java:731)at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957)

输入法显示流程

输入法也是一种inset, 其显示和隐藏的流程也与inset 显示隐藏一致。 下面介绍的是在点击编辑框时,输入法显示流程。

1. 在某个app侧点击编辑框

最后调用showSoftInput@InputMethodManager :

showSoftInput:1587, InputMethodManager (android.view.inputmethod)
onTouchEvent:11082, TextView (android.widget)
dispatchTouchEvent:14309, View (android.view)
dispatchTransformedTouchEvent:3118, ViewGroup (android.view)
dispatchTouchEvent:2799, ViewGroup (android.view)
dispatchTransformedTouchEvent:3118, ViewGroup (android.view)
dispatchTouchEvent:2799, ViewGroup (android.view)
dispatchTransformedTouchEvent:3118, ViewGroup (android.view)
dispatchTouchEvent:2799, ViewGroup (android.view)
dispatchTransformedTouchEvent:3118, ViewGroup (android.view)
dispatchTouchEvent:2799, ViewGroup (android.view)
superDispatchTouchEvent:515, DecorView (com.android.internal.policy)
superDispatchTouchEvent:1879, PhoneWindow (com.android.internal.policy)
dispatchTouchEvent:4135, Activity (android.app)
dispatchTouchEvent:473, DecorView (com.android.internal.policy)
dispatchPointerEvent:14568, View (android.view)
processPointerEvent:6024, ViewRootImpl$ViewPostImeInputStage (android.view)
onProcess:5827, ViewRootImpl$ViewPostImeInputStage (android.view)
deliver:5318, ViewRootImpl$InputStage (android.view)
onDeliverToNext:5375, ViewRootImpl$InputStage (android.view)
forward:5341, ViewRootImpl$InputStage (android.view)
forward:5493, ViewRootImpl$AsyncInputStage (android.view)
apply:5349, ViewRootImpl$InputStage (android.view)
apply:5550, ViewRootImpl$AsyncInputStage (android.view)
deliver:5322, ViewRootImpl$InputStage (android.view)
onDeliverToNext:5375, ViewRootImpl$InputStage (android.view)
forward:5341, ViewRootImpl$InputStage (android.view)
apply:5349, ViewRootImpl$InputStage (android.view)
deliver:5322, ViewRootImpl$InputStage (android.view)
deliverInputEvent:8088, ViewRootImpl (android.view)
doProcessInputEvents:8039, ViewRootImpl (android.view)
enqueueInputEvent:8000, ViewRootImpl (android.view)
onInputEvent:8211, ViewRootImpl$WindowInputEventReceiver (android.view)
dispatchInputEvent:220, InputEventReceiver (android.view)
nativePollOnce:-1, MessageQueue (android.os)
next:335, MessageQueue (android.os)
loop:183, Looper (android.os)
main:7664, ActivityThread (android.app)
invoke:-1, Method (java.lang.reflect)
run:592, RuntimeInit$MethodAndArgsCaller (com.android.internal.os)
main:947, ZygoteInit (com.android.internal.os)

2.输入法app接收到显示输入法消息

输入法app, 即实现inputmethodservice的app。 其与InputMethodManagerService的接口为IInputMethodWrapper。 InputMethodManagerService 调用 IInputMethodWrapper.showSoftInput, 其发送消息DO_SHOW_SOFT_INPUT。 处理DO_SHOW_SOFT_INPUT, 调用到InputMethodService.showSoftInput (), 最终调用到IInputMethodPrivilegedOperations.applyImeVisibility().IInputMethodPrivilegedOperations 为inputMethodService与InputMethodManagerService的通信接口。 

applyVisibilityInInsetsConsumerIfNecessary:2219, InputMethodService (android.inputmethodservice)
access$400:263, InputMethodService (android.inputmethodservice)
showSoftInput:748, InputMethodService$InputMethodImpl (android.inputmethodservice)
showSoftInputWithToken:718, InputMethodService$InputMethodImpl (android.inputmethodservice)
executeMessage:226, IInputMethodWrapper (android.inputmethodservice)
handleMessage:44, HandlerCaller$MyHandler (com.android.internal.os)
dispatchMessage:106, Handler (android.os)
loop:223, Looper (android.os)
main:7664, ActivityThread (android.app)
invoke:-1, Method (java.lang.reflect)
run:592, RuntimeInit$MethodAndArgsCaller (com.android.internal.os)
main:947, ZygoteInit (com.android.internal.os)

3.InputMethodManagerService接收到输入法app的显示状态信息

输入法app调用InputMethodManagerService.applyImeVisibility() 通知InputMethodManagerService(IMMS)显示状态变化,IMMS然后调用到scheduleShowImePostLayout@ImeInsetsSourceProvider,该函数在下一个vsync调用输入法窗口的windowState.showInsets通知输入法窗口: ims: show.  

scheduleShowImePostLayout:52, ImeInsetsSourceProvider (com.android.server.wm)
showImePostLayout:7615, WindowManagerService$LocalService (com.android.server.wm)
applyImeVisibility:4088, InputMethodManagerService (com.android.server.inputmethod)
access$4700:188, InputMethodManagerService (com.android.server.inputmethod)
applyImeVisibility:5935, InputMethodManagerService$InputMethodPrivilegedOperationsImpl (com.android.server.inputmethod)
onTransact:336, IInputMethodPrivilegedOperations$Stub (com.android.internal.inputmethod)
execTransactInternal:1154, Binder (android.os)
execTransact:1123, Binder (android.os)

4.输入法窗口接收到showInsets@IWindow 

输入法在接收到ims显示状态变化后, 如下面流程,调用InsetsController.show, 后面的流程和前面介绍的inset show的流程一致: 通知wms ims inset状态变化,  并通知给所有活动中的窗口。 在下一个vsync, 调用relayoutWindow(),重新布局。下面为输入法窗口的showInsets流程。

  • "main@15899" prio=5 tid=0x2 nid=NA runnablejava.lang.Thread.State: RUNNABLEat android.view.InsetsController.updateRequestedState(InsetsController.java:1262)at android.view.InsetsController.notifyVisibilityChanged(InsetsController.java:1209)at android.view.InsetsSourceConsumer.setRequestedVisible(InsetsSourceConsumer.java:344)at android.view.InsetsSourceConsumer.show(InsetsSourceConsumer.java:196)at android.view.InsetsController.showDirectly(InsetsController.java:1325)at android.view.InsetsController.controlAnimationUnchecked(InsetsController.java:1013)at android.view.InsetsController.applyAnimation(InsetsController.java:1305)at android.view.InsetsController.show(InsetsController.java:870)at android.view.ViewRootImpl$ViewRootHandler.handleMessage(ViewRootImpl.java:5031)  //处理 MSG_SHOW_INSETS, MSG_SHOW_INSETS 为wms 调用iWindow.showInsets触发。at android.os.Handler.dispatchMessage(Handler.java:106)at android.os.Looper.loop(Looper.java:223)at android.app.ActivityThread.main(ActivityThread.java:7664)at java.lang.reflect.Method.invoke(Method.java:-1)at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
    

监听inset 变化

窗口中的view可以在insets变化时, 改变默认的inset 占位行为。 监听inset变化, 然后自行设置insets如何占位。 如:

  • 设置Insetscontroller变化监听

InsetsController.addOnControllableInsetsChangedListener(OnControllableInsetsChangedListener ...);
  • 应用WindowInsets变化

getWindow().getDecorView().setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener ...);@Overridepublic WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {mImeVisible = insets.isVisible(ime());return v.onApplyWindowInsets(insets);}

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

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

相关文章

幻兽帕鲁客户端存档文件 - 云上备份和恢复教程

本文将详细介绍如何将幻兽帕鲁游戏客户端的存档文件备份至云端&#xff0c;以及如何从云端恢复存档数据至本地。 一、游戏存档备份场景 幻兽帕鲁的游戏进度存储在电脑本地磁盘上&#xff0c;游戏中创建的每个世界都对应一个本地存档文件夹。在玩游戏过程中&#xff0c;客户端…

智能边缘计算网关实现高效数据处理与实时响应-天拓四方

在当今时代&#xff0c;数据已经成为驱动业务决策的关键因素。然而&#xff0c;传统的数据处理方式往往存在延迟&#xff0c;无法满足实时性要求。此时&#xff0c;智能边缘计算网关应运而生&#xff0c;它能够将数据处理和分析的能力从中心服务器转移至设备边缘&#xff0c;大…

基于单片机控制的智能门锁设计

摘要&#xff1a;阐述基于STC15F2K60S2单片机控制的智能门锁设计&#xff0c;包括CPU控制单元模块、液晶显示LCD、 Wi-Fi模块&#xff0c;实现远程控制开门&#xff0c;密码开门的智能化功能。 关键词&#xff1a;控制技术&#xff0c;单片机&#xff0c;智能门锁&#xff0c;…

游戏视频录制软件推荐,打造专业电竞视频(3款)

随着游戏产业的快速发展&#xff0c;越来越多的玩家开始关注游戏视频录制软件。一款好的录制软件不仅可以帮助玩家记录游戏中的精彩瞬间&#xff0c;还可以让其与他人分享自己的游戏体验。接下来&#xff0c;我们将介绍三款热门的游戏视频录制软件&#xff0c;并对其进行详细的…

收放卷转动线速度计算FC(SCL+梯形图代码)

这篇博客是收放控制算法的基础系列,通过这篇文章的学习。大家能更好的理解收放卷控制里的前馈量计算,收放卷前馈PID大家可以参考下面链接文章: https://rxxw-control.blog.csdn.net/article/details/129352629https://rxxw-control.blog.csdn.net/article/details/12935262…

3D Line Mapping Revisited论文阅读

1. 代码地址 GitHub - cvg/limap: A toolbox for mapping and localization with line features. 2. 项目主页 3D Line Mapping Revisited 3. 摘要 提出了一种基于线的重建算法&#xff0c;Limap&#xff0c;可以从多视图图像中构建3D线地图&#xff0c;通过线三角化、精心…

06、全文检索 -- Solr -- Solr 全文检索之在图形界面管理 Core 的 Schema(演示对 普通字段、动态字段、拷贝字段 的添加和删除)

目录 Solr 全文检索之管理 Schema使用Web控制台管理Core的Schema3 种 字段解释&#xff1a;Field&#xff1a;普通字段Dynamic Field&#xff1a;动态字段Copy Field&#xff1a;拷贝字段 演示&#xff1a;添加 普通字段&#xff08; Field &#xff09;演示&#xff1a;添加 动…

C++入门的基础

幸福比傲慢更容易蒙住人的眼睛。 ——大仲马 C入门 1、属于C的关键字1、1、C从何而来1、2、C关键字(C98) 2、命名空间2、1、命名空间的定义2、2、命名空间使用 3、C输入和输出4、缺省参数4、1、缺省参数概念4、2、缺省参数分类 5、函数重载5、1、函数重载概念 6、引用6、1、引用…

电脑/机顶盒/ps3/4/连接老电视(只有AV、S-Video接口)解决方案之HDMI转AV/S-Video转换器HAV

HDMI转AV/S-Video转换器功能 01、将HDMI高清信号经过视频处理转换成AV、S-VIDEO(PAL/NTSC)的视频信号输出 02、将HDMI数字音频&#xff0c;经过DAC数模芯片处理转成模拟立体声输出 03、采用先进的视频处理技术&#xff0c;对图像的亮度&#xff0c;对比度及色彩进行增强处理 04…

使用Docker本地部署Jupyter Notebook并结合内网穿透实现远程访问

文章目录 1. 选择与拉取镜像2. 创建容器3. 访问Jupyter工作台4. 远程访问Jupyter工作台4.1 内网穿透工具安装4.2 创建远程连接公网地址4.3 使用固定二级子域名地址远程访问 本文主要介绍如何在Ubuntu系统中使用Docker本地部署Jupyter Notebook&#xff0c;并结合cpolar内网穿透…

01-操作系统_名词_文件下载_反弹

操作系统_名词_文件下载_反弹 一、渗透测试1.1、POC、EXP、Payload与Shellcode1.2、后门1.3、木马1.4、反弹1.5、回显1.6、跳板1.7、黑白盒测试1.8、暴力破解1.9、社会工程学1.10、撞库1.11、ATT&CK 二、案例演示2.1、基础案例1&#xff1a;操作系统-用途&命令&权限…

Android学习之路(27) ProGuard,混淆,R8优化

前言 使用java编写的源代码编译后生成了对于的class文件&#xff0c;但是class文件是一个非常标准的文件&#xff0c;市面上很多软件都可以对class文件进行反编译&#xff0c;为了我们app的安全性&#xff0c;就需要使用到Android代码混淆这一功能。 针对 Java 的混淆&#x…

【Docker】Docker Registry(镜像仓库)

文章目录 一、什么是 Docker Registry二、镜像仓库分类三、镜像仓库工作机制四、常用的镜像仓库五、常用命令镜像仓库命令镜像命令(部分)容器命令(部分) 六、docker镜像仓库实战综合实战一&#xff1a;搭建一个 nginx 服务综合实战二&#xff1a;Docker hub上创建自己私有仓库综…

B站课程评分

Spring6 https://www.bilibili.com/video/BV1Ft4y1g7Fb/ 评价: 推荐一看 配套文档优秀, 老师口齿清晰, 条理不错. mybatis https://www.bilibili.com/video/BV1JP4y1Z73S/?spm_id_from333.337.search-card.all.click 评价: 推荐一看 配套文档优秀, 老师口齿清晰, 条理不错…

等变和不变 、向量神经元(vector neurons)是什么?

等变和不变 等变&#xff1a;如果输入是一个旋转后的椅子&#xff0c;那么输出也应该是一个旋转后的椅子 不变&#xff1a;如果输入是一个旋转后的椅子&#xff0c;那么输出应该是一个椅子&#xff0c;而不是一只狗。 向量神经元&#xff08;vector neurons&#xff09; 向量…

如何监控摄像头是否在线?有什么工具推荐

WGCLOUD监控系统 我们项目中&#xff0c;摄像头用的WGCLOUD监控系统来监控的&#xff0c;主要两种方式来监控 一种是监控摄像头的端口&#xff0c;使用WGCLOUD的端口监控模块 一种是PING摄像头的IP&#xff0c;使用WGCLOUD的ping监测模块 这两种方式比较简单&#xff0c;也…

1997-2022年中央对各省份一般公共预算转移支付数据

1997-2022年中央对各省份一般公共预算转移支付数据 1、时间&#xff1a;1997-2022年 2、范围&#xff1a;31省 3、指标&#xff1a;一般公共预算转移支付 4、来源&#xff1a;wind 财政部 5、指标解释&#xff1a;一般性转移支付又称体制性转移支付&#xff0c;是指上级政…

【2024.2.4练习】国王游戏

题目描述 题目思路 涉及排列组合求最优解问题&#xff0c;数据大考虑是否满足某种贪心策略。 假设不除以右手的数字&#xff0c;那么获得金币数量最多的显然为最后一个人。左手数字最大的应排在最后一位。在右手有数字的情况下&#xff0c;不妨也尝试从最后一个人开始排。 假…

Element UI+Spring Boot进行CRUD的实例

ElementUI安装与使用指南 前端代码&#xff1a;点击查看learnelementuispringboot项目源码 后端代码&#xff1a;点击查看 LearnElementUiAndSpringBoot 一、前端配置 安装axios axios官网axios中文文档安装指令&#xff1a;npm install axios 二、后端配置 springboot3m…

BLIP2——采用Q-Former融合视觉语义与LLM能力的方法

BLIP2——采用Q-Former融合视觉语义与LLM能力的方法 FesianXu 20240202 at Baidu Search Team 前言 大规模语言模型&#xff08;Large Language Model,LLM&#xff09;是当前的当红炸子鸡&#xff0c;展现出了强大的逻辑推理&#xff0c;语义理解能力&#xff0c;而视觉作为人…