flutter和原生利用pigeon建立通道

news2024/11/15 13:39:29

首先导入依赖:

dependencies:
pigeon: ^10.0.0

image.png

定义一个文件:

/// 用于定于flutter和平台的桥接方法
/// @HostApi() 标记的,是用于 Flutter 调用原生的方法;
/// @FlutterApi() 标记的,是用于原生调用 Flutter 的方法;
/// @async 如果原生的方法,是步回调那种,你就可以使用这个标记;
/// 在项目根目录,运行以下命令生成平台代码
/// dart run pigeon --input pigeons/messages.dart

import 'package:pigeon/pigeon.dart';

@ConfigurePigeon(PigeonOptions(
  dartOut: 'lib/pigeons/pigeon.dart',
  dartOptions: DartOptions(),
  // objcHeaderOut: '../isolarCloud/operation4ios/Flutter/SGFlutterBridge.h',
  // objcSourceOut: '../isolarCloud/operation4ios/Flutter/SGFlutterBridge.m',
  // objcOptions: ObjcOptions(),
  kotlinOut:
  '../iSolarCloud/LibBase/src/main/java/com/isolarcloud/libbase/flutter/SGFlutterBridge.kt',
  kotlinOptions: KotlinOptions(),
))
class CommonParams {
  String? pageName;
  Map<String?, Object?>? arguments;
}
class ApiParams {
  String? url;
  Map<String?, Object?>? arguments;
}

/// Flutter调用原生的Api,全部放在一个抽象类中即可
@HostApi()

abstract class SGHostApi {
  /// push至原生页面,参数:页面名称、参数
  void pushNativePage(CommonParams params);
  /// pop出当前页面,预留参数,可通过params.pageName pop到指定页面
  void popPage(CommonParams? params);
  /// 通过Key获取本地化文本数据(同步)
  String getLocalizedText(String? key);
  /// Flutter通过URL和arguments调用原生端接口,异步返回数据给Flutter端
  @async
  Map requestNativeApi(ApiParams apiParams);
  /// 是否允许开启Native页面的原生手势返回效果
  void enablePopRecognizer(bool enable);
}

运行命令行:
dart run pigeon --input pigeons/messages.dart

接着可以运行下:flutter pub get 的命令

自动会生成这个文件:

image.png

里面会实现SGHostApi的定义的方法:比如下面的方法就是自动生成:

/// push至原生页面,参数:页面名称、参数
Future<void> pushNativePage(CommonParams arg_params) async {
  final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
      'dev.flutter.pigeon.isolarcloud_flutter.SGHostApi.pushNativePage', codec,
      binaryMessenger: _binaryMessenger);
  final List<Object?>? replyList =
      await channel.send(<Object?>[arg_params]) as List<Object?>?;
  if (replyList == null) {
    throw PlatformException(
      code: 'channel-error',
      message: 'Unable to establish connection on channel.',
    );
  } else if (replyList.length > 1) {
    throw PlatformException(
      code: replyList[0]! as String,
      message: replyList[1] as String?,
      details: replyList[2],
    );
  } else {
    return;
  }
}

注意打开这个代码注释:意思是在你Android项目的某个路径下生成SGFlutterBridge文件。

kotlinOut:
    '../iSolarCloud/LibBase/src/main/java/com/isolarcloud/flutter/SGFlutterBridge.kt',
kotlinOptions: KotlinOptions(),

然后会在:上面这个路径下自动生成和原生的桥接方法,这里执行的是Android的方法,ios只需要打开:

  // objcHeaderOut: '../isolarCloud/operation4ios/Flutter/SGFlutterBridge.h',
  // objcSourceOut: '../isolarCloud/operation4ios/Flutter/SGFlutterBridge.m',
  // objcOptions: ObjcOptions(),

我们先看看原生和flutter项目的依赖:

image.png

在Android的项目settings.gradle中配置引用:

setBinding(new Binding([gradle: this]))
evaluate(
     new File(
        settingsDir,
        '../isolarcloud_flutter/.android/include_flutter.groovy'
    )
)

以上操作就把两个项目关联在一起了。下面是自动生成的桥接方法,pigeon自动帮你实现:

/**
 * Flutter调用原生的Api,全部放在一个抽象类中即可
 *
 * Generated interface from Pigeon that represents a handler of messages from Flutter.
 */
interface SGHostApi {
  /** push至原生页面,参数:页面名称、参数 */
  fun pushNativePage(params: CommonParams)
  /** pop出当前页面,预留参数,可通过params.pageName pop到指定页面 */
  fun popPage(params: CommonParams?)
  /** Flutter通过URL和arguments调用原生端接口,异步返回数据给Flutter端 */
  fun requestNativeApi(apiParams: ApiParams, callback: (Result<String?>) -> Unit)
  /** 是否允许开启Native页面的原生手势返回效果 */
  fun enablePopRecognizer(enable: Boolean)
  /**
   * 调用原生toast
   * type:0 老版,1:国内,2:海外样式
   */
  fun showToast(type: AppType, msg: String)
  /**
   * 调用原生toast
   * type:0 老版,1:国内,2:海外样式
   */
  fun showLoading(show: Boolean, type: AppType, msg: String?)
  /** 获取用户信息 */
  fun getUserInfo(): String?

  companion object {
    /** The codec used by SGHostApi. */
    val codec: MessageCodec<Any?> by lazy {
      SGHostApiCodec
    }
    /** Sets up an instance of `SGHostApi` to handle messages through the `binaryMessenger`. */
    @Suppress("UNCHECKED_CAST")
    fun setUp(binaryMessenger: BinaryMessenger, api: SGHostApi?) {
      run {
        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.isolarcloud_flutter.SGHostApi.pushNativePage", codec)
        if (api != null) {
          channel.setMessageHandler { message, reply ->
            val args = message as List<Any?>
            val paramsArg = args[0] as CommonParams
            var wrapped: List<Any?>
            try {
              api.pushNativePage(paramsArg)
              wrapped = listOf<Any?>(null)
            } catch (exception: Throwable) {
              wrapped = wrapError(exception)
            }
            reply.reply(wrapped)
          }
        } else {
          channel.setMessageHandler(null)
        }
      }
      run {
        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.isolarcloud_flutter.SGHostApi.popPage", codec)
        if (api != null) {
          channel.setMessageHandler { message, reply ->
            val args = message as List<Any?>
            val paramsArg = args[0] as CommonParams?
            var wrapped: List<Any?>
            try {
              api.popPage(paramsArg)
              wrapped = listOf<Any?>(null)
            } catch (exception: Throwable) {
              wrapped = wrapError(exception)
            }
            reply.reply(wrapped)
          }
        } else {
          channel.setMessageHandler(null)
        }
      }
      run {
        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.isolarcloud_flutter.SGHostApi.requestNativeApi", codec)
        if (api != null) {
          channel.setMessageHandler { message, reply ->
            val args = message as List<Any?>
            val apiParamsArg = args[0] as ApiParams
            api.requestNativeApi(apiParamsArg) { result: Result<String?> ->
              val error = result.exceptionOrNull()
              if (error != null) {
                reply.reply(wrapError(error))
              } else {
                val data = result.getOrNull()
                reply.reply(wrapResult(data))
              }
            }
          }
        } else {
          channel.setMessageHandler(null)
        }
      }
      run {
        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.isolarcloud_flutter.SGHostApi.enablePopRecognizer", codec)
        if (api != null) {
          channel.setMessageHandler { message, reply ->
            val args = message as List<Any?>
            val enableArg = args[0] as Boolean
            var wrapped: List<Any?>
            try {
              api.enablePopRecognizer(enableArg)
              wrapped = listOf<Any?>(null)
            } catch (exception: Throwable) {
              wrapped = wrapError(exception)
            }
            reply.reply(wrapped)
          }
        } else {
          channel.setMessageHandler(null)
        }
      }
      run {
        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.isolarcloud_flutter.SGHostApi.showToast", codec)
        if (api != null) {
          channel.setMessageHandler { message, reply ->
            val args = message as List<Any?>
            val typeArg = AppType.ofRaw(args[0] as Int)!!
            val msgArg = args[1] as String
            var wrapped: List<Any?>
            try {
              api.showToast(typeArg, msgArg)
              wrapped = listOf<Any?>(null)
            } catch (exception: Throwable) {
              wrapped = wrapError(exception)
            }
            reply.reply(wrapped)
          }
        } else {
          channel.setMessageHandler(null)
        }
      }
      run {
        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.isolarcloud_flutter.SGHostApi.showLoading", codec)
        if (api != null) {
          channel.setMessageHandler { message, reply ->
            val args = message as List<Any?>
            val showArg = args[0] as Boolean
            val typeArg = AppType.ofRaw(args[1] as Int)!!
            val msgArg = args[2] as String?
            var wrapped: List<Any?>
            try {
              api.showLoading(showArg, typeArg, msgArg)
              wrapped = listOf<Any?>(null)
            } catch (exception: Throwable) {
              wrapped = wrapError(exception)
            }
            reply.reply(wrapped)
          }
        } else {
          channel.setMessageHandler(null)
        }
      }
      run {
        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.isolarcloud_flutter.SGHostApi.getUserInfo", codec)
        if (api != null) {
          channel.setMessageHandler { _, reply ->
            var wrapped: List<Any?>
            try {
              wrapped = listOf<Any?>(api.getUserInfo())
            } catch (exception: Throwable) {
              wrapped = wrapError(exception)
            }
            reply.reply(wrapped)
          }
        } else {
          channel.setMessageHandler(null)
        }
      }
    }
  }
}

同步或者异步的去调用自动生成的方法:

Future<void> makeApiCall() async {
  var arguments = {"curPage": 1, "size": 10, "message_scene_code": 2};

  final stopwatch = Stopwatch()
    ..start();

  await SGHostApi()
      .requestNativeApi(ApiParams(arguments: arguments))
      .then((value) {
    print("数据回来的时间:${DateTime
        .now()
        .millisecondsSinceEpoch}");
    stopwatch.stop();
    print("总共花费时间:${stopwatch.elapsedMilliseconds}毫秒");
    toast = "android 返回的数据==$value";
    // print("value===$value");
    setState(() {
    });
  });
}

 _getString(){
   SGHostApi().getLocalizedText("I18N_COMMON_SERVICE_AGREEMENT_DESCRIPTION").then((value){
     print("android 给过来的数据==$value");
   });
  setState(() {

  });
}

Android的代码:

class SingleFlutterActivity : FlutterActivity(), EngineBindingsDelegate {

  private val engineBindings: EngineBindings by lazy {
    EngineBindings(activity = this, delegate = this, entrypoint = FlutterRouter.DEMO_ENTRY_POINTER, initialRoute = "${FlutterRouter.DEMO_ROUTER}?psId=1234")
  }

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    engineBindings.attach()
    /**
     * flutter 调用原生的方法
     * */
    SGHostApiget.setUp(getFlutterEngine()!!.getDartExecutor().getBinaryMessenger(), MyApi())

    SGHostApi.setUp(getFlutterEngine()!!.getDartExecutor().getBinaryMessenger(),FlutterToNativeApi() )
  }

  override fun onDestroy() {
    super.onDestroy()
    engineBindings.detach()
  }

  override fun provideFlutterEngine(context: Context): FlutterEngine? {
    return engineBindings.engine
  }

  override fun onNext() {
    val flutterIntent = Intent(this, LoginActivity::class.java)
    startActivity(flutterIntent)
  }

  /**
   * flutter 调用原生的方法,原生写法
   * */
  override fun onNext(str: String?) {

    val flutterIntent = Intent(this, FlutterToAndroidActivity::class.java)
    flutterIntent.putExtra("extraString", str)
    startActivity(flutterIntent)
  }

  /**
   * flutter 调用原生的方法
   * */
  class MyApi : SGHostApiget {
    override fun getString(): String {
      println("测试===6666")
      return "测试===6666,这里是Android的方法"
    }
  }

  /**
   * flutter 调用原生的方法
   * */
  class FlutterToNativeApi() : SGHostApi {

    /**
     * flutter调用原生跳原生页面
     * */
    override fun pushNativePage(params: CommonParams) {
      //params.pageName 页面名称非类名,不可直接创建实例

      /*val flutterIntent = Intent(this, params::class.java)
      flutterIntent.putExtra("extraString", str)
      startActivity(flutterIntent)*/
    }

    /**
     * flutter调用原生跳原生页面
     * */
    override fun popPage(params: CommonParams?) {
      //flutter调用Android去退出页面
    }

    /**
     * flutter调用原生 获取国际化字符串
     * */
    override fun getLocalizedText(key: String?): String {
      return I18nUtil.getString(key);
    }

    /**
     * flutter调用原生 获取网络信息 异步
     * */
    override fun requestNativeApi(
      apiParams: ApiParams,
      callback: (Result<Map<Any, Any?>>) -> Unit,
    ) {
      /*val bitmap: Bitmap = BitmapFactory.decodeResource(BaseApplication.getApplication().resources, R.drawable.test_image)
      val outputStream: ByteArrayOutputStream = ByteArrayOutputStream()
      bitmap.compress(Bitmap.CompressFormat.PNG, 50, outputStream)
      val size: Int = outputStream.size()
      println("字节大小: $size")
      val result: Result<Map<Any, Any?>> = Result.success(
        mapOf(
          "name" to outputStream
        ),
      )
      callback(result)*/

       val map: MutableMap<String, Any> = HttpRequest.getCommonParamMap()
       HttpUtil.postWithPath("/v1/devService/getDevModelUpgradeConfigList", /*apiParams.arguments*/map, object : HttpGlobalHandlerCallback<UpdateRequestBean?>() {
        override fun onSuccess(jsonResult: JsonResults<UpdateRequestBean?>) {
          // 处理成功返回的数据
          val data = jsonResult.result_data // 获取数据
          if (data is UpdateRequestBean) {
            data as UpdateRequestBean
          }
          println("开始传输时间: ${System.currentTimeMillis()}")
            callback(Result.success(data!!.toMap())) // 通过callback返回结果
          // 打印字节大小
          val byteArray = data?.toString()?.toByteArray(Charsets.UTF_8)
          val size = byteArray?.size ?: 0
          println("字节大小: $size")
        }
        fun UpdateRequestBean.toMap(): Map<Any, Any?> {
          val map = mutableMapOf<Any, Any?>()
          map["code"] = code
          map["record"] = record
          map["totalFileSize"] = totalFileSize
          map["pageList"] = pageList?.map { fileInfo ->
            mapOf(
              "file_url" to fileInfo.file_url,
              "file_signature" to fileInfo.file_signature,
              "file_name" to fileInfo.file_name,
              "file_id" to fileInfo.file_id,
              "dev_model" to fileInfo.dev_model,
              "file_size" to fileInfo.file_size,
              "type" to fileInfo.type,
              "dev_type_id" to fileInfo.dev_type_id,
              "record_id" to fileInfo.record_id,
              "sn" to fileInfo.sn,
              "update_time_stamp" to fileInfo.update_time_stamp,
              "block_flag" to fileInfo.block_flag
            )
          }
          return map
        }

        override fun onError(type: ErrorNetType) {
          super.onError(type)
          // 处理错误情况
          // val result: Result<Map<Any, Any?>> = Result.success(
          //   mapOf(
          //     "name" to "John",
          //     "age" to 30,
          //     "email" to "john@example.com"
          //   )
          // )
          // callback(result)
          // 通过callback返回错误信息
          val failureResult: Result<Map<Any, Any?>> = Result.failure(
            Exception("An error occurred")
          )
          callback(failureResult)
        }
        override fun onFinish() {
          super.onFinish()
        }
      })
    }

    override fun disablePopRecognizer(disable: Boolean) {
    }
  }

}

在flutter中统一使用这个类来获取原生获取的网络数据:

/// 成功回调
typedef SuccessCallback = void Function(
    Map<String, dynamic>? resultData, String resultCode, String resultMsg);

/// 失败回调
typedef ErrorCallback = void Function();

class RequireNativeApi {
  static void postWithPathOversea(String? url, Map<String?, Object?>? arguments,
      SuccessCallback? successCallback, ErrorCallback? errorCallback,
      {bool showToast = true}) {
    postWithPath(url, arguments, successCallback, errorCallback,
        showToast: showToast, appType: AppType.oversea);
  }

  static void postWithPathDomestic(
      String? url,
      Map<String?, Object?>? arguments,
      SuccessCallback? successCallback,
      ErrorCallback? errorCallback,
      {bool showToast = true}) {
    postWithPath(url, arguments, successCallback, errorCallback,
        showToast: showToast, appType: AppType.domestic);
  }

  static void postWithPath(String? url, Map<String?, Object?>? arguments,
      SuccessCallback? successCallback, ErrorCallback? errorCallback,
      {bool showToast = true, AppType appType = AppType.oversea}) {
    ApiParams apiParams = ApiParams();
    apiParams.url = url;
    apiParams.arguments = arguments;

    sgApi.requestNativeApi(apiParams).then((data) {
      debugPrint("");
      debugPrint("======================================================");
      debugPrint("api: $url");
      debugPrint("业务入参: $arguments");
      debugPrint("出参:$data");
      debugPrint("======================================================");
      if (data == null || data.isEmpty) {
        /// 网络异常
        if (showToast) {
          sgApi.showToast(appType, SGi18n.key("I18N_COMMON_NETWORK_ERROR"));
        }
        if (errorCallback != null) {
          errorCallback();
        }
        return;
      }

      var jsonData = json.decode(data);
      if (successCallback != null) {
        // 返回接口返回数据,需要调用各个实体类的方法,所以需要各个业务层将Map转为对应的实体类
        successCallback(
          jsonData['result_data'] ?? {},
          jsonData['result_code'] ?? "",
          jsonData['result_msg'] ?? "",
        );
      }
    }).onError((error, stackTrace) {
      debugPrint("RequireNativeApi error: $error");
      debugPrint("RequireNativeApi error: $stackTrace");
      if (showToast) {
        sgApi.showToast(
            appType, SGi18n.key("I18N_COMMON_NETWORK_ERROR_MESSAGE"));
      }
      if (errorCallback != null) {
        errorCallback();
      }
    });
  }
}

flutter中要使用的地方直接拿到成功和失败的回调即可:

RequireNativeApi.postWithPathOversea(Api.getDeleteUserMessage, argument,
    getDeleteMessageSuccess, () => SGOSLoadingToast.dismissLoading());

我项目中用的是getx,大家可以看看我完整的代码:

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:isolarcloud_flutter/api/api.dart';
import 'package:isolarcloud_flutter/api/require_native_api.dart';
import 'package:isolarcloud_flutter/bean/home_msg_entity.dart';
import 'package:isolarcloud_flutter/bean/update_msg_entity.dart';
import 'package:isolarcloud_flutter/modules/demo/constant/constant_state_id.dart';
import 'package:isolarcloud_flutter/utils/hud/sg_os_loading_toast.dart';
import 'package:isolarcloud_flutter/utils/json_cache_util.dart';

import 'sg_message_first_state.dart';

class SGMessageHomePageLogic extends GetxController {
  final SGMessageHomePageState state = SGMessageHomePageState();

  static const idMessageClearUpdate = "message_clear_update";
  static const idMessageList = "message_list";
  static const idLoadFail = "message_load_fail";

  void getList(String labelStr, {bool isFirst = false}) async {
    state.labelStr = labelStr;
    isFirst ? SGOSLoadingToast.showLoading() : null;
    Map<String, Object> argument = {};
    var cache = await JsonCacheManageUtils.getCacheData(
            JsonCacheManageUtils.HomeMessageResponse,
            labelId: labelStr.toString())
        .then((value) {
      if (value != null) {
        return HomeMsgEntity.fromJson(value as Map<String, dynamic>);
      }
    });
    state.hasCache = false;
    if (cache is HomeMsgEntity) {
      state.pageList = cache;
      state.hasCache = true;
      update([idMessageList + labelStr.toString()]);
    }

    RequireNativeApi.postWithPathOversea(
        Api.getHomeMessageList, argument, getHomeMessageSuccess, () {
      isFirst ? SGOSLoadingToast.dismissLoading() : null;
      update([idLoadFail]);
    });
  }

  void getHomeMessageSuccess(
      Map<String, dynamic>? resultData, String resultCode, String resultMsg) {
    if (resultCode == "1" && resultData != null && resultData.isNotEmpty) {
      JsonCacheManageUtils.saveCacheData(
          JsonCacheManageUtils.HomeMessageResponse,
          labelId: state.labelStr,
          resultData);
      state.pageList = HomeMsgEntity.fromJson(resultData);
    }
    SGOSLoadingToast.dismissLoading();
    if (!state.hasCache) {
      update(["$idMessageList${state.labelStr}"]);
    }
  }

  /// clear 消息 传null为全部
  void updateUserAllMessage(dynamic messageSceneCode) {
    SGOSLoadingToast.showLoading();
    Map<String, dynamic> argument = {
      "is_all": 1,
      "message_scene_code": messageSceneCode,
    };
    RequireNativeApi.postWithPathOversea(Api.getUpdateUserMessage, argument,
        getClearMessageSuccess, () => SGOSLoadingToast.dismissLoading());
  }

  void getClearMessageSuccess(
      Map<String, dynamic>? resultData, String resultCode, String resultMsg) {
    if (resultCode == "1" && resultData != null && resultData.isNotEmpty) {
      state.updateBean = UpdateMsgEntity.fromJson(resultData);
    }
    SGOSLoadingToast.dismissLoading();
    update([idMessageClearUpdate]);
  }

  //删除单个消息大类
  void deleteUserMessage(String? ids, String? messageSceneCode, int index) {
    SGOSLoadingToast.showLoading();
    Map<String, dynamic> argument = {
      "ids": ids,
      "message_scene_code": messageSceneCode,
    };
    state.removeIndex = index;
    RequireNativeApi.postWithPathOversea(Api.getDeleteUserMessage, argument,
        getDeleteMessageSuccess, () => SGOSLoadingToast.dismissLoading());
  }

  void getDeleteMessageSuccess(
      Map<String, dynamic>? resultData, String resultCode, String resultMsg) {
    debugPrint("resultData: $resultData");
    if (resultCode == "1" && resultData != null && resultData.isNotEmpty) {
      state.deleteBean = UpdateMsgEntity.fromJson(resultData);
    }
    SGOSLoadingToast.dismissLoading();
    update([StateListenerId.messageDelete]);
  }

  ///底部按钮删除全部选中的
  void deleteCheckMessage(List<HomeMsgPageList> messageHomeList) {
    SGOSLoadingToast.showLoading();
    StringBuffer messageSceneCodes = StringBuffer();
    for (int i = 0; i < messageHomeList.length; i++) {
      String? sceneCode = messageHomeList[i].messageSceneCode;
      messageSceneCodes.write(sceneCode);
      if (i != messageHomeList.length - 1) {
        messageSceneCodes.write(',');
      }
    }
    String result = messageSceneCodes.toString();
    if (result.isEmpty) {
      return;
    }

    Map<String, dynamic> argument = {
      "ids": null,
      "message_scene_code": result,
    };
    RequireNativeApi.postWithPathOversea(Api.getDeleteUserMessage, argument,
        getDeleteMessageSuccess, () => SGOSLoadingToast.dismissLoading());
  }
}

按理来说这个GetxController类是用来访问网络的类,这里用来和原生交互,就这样子。

最近工作忙,加班重,疏于思考,缺乏输出,望大家理解,有时间优化文章,敬请期待!

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

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

相关文章

pycharm 右键运行代码时总是测试模式运行(run pytest)

*# 问题 使用pycharm时&#xff0c;右键运行代码&#xff0c;结果是这样的&#xff1a; 运行_‘pytesr(xxx.py 内)’ 英语界面可能是这样&#xff1a;run_‘pytesr(xxx.py)’我并不想使用测试模式。如何改回正常模式&#xff1f; 解决办法 本着遇到什么问题就搜什么问题的态…

英语略读三

课文的客观&#xff0c;或者逻辑推理 同增通减 比错 对比选项&#xff0c;找一个明显的区别 防并列&#xff0c;文章再说主语在干嘛干嘛的&#xff0c;但是与答案的角度不一样&#xff0c;是并列的关系 在对比选项&#xff0c;不是证明正确的 具体问题具体分析&#xff0c;but…

ICCV 2023 Oral | 从无约束图像集合中生成新视角的交叉光线神经辐射场

文章链接&#xff1a;https://arxiv.org/abs/2307.08093 代码链接&#xff1a;https://github.com/YifYang993/CR-NeRF-PyTorch.git 01. 介绍 本工作旨在通过从不受限制的图像集合&#xff08;例如从互联网中爬取的图像&#xff09;中合成新视角图片&#xff0c;从而提供3D沉浸…

在大规模推荐系统中整合 ML 模型的经验教训

一、说明 在这篇博文中&#xff0c;我们分享了将 Netflix 大规模搜索和推荐系统的多个相关机器学习模型整合到一个统一模型中的系统设计经验。给定不同的推荐用例&#xff0c;许多推荐系统将每个用例视为单独的机器学习任务&#xff0c;并为每个任务训练定制的 ML 模型。相比之…

Linux(基础IO、文件权限、Makefile)

目录 1、man 手册 1.1 汉化 1.2 具体使用 2、文件权限 2.1 权限理解 2.2 文件详细信息查询 2.3 权限更改 3、常用函数接口 3.1 open 3.2 read 3.3 write 3.4 close 3.5 函数使用示例 4、make与Makefile 4.1 make 与 Makefile区别 4.2 Makefile的编写 5、vim简…

windows11系统重装步骤及优化技巧

目录 目录 本文目的 Windows11介绍 Windows下载 和win10对比 重装步骤 系统设置调整 系统备份还原 C盘减肥&#xff0c;空间优化技巧 Java开发工具 本文目的 说明windows11的系统重装步骤&#xff0c;大部分步骤也适用于其他windows版本。常用软件的安装与介绍。系统…

《图解HTTP》——上野 宣

图解HTTP 看完这本书并在此博客下摘录书中的部分知识以便回顾。 第一章 了解Web及网络基础 1.1 使用HTTP协议访问Web Web使用一种名为HTTP(HyperText Transfer Protocol&#xff0c;超文本传输协议)的协议作为规范&#xff0c;完成从客户端到服务器端等一系列运作流程。而协…

Compose - 交互组合项

按钮 Button OutLinedButton带外边框、TextButton只是文字、IconButton只是图标形状。 Button(onClick { }, //点击回调modifier Modifier,enabled true, //启用或禁用interactionSource MutableInteractionSource(),elevation ButtonDefaults.elevatedButtonElevation( /…

Docker网络-探索容器网络如何相互通信

当今世界&#xff0c;企业热衷于容器化&#xff0c;这需要强大的网络技能来正确配置容器架构&#xff0c;因此引入了 Docker Networking 的概念。Docker 是一种容器化平台&#xff0c;允许您在独立、轻量级的容器中运行应用程序和服务。Docker 提供了一套强大的网络功能&#x…

【rust/egui】(六)看看template的app.rs:TextEdit

说在前面 rust新手&#xff0c;egui没啥找到啥教程&#xff0c;这里自己记录下学习过程环境&#xff1a;windows11 22H2rust版本&#xff1a;rustc 1.71.1egui版本&#xff1a;0.22.0eframe版本&#xff1a;0.22.0上一篇&#xff1a;这里 TextEdit 文本编辑框 其定义为&#…

【调试经验】Ubuntu22.04 安装和配置MySQL 8.0.34

在安装新版本的MySQL到电脑时&#xff0c;按着网上一些教程执行发现错误繁多&#xff0c;最后索性自己摸索并把服务装好了。自己也整理了一下在操作时的一些&#xff0c;上传分享上来希望能帮助到大家。 目录 正文 安装MySQL 配置MySQL 登录账户 方式1: 默认账户登录 方…

Tableau可视化入门实践-1

目录 Tableau 介绍基础统计图形条形图堆积图直方图饼图环形图 Tableau 介绍 Tableau是一款功能强大的数据可视化和业务智能工具&#xff0c;被广泛应用于各行各业的数据分析和决策支持领域。 Tableau提供了直观友好的用户界面&#xff0c;无需编程和复杂的数据处理技能&#x…

Tensorflow2.0搭建网络八股扩展

目录 一、自制数据集 准备&#xff1a;txt和图片 制作函数 二、断点继训&#xff0c;存取模型 1.读取保存的模型 2.保存模型 3.正确使用 三、参数提取&#xff0c;把参数存入txt 参数提取 四、acc/loss可视化&#xff0c;查看效果 1.前提开启&#xff1a;获取history…

ubuntu学习(六)----文件编程实现cp指令

1 思路 Linux要想复制一份文件通常指令为&#xff1a; cp src.c des.c 其中src.c为源文件&#xff0c;des.c为目标文件。 要想通过文件编程实现cp效果&#xff0c;思路如下 1 首先打开源文件 src.c 2 读src到buf 3 创建des.c 4 将buf写入到des.c 5 close两个文件 2 实现 vi …

并发编程基础知识篇--线程的状态和基本操作

目录 创建线程的四种方式 线程的状态和生命周期 扩展知识 线程的调度 线程状态的基本操作 interrupted 实例 join 实例 sleep 实例 扩展小知识 yield 实例 扩展 创建线程的四种方式 创建线程的四种方式 继承Thread类实现Runnable接口使用Callable和Future创…

博客系统——前端部分

目录 一、博客页面介绍 二、实现博客列表页 1、先实现导航栏 2、页面主体 左侧区域的实现&#xff1a;​编辑 右侧页面的实现&#xff1a;​编辑 博客列表页代码汇总&#xff1a; 三、实现博客详情页 代码实现&#xff1a; 四、实现博客登录页​编辑 五、博客编辑页 …

【赋权算法】Python实现熵权法

在开始之前&#xff0c;我们先说一下信息熵的概念。 当一件事情发生&#xff0c;如果是意料之中&#xff0c;那么这个事情就并不能拿来当做茶余饭后的谈资&#xff0c;我们可以说这个事情并没有什么信息和价值。而当一件不可能发生的事情发生的时候&#xff0c;我们可能就会觉…

挖数据四周年庆典,壕礼不断,惊喜不停!

挖数据四周岁啦&#xff01;为了感谢广大用户们一路以来的支持与陪伴&#xff0c;我们特地准备了丰富的优惠活动&#xff0c;希望能够用最实际的行动来回馈您们的厚爱。四年的成长与蜕变&#xff0c;都是因为有您们的陪伴与鼓励&#xff0c;我们期待与您们一同分享这份喜悦与成…

Linux 基金会宣布正式进驻中国

在 LinuxCon 2017 &#xff08;北京&#xff09;即将召开前夕&#xff0c;我们Linux 中国会同 51CTO、开源中国对 Linux 基金会执行董事 Jim Zemlin 进行了一场远跨大洋的视频专访。 在这次专访中&#xff0c;Jim 先生回答了几个开源界和互联网领域关注的问题&#xff0c;并披…

PCI设备和PCI桥的配置空间(header_type0、header_type1)和配置命令(type0、type1)详解

1、PCI典型拓扑 2、type0和type1 名称含义Bus Number设备所在总线号Device Number设备分配到的设备号Function Number功能号&#xff0c;有的设备是支持多个功能的&#xff0c;最多8种功能Register Number要访问的寄存器地址 (1)type0和type1的区别&#xff1a;AD[1:0]是00代表…