鸿蒙开发:应用组件跨设备交互(流转)【跨端迁移】

news2024/11/13 4:22:44

跨端迁移

概述

在用户使用设备的过程中,当使用情境发生变化时(例如从室内走到户外或者周围有更适合的设备等),之前使用的设备可能已经不适合继续当前的任务,此时,用户可以选择新的设备来继续当前的任务,原设备可按需决定是否退出任务,这个就是跨端迁移的场景。常见的跨端迁移场景实例:在平板上播放的视频,迁移到智慧屏继续播放,从而获得更佳的观看体验;平板上的视频应用退出。在应用开发层面,跨端迁移指在A端运行的UIAbility迁移到B端上,完成迁移后,B端UIAbility继续任务,而A端UIAbility可按需决定是否退出。

跨端迁移的核心任务是将应用的当前状态(包括页面控件、状态变量等)无缝迁移到另一设备,从而在新设备上无缝接续应用体验。这意味着用户在一台设备上进行的操作可以在另一台设备的相同应用中快速切换并无缝衔接。

主要功能包括:

  • 支持用户自定义数据存储及恢复。

  • 支持页面路由信息和页面控件状态数据的存储及恢复。

  • 支持应用兼容性检测。

  • 支持应用根据实际使用场景动态设置迁移状态(默认迁移状态为 ACTIVE 激活状态)。例如,编辑类应用在编辑文本的页面下才需要迁移,其他页面不需要迁移,则可以通过[setMissionContinueState]进行控制。

  • 支持应用动态选择是否进行页面栈恢复(默认进行页面栈信息恢复)。例如,应用希望自定义迁移到其他设备后显示的页面,则可以通过[SUPPORT_CONTINUE_PAGE_STACK_KEY]进行控制。

  • 支持应用动态选择迁移成功后是否退出迁移源端应用(默认迁移成功后退出迁移源端应用)。可以通过[SUPPORT_CONTINUE_SOURCE_EXIT_KEY]进行控制。

    说明:

    开发者可以开发具有迁移能力的应用,迁移的触发由系统应用完成。

运作机制

hop-cross-device-migration

  1. 在源端,通过UIAbility的[onContinue()]回调,开发者可以保存待接续的业务数据。例如,在浏览器应用中完成跨端迁移,开发者需要使用[onContinue()]回调保存页面URL等业务内容,而系统将自动保存页面状态,如当前浏览进度。
  2. 分布式框架提供了跨设备应用界面、页面栈以及业务数据的保存和恢复机制,它负责将数据从源端发送到对端。
  3. 在对端,同一UIAbility可以通过[onCreate()](冷启动)和[onNewWant()](热启动)接口来恢复业务数据。

跨端迁移流程

以从对端的迁移入口发起迁移为例,跨端迁移流程如下图所示。

hop-cross-device-migration

约束限制

  • 跨端迁移要求在同一UIAbility之间进行,也就是需要相同的bundleNameabilityName和签名信息。
  • 为了获得最佳体验,使用wantParam传输的数据需要控制在100KB以下。

开发步骤

  1. 在[module.json5配置文件]的abilities标签中配置跨端迁移标签continuable

    {
      "module": {
        // ...
        "abilities": [
          {
            // ...
            "continuable": true, // 配置UIAbility支持迁移
          }
        ]
      }
    }
    

    说明:

    根据需要配置应用启动模式类型,配置详情请参照[UIAbility组件启动模式]。

  2. 在源端UIAbility中实现[onContinue()]回调。

    UIAbility实例触发迁移时,[onContinue()]回调在源端被调用,开发者可以在该接口中通过同步或异步的方式来保存迁移数据,实现应用兼容性检测,决定是否支持此次迁移。

    • 保存迁移数据:开发者可以将要迁移的数据通过键值对的方式保存在wantParam参数中。
    • 应用兼容性检测:开发者可以通过从wantParam参数中获取对端应用的版本号与源端应用版本号做兼容性校验。开发者可以在触发迁移时从[onContinue()]回调中wantParam.version获取到迁移对端应用的版本号与迁移源端应用版本号做兼容校验。
    • 迁移决策:开发者可以通过[onContinue()]回调的返回值决定是否支持此次迁移,接口返回值详见[AbilityConstant.OnContinueResult]。
    import AbilityConstant from '@ohos.app.ability.AbilityConstant';
    import hilog from '@ohos.hilog';
    import UIAbility from '@ohos.app.ability.UIAbility';
    
    const TAG: string = '[MigrationAbility]';
    const DOMAIN_NUMBER: number = 0xFF00;
    
    export default class MigrationAbility extends UIAbility {
      onContinue(wantParam: Record<string, Object>):AbilityConstant.OnContinueResult {
        let version = wantParam.version;
        let targetDevice = wantParam.targetDevice;
        hilog.info(DOMAIN_NUMBER, TAG, `onContinue version = ${version}, targetDevice: ${targetDevice}`); // 准备迁移数据
    
        // 获取源端版本号
        let versionSrc: number = -1; // 请填充具体获取版本号的代码
    
        // 兼容性校验
        if (version !== versionSrc) {
          // 在兼容性校验不通过时返回MISMATCH
          return AbilityConstant.OnContinueResult.MISMATCH;
        }
    
        // 将要迁移的数据保存在wantParam的自定义字段(例如data)中
        const continueInput = '迁移的数据';
        wantParam['data'] = continueInput;
    
        return AbilityConstant.OnContinueResult.AGREE;
      }
    }
    
  3. 源端设备UIAbility实例在冷启动和热启动情况下分别会调用不同的接口来恢复数据和加载UI。 在对端设备的UIAbility中,需要实现[onCreate()]/[onNewWant()]接口来恢复迁移数据。不同情况下的函数调用如下图所示:

    hop-cross-device-migration

    • 通过在[onCreate()]/[onNewWant()]回调中检查launchReason,可以判断此次启动是否有迁移触发。
    • 开发者可以从want中获取之前保存的迁移数据
    • 数据恢复后调用restoreWindowStage()来触发页面恢复,包括页面栈信息。
    import AbilityConstant from '@ohos.app.ability.AbilityConstant';
    import hilog from '@ohos.hilog';
    import UIAbility from '@ohos.app.ability.UIAbility';
    import type Want from '@ohos.app.ability.Want';
    
    const TAG: string = '[MigrationAbility]';
    const DOMAIN_NUMBER: number = 0xFF00;
    
    export default class MigrationAbility extends UIAbility {
      storage : LocalStorage = new LocalStorage();
    
      onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
        hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Ability onCreate');
        if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
          // 将上述保存的数据从want.parameters中取出恢复
          let continueInput = '';
          if (want.parameters !== undefined) {
            continueInput = JSON.stringify(want.parameters.data);
            hilog.info(DOMAIN_NUMBER, TAG, `continue input ${JSON.stringify(continueInput)}`);
          }
          // 触发页面恢复
          this.context.restoreWindowStage(this.storage);
        }
      }
    
      onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
         hilog.info(DOMAIN_NUMBER, TAG, 'onNewWant');
         if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
           // 将上述保存的数据从want.parameters中取出恢复
           let continueInput = '';
           if (want.parameters !== undefined) {
             continueInput = JSON.stringify(want.parameters.data);
             hilog.info(DOMAIN_NUMBER, TAG, `continue input ${JSON.stringify(continueInput)}`);
           }
           // 触发页面恢复
           this.context.restoreWindowStage(this.storage);
         }
       }
    }
    

可选配置迁移能力

动态配置迁移能力

从API version 10开始,提供了支持动态配置迁移能力的功能。即应用可以根据实际使用场景,在需要迁移时开启应用迁移能力;在业务不需要迁移时则可以关闭迁移能力。

开发者可以通过调用[setMissionContinueState()]接口对迁移能力进行设置。默认状态下,应用的迁移能力为ACTIVE状态,即迁移能力开启,可以迁移。

设置迁移能力的时机

迁移能力的改变可以根据实际业务需求和代码实现,发生在应用生命周期的绝大多数时机。本文介绍常用的几种配置方式。

UIAbility的[onCreate()]回调中调用接口,可以在应用创建时设置应用的迁移状态。

// MigrationAbility.ets
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import hilog from '@ohos.hilog';
import UIAbility from '@ohos.app.ability.UIAbility';
import type Want from '@ohos.app.ability.Want';

const TAG: string = '[MigrationAbility]';
const DOMAIN_NUMBER: number = 0xFF00;

export default class MigrationAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    // ...
    this.context.setMissionContinueState(AbilityConstant.ContinueState.INACTIVE, (result) => {
      hilog.info(DOMAIN_NUMBER, TAG, `setMissionContinueState INACTIVE result: ${JSON.stringify(result)}`);
    });
    // ...
  }
}

在页面的onPageShow()回调中调用接口,可以设置单个页面出现时应用的迁移状态。

// Page_MigrationAbilityFirst.ets
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import common from '@ohos.app.ability.common';
import hilog from '@ohos.hilog';

const TAG: string = '[MigrationAbility]';
const DOMAIN_NUMBER: number = 0xFF00;

@Entry
@Component
struct Page_MigrationAbilityFirst {
  private context = getContext(this) as common.UIAbilityContext;
  build() {
    // ...
  }
  // ...
  onPageShow(){
    // 进入该页面时,将应用设置为可迁移状态
    this.context.setMissionContinueState(AbilityConstant.ContinueState.ACTIVE, (result) => {
      hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', `setMissionContinueState ACTIVE result: ${JSON.stringify(result)}`);
    });
  }
}

在某个组件的触发事件中设置应用迁移能力。

// Page_MigrationAbilityFirst.ets
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import common from '@ohos.app.ability.common';
import hilog from '@ohos.hilog';
import promptAction from '@ohos.promptAction'
import router from '@ohos.router';

const TAG: string = '[MigrationAbility]';
const DOMAIN_NUMBER: number = 0xFF00;

@Entry
@Component
struct Page_MigrationAbilityFirst {
  private context = getContext(this) as common.UIAbilityContext;
  build() {
    Column() {
      //...
      List({ initialIndex: 0 }) {
        ListItem() {
          Row() {
            //...
          }
          .onClick(() => {
            // 点击该按钮时,将应用设置为可迁移状态
            this.context.setMissionContinueState(AbilityConstant.ContinueState.ACTIVE, (result) => {
              hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', `setMissionContinueState ACTIVE result: ${JSON.stringify(result)}`);
              promptAction.showToast({
                message: $r('app.string.Success')
              });
            });
          })
        }
        //...
      }
      //...
    }
    //...
  }
}

保证迁移连续性

由于迁移加载时,对端拉起的应用可能执行过自己的迁移状态设置命令(例如,冷启动时对端在[onCreate()]中设置了 INACTIVE ;热启动时对端已打开了不可迁移的页面,迁移状态为 INACTIVE 等情况)。为了保证迁移过后的应用依然具有可以迁移回源端的能力,应在 [onCreate()]/[onNewWant()]的迁移调用判断中,将迁移状态设置为 ACTIVE 。

// MigrationAbility.ets
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import UIAbility from '@ohos.app.ability.UIAbility';
import hilog from '@ohos.hilog';
import type Want from '@ohos.app.ability.Want';

const TAG: string = '[MigrationAbility]';
const DOMAIN_NUMBER: number = 0xFF00;

export default class MigrationAbility extends UIAbility {
  // ...
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    // ...
    if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
      // ...
    }
    // 调用原因为迁移时,设置状态为可迁移,应对冷启动情况
    this.context.setMissionContinueState(AbilityConstant.ContinueState.ACTIVE, (result) => {
      hilog.info(DOMAIN_NUMBER, TAG, `setMissionContinueState ACTIVE result: ${JSON.stringify(result)}`);
    });
  }

  onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    // ...
    // 调用原因为迁移时,设置状态为可迁移,应对热启动情况
    if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
      this.context.setMissionContinueState(AbilityConstant.ContinueState.ACTIVE, (result) => {
        hilog.info(DOMAIN_NUMBER, TAG, `setMissionContinueState ACTIVE result: ${JSON.stringify(result)}`);
      });
    }
  }
  // ...
}

按需迁移页面栈

支持应用动态选择是否进行页面栈恢复(默认进行页面栈信息恢复)。如果应用不想使用系统默认恢复的页面栈,则可以设置不进行页面栈迁移,而需要在onWindowStageRestore()设置迁移后进入的页面,参数定义见[SUPPORT_CONTINUE_PAGE_STACK_KEY]。

应用在源端的页面栈中存在Index和Second路由,而在对端恢复时不需要按照源端页面栈进行恢复,需要恢复到指定页面。

例如,UIAbility迁移不需要自动迁移页面栈信息。

// MigrationAbility.ets
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import UIAbility from '@ohos.app.ability.UIAbility';
import wantConstant from '@ohos.app.ability.wantConstant';
import hilog from '@ohos.hilog';
import type window from '@ohos.window';

const TAG: string = '[MigrationAbility]';
const DOMAIN_NUMBER: number = 0xFF00;

export default class MigrationAbility extends UIAbility {
  // ...
  onContinue(wantParam: Record<string, Object>):AbilityConstant.OnContinueResult {
    hilog.info(DOMAIN_NUMBER, TAG, `onContinue version = ${wantParam.version}, targetDevice: ${wantParam.targetDevice}`);
    wantParam[wantConstant.Params.SUPPORT_CONTINUE_PAGE_STACK_KEY] = false;
    return AbilityConstant.OnContinueResult.AGREE;
  }

  onWindowStageRestore(windowStage: window.WindowStage) : void {
    // 若不需要自动迁移页面栈信息,则需要在此处设置应用迁移后进入的页面
    windowStage.loadContent('pages/page_migrationability/Page_MigrationAbilityThird', (err, data) => {
      if (err.code) {
        hilog.error(DOMAIN_NUMBER, TAG, 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
        return;
      }
    });
  }
}

按需退出

支持应用动态选择迁移成功后是否退出迁移源端应用(默认迁移成功后退出迁移源端应用)。如果应用不想让系统自动退出迁移源端应用,则可以设置不退出,参数定义见[SUPPORT_CONTINUE_SOURCE_EXIT_KEY]。

示例:UIAbility设置迁移成功后,源端不需要退出迁移应用。

import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import UIAbility from '@ohos.app.ability.UIAbility';
import wantConstant from '@ohos.app.ability.wantConstant';
import hilog from '@ohos.hilog';

const TAG: string = '[MigrationAbility]';
const DOMAIN_NUMBER: number = 0xFF00;

export default class MigrationAbility extends UIAbility {
  // ...
  onContinue(wantParam: Record<string, Object>):AbilityConstant.OnContinueResult {
    hilog.info(DOMAIN_NUMBER, TAG, `onContinue version = ${wantParam.version}, targetDevice: ${wantParam.targetDevice}`);
    wantParam[wantConstant.Params.SUPPORT_CONTINUE_SOURCE_EXIT_KEY] = false;
    return AbilityConstant.OnContinueResult.AGREE;
  }
}

跨端迁移中的数据迁移

当前推荐两种不同的数据迁移方式,开发者可以根据实际使用需要进行选择。

说明:

部分ArkUI组件支持通过配置restoreId的方式,在迁移后将特定状态恢复到对端设备。
如果涉及分布式对象迁移时应注意:

  1. 需要申请ohos.permission.DISTRIBUTED_DATASYNC权限。
  2. 同时需要在应用首次启动时弹窗向用户申请授权。

使用wantParam迁移数据

在需要迁移的数据较少(100KB以下)时,开发者可以选择在wantParam中增加字段进行数据迁移。示例如下:

import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import UIAbility from '@ohos.app.ability.UIAbility';
import type Want from '@ohos.app.ability.Want';
const TAG: string = '[MigrationAbility]';
const DOMAIN_NUMBER: number = 0xFF00;

export default class MigrationAbility extends UIAbility {
  // 源端保存
  onContinue(wantParam: Record<string, Object>):AbilityConstant.OnContinueResult {
    // 将要迁移的数据保存在wantParam的自定义字段(例如data)中
    const continueInput = '迁移的数据';
    wantParam['data'] = continueInput;
    return AbilityConstant.OnContinueResult.AGREE;
  }

  // 对端恢复
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
      // 将上述保存的数据取出恢复
      let continueInput = '';
      if (want.parameters !== undefined) {
        continueInput = JSON.stringify(want.parameters.data);
        hilog.info(DOMAIN_NUMBER, TAG, `continue input ${continueInput}`);
      }
      // 触发页面恢复
      this.context.restoreWindowStage(this.storage);
    }
  }

  onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) {
      let continueInput = '';
      if (want.parameters !== undefined) {
        continueInput = JSON.stringify(want.parameters.data);
        hilog.info(DOMAIN_NUMBER, TAG, `continue input ${JSON.stringify(continueInput)}`);
      }
      // 触发页面恢复
      this.context.restoreWindowStage(this.storage);
    }
  }
}

使用分布式对象迁移数据

当需要迁移的数据较大(100KB以上)或数据以文件形式存在时,可以选择[分布式对象]进行数据迁移。其中,对于文件的迁移,可以使用分布式对象提供的[资产]迁移方式进行。

  1. 在源端onContinue()接口中创建一个分布式数据对象[DataObject],将所要迁移的数据填充到分布式对象数据中,并将生成的sessionId通过want传递到对端。
  2. 对端在onCreate()/onNewWant中进行数据恢复时,可以从want中读取该sessionId,通过分布式对象恢复数据。

说明:  自API 12起,为了保证更高的成功率,文件数据的迁移不建议继续通过[跨设备文件访问]实现,推荐使用分布式对象携带资产的方式进行。开发者此前通过跨设备文件访问实现的文件迁移依然可以使用。

验证指导

为方便开发者验证已开发的可迁移应用,系统提供了一个全局任务中心demo作为迁移的入口。下面介绍通过安装全局任务中心来验证迁移的方式。

1. 编译安装全局任务中心

配置环境

public-SDK不支持开发者使用所有的系统API,例如:全局任务中心使用的[ @ohos.distributedDeviceManager]不包括在public_SDK中。因此为了正确编译安装全局任务中心,开发者需要替换full-SDK,具体操作可参见[替换指南]。

说明

本文中的截图仅为参考,具体的显示界面请以实际使用的DevEco Studio和SDK的版本为准。

下载MissionCenter_Demo[示例代码]
编译工程文件

​a.新建一个工程,找到对应的文件夹替换下载文件

hop-cross-device-migration

​b.自动签名,编译安装。

​DevEco的自动签名模板默认签名权限为normal级。而本应用设计到ohos.permission.MANAGE_MISSIONS权限为system_core级别。自动生成的签名无法获得足够的权限,所以需要将权限升级为system_core级别,然后签名。

​c.系统权限设置(以api10目录为例): 将Sdk目录下的openharmony\api版本(如:10)\toolchains\lib\UnsignedReleasedProfileTemplate.json文件中的"apl":“normal"改为"apl”:“system_core”。

  1. 点击file->Project Structure。

    hop-cross-device-migration

  2. 点击Signing Configs 点击OK。

    hop-cross-device-migration

  3. 连接开发板运行生成demo。

2. 设备组网

  1. 打开A,B两设备的计算器。
  2. 点击右上角箭头选择B设备。
  3. 在B设备选择信任设备,弹出PIN码。
  4. 在A设备输入PIN码。
  5. 已组网成功,验证方法:在A设备输入数字,B设备同步出现则证明组网成功。

3. 发起迁移

  1. 在B设备打开多设备协同权限的应用,A设备打开全局任务中心demo,A设备出现A设备名称(即:本机:OpenHarmony 3.2)和B设备名称(OpenHarmony 3.2)。

    hop-cross-device-migration

  2. 点击B设备名称,然后出现B设备的应用。

    hop-cross-device-migration

  3. 最后将应用拖拽到A设备名称处,A设备应用被拉起,B设备应用退出。

    hop-cross-device-migration

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

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

相关文章

刷代码随想录有感(100):动态规划——不同路径

题干&#xff1a; 代码&#xff1a; class Solution { public:int uniquePaths(int m, int n) {vector<vector<int>>dp(m,vector<int>(n, 0));for(int i 0; i < m; i) dp[i][0] 1;for(int j 0; j < n; j) dp[0][j] 1;for(int i 1; i < m; i){…

程序员日志之DNF手游6月5日罗特斯入门团本

目录 传送门正文日志1、概要1、散件装备过渡2、世界领主攻略和爬塔攻略3、团本攻略4、DNF剧情收集5、新版本预告6、合成冥域天空套&#xff08;天一&#xff09;7、额外重磅消息 传送门 SpringMVC的源码解析&#xff08;精品&#xff09; Spring6的源码解析&#xff08;精品&a…

UE4_后期_ben_模糊和锐化滤镜

学习笔记&#xff0c;不喜勿喷&#xff0c;侵权立删&#xff0c;祝愿生活越来越好&#xff01; 本篇教程主要介绍后期处理的简单模糊和锐化滤镜效果&#xff0c;学习之前首先要回顾下上节课介绍的屏幕扭曲效果&#xff1a; 这是全屏效果&#xff0c;然后又介绍了几种蒙版&#…

Java操作数据库 —— JDBC ① 基础篇

我走我的路&#xff0c;有人拦也走&#xff0c;没人陪也走 —— 24.6.7 JDBC JDBC就是使用Java语言操作关系型数据库的一套API 一、JDBC简介 JDBC 概念 JDBC 就是使用Java语言操作关系型数据库的一套API 全称:(Java DataBase Connectivity)意为Java 数据库连接 JDBC 本质: ①…

OCP前景咋样,工资高吗?

Oracle数据库作为企业级应用的基石&#xff0c;其专业人才一直是市场上的热门需求。 OCP认证&#xff0c;作为Oracle公司颁发的专业证书&#xff0c;OCP认证的持有者通常被视为具备了高级数据库管理、配置、备份、恢复、调优以及SQL编程等关键技能的专业人士。 这些技能在当今…

python生成excel数据并实现隔行变色

代码 from openpyxl import Workbook from datetime import date from openpyxl.styles import PatternFilldef create_excel():wb Workbook()sh wb.activerows [[Date, Batch 1, Batch 2, Batch 3],[date(2024, 2, 1), 40, 30, 25],[date(2024, 2, 2), 40, 25, 30],[date(…

如何低成本、高效搭建线上3D艺术展?

随着数字技术的日新月异&#xff0c;艺术展览领域正迎来一场革新。未来的艺术展览将不再是单一的线下体验&#xff0c;而是线上线下相互融合&#xff0c;其中&#xff0c;3D线上展览将成为线下展览的重要延伸与拓展&#xff0c;为广大观众提供更多元化的选择。 对于艺术家和策…

单机多卡分布式训练策略——MirroredStrategy

前言 分布式训练是一种用于在多个设备或机器上同时训练深度学习模型的技术&#xff0c;它有助于减少训练时间&#xff0c;允许使用更多数据更快训练大模型。分布式训练重点关注数据并行性&#xff0c;本次试验使用的是单机多卡的分布式训练策略&#xff0c;也就是 MirroredStr…

2023 hnust 湖科大 嵌入式 实验报告+代码及复习资料等

2023 hnust 湖科大 嵌入式 实验报告代码及复习资料等 目录 流水灯 1 8位数码管动态扫描 3 按键输入 5 温度与关照 7 看门狗 9 内容 报告 代码 下载链接 https://pan.baidu.com/s/1LIN8rm42yrukXliI3XyZ1g?pwd1111

iOS——KVO底层学习

前情回顾 什么是KVO&#xff1f;在之前的博客里我们已经学过&#xff1a; KVO全称Key Value Observing。KVO传值允许对象监听另一个对象的特定属性&#xff0c;当该属性改变的时候&#xff0c;会触发事件。 KVO不仅可以监听单个属性的变化&#xff0c;也可以监听集合对象的变…

进口电动温度调节阀的原理-美国品牌

进口电动温度调节阀的原理可以清晰地分为以下几个部分进行描述&#xff1a; 1. 温度感应与信号转换 温度传感器&#xff1a;负责感应介质&#xff08;如液体、气体等&#xff09;的温度&#xff0c;并将其转化为相应的电信号。这个电信号反映了介质当前的实际温度。 2. 信号…

数据结构——bitset(位图)模拟实现

从一个题目引出位图 给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&#xff0c;如何快速判断一个数是否在这40亿个数中&#xff1f; 这里有两种大家容易想到的解法&#xff1a; 1.遍历搜索&#xff0c;时间复杂度为O(N) 2.先排序&#xff08;O(NlogN)&a…

【DBA早下班系列】—— 并行SQL/慢SQL 问题该如何高效收集诊断信息

1. 前言 OceanBase论坛问答区或者提交工单支持的时候大部分时间都浪费在了诊断信息的获取交互上&#xff0c;今天我就其中大家比较头疼的SQL问题&#xff0c;给大家讲解一下如何一键收集并行SQL/慢SQL所需要的诊断信息&#xff0c;减少沟通成本&#xff0c;让大家早下班。 2. …

Linux安装——初入linux

前言&#xff1a;linux是雷纳斯托瓦斯在1991年接触到学校机房的装配unix操作系统的电脑后&#xff0c; 立志并且力行大学四年创建出来的操作系统。 在大佬创建linux后就将它的源代码公开——开源。 同时&#xff0c; 大佬给linux取得全名是&#xff1a; Linux is not unix。lin…

使用 python 将 Markdown 文件转换为 ppt演示文稿

在这篇博客中&#xff0c;我们将展示如何使用 wxPython 创建一个简单的图形用户界面 (GUI)&#xff0c;以将 Markdown 文件转换为 PowerPoint 演示文稿。我们将利用 markdown2 模块将 Markdown 转换为 HTML&#xff0c;并使用 python-pptx 模块将 HTML 内容转换为 PowerPoint 幻…

笨蛋学算法之LeetCodeHot100_2_字母异位词分组(Java)

package com.lsy.leetcodehot100;import java.util.*;public class _Hot2_字母异位词分组 {public static List<List<String>> groupAnagrams(String[] strs){//首先&#xff0c;定义一个map类型&#xff0c;其中key为String&#xff0c;value为List<String>…

C# 中文字符串转GBK字节的示例

一、编写思路 在 C# 中&#xff0c;将中文字符串转换为 GBK 编码的字节数组需要使用 Encoding 类。然而&#xff0c;Encoding 类虽然默认并不直接支持 GBK 编码&#xff0c;但是可以通过以下方式来实现这一转换&#xff1a; 1.使用系统已安装的编码提供者&#xff08;如果系统…

axure使用中继器画柱状图

源文件在顶部。 在axure通过读取中继器中的数据来画柱状图&#xff0c;如下图&#xff1a; 1&#xff09;创建一个中继器&#xff0c;在里面创建两列&#xff1a;1列是柱状图底部的名称、2列是柱的高度&#xff0c;如下图&#xff1a; 2&#xff09;双击中继器&#xff0c;画一…

springmvc 全局异常处理器配置的三种方式深入底层源码分析原理

文章目录 springmvc 全局异常处理器配置的三种方式&深入底层源码分析原理配置全局异常处理器的三种方式实现接口HandlerExceptionResolver并配置到WebMvcConfigurer注解式配置ExceptionHandlercontroller里方法上定义ExceptionHandler 深入源码分析进入DispatcherServlet执…

防泄密的方法?用迅软DSE加密软件可靠吗?

防止泄密常用的方法则是使用加密软件&#xff0c;把文件转换为密文&#xff0c;这样一来&#xff0c;未授权的人员打不开&#xff0c;查看不到内容&#xff0c;也就防止了泄密行为的出现。只需用到加密软件&#xff0c;即可保护数据。 用迅软DSE加密软件可靠吗&#xff1f; 特…