android,flutter 混合开发,pigeon通信,传参

news2025/4/12 14:17:55

文章目录

        • app效果
        • native和flutter通信的基础知识
          • 1. 编解码器 一致性和完整性,安全性,性能优化
          • 2. android代码
          • 3. dart代码
        • 1. 创建flutter_module
        • 2.修改 Android 项目的 settings.gradle,添加 Flutter module
        • 3. 在 Android app 的 build.gradle 中添加依赖
        • 4. 原生和flutter_module通信BasePlugin
        • 5. io.flutter.embedding.engine.plugins.util.GeneratedPluginRegister 自动注册插件
        • 6 手动注册
        • 7. 通信关闭flutter页面
        • 8. dartEntrypointArgs传入参数
        • 9. 通信传入参数
          • 9.1 发送参数
          • 9.1 接收参数
        • 10. android代码
        • 11 源码

app效果
在这里插入图片描述
native和flutter通信的基础知识

低级的消息通道,一般不直接使用
ServicesBinding.instance.defaultBinaryMessenger
高级别的消息通道,对defaultBinaryMessenger进行了封装,提供的更简单的api发送和接收消息
BasicMessageChannel MethodChannel EventChannel
MethodChannel EventChannel底层都是基于BasicMessageChannel

1. 编解码器 一致性和完整性,安全性,性能优化

MethodChannel,EventChannel->StandardMethodCodec
BasicMessageChannel->StandardMessageCodec
StandardMessageCodec:支持基本的数据类型(字符串、数字、布尔值、字节数组、列表、映射等)。
StandardMethodCodec:除了支持基本的数据类型外,还支持方法调用的参数和返回结果的编码和解码。
StringCodec:由于只处理字符串,StringCodec 的实现更为简单,性能更高

2. android代码
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        basicMessageChannel = BasicMessageChannel(flutterEngine.dartExecutor.binaryMessenger, BASIC_CHANNEL, StringCodec.INSTANCE)
        //创建MethodChannel
        methodChannel =
            MethodChannel(flutterEngine.dartExecutor, BASIC_CHANNEL, StandardMethodCodec.INSTANCE)

        //创建EventChannel
        eventChannel = EventChannel(flutterEngine.dartExecutor, BASIC_CHANNEL)


        basicMessageChannel.send("dddd")
        basicMessageChannel.setMessageHandler { message, reply ->
            reply.reply("dddd")
            Log.e("dddd", message.toString())
        }

        methodChannel.invokeMethod("getPlatformVersion", null)
        methodChannel.setMethodCallHandler { call, result ->
            when (call.method) {
                "getPlatformVersion" -> {
                    result.success("Android ${android.os.Build.VERSION.RELEASE}")
                }

                else -> {
                    result.notImplemented()
                }
            }
        }

        eventChannel.setStreamHandler(object : EventChannel.StreamHandler {
            override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
                eventSink = events
                eventSink?.success("Event")
            }

            override fun onCancel(arguments: Any?) {
                eventSink = null
            }
        })

    }
3. dart代码
class _StudyChannelState extends State<StudyChannel> {
  MethodChannel methodChannel = const MethodChannel('base_plugin');
  EventChannel eventChannel = const EventChannel('base_plugin');
  static const basicMessageChannel = BasicMessageChannel<String>('base_plugin', StringCodec());  
  void initState() {
    super.initState();
    //只接收
    eventChannel.receiveBroadcastStream().listen((value){

    });

    //监听
    methodChannel.setMethodCallHandler((call){
      call.method == "getData" ? print("getData") : print("method=$call");
      return Future.value("methodChannel=$call");
    });
    //执行,相当于发送
    methodChannel.invokeListMethod("getData");

    //发送
    basicMessageChannel.send("data");
    //监听
    basicMessageChannel.setMessageHandler((message){
      return Future.value("basicMessageChannel=$message");
    });

  }
  
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}
1. 创建flutter_module

File->New->New Flutter Project
name为flutter_module
选择project type为module

2.修改 Android 项目的 settings.gradle,添加 Flutter module
pluginManagement {
    repositories {
        google {
            content {
                includeGroupByRegex("com\\.android.*")
                includeGroupByRegex("com\\.google.*")
                includeGroupByRegex("androidx.*")
            }
        }
        mavenCentral()
        gradlePluginPortal()
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
    repositories {
        google()
        mavenCentral()
        maven(url = "https://storage.googleapis.com/download.flutter.io")
    }
}

rootProject.name = "hunheandroid"
include(":app")
//主要是这一句
apply(from = "../flutter_module/.android/include_flutter.groovy")
3. 在 Android app 的 build.gradle 中添加依赖
dependencies {
    implementation(project(":flutter"))
}
4. 原生和flutter_module通信BasePlugin

参考文章生成对应的io/flutter/plugins/Messages.g.kt
用pigeon kotlin swift写一个自己的插件
拷贝BasePlugin

package io.flutter.plugins

import android.app.Activity
import android.util.Log
import androidx.annotation.NonNull
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding


/** BasePlugin */
/** BasePlugin */
class BasePlugin : FlutterPlugin, HostMessageApi, ActivityAware {

    companion object {
        private var flutterMessageApi: FlutterMessageApi? = null
        fun getFlutterMessageApi(): FlutterMessageApi? {
            return flutterMessageApi
        }
    }

    private var activity: Activity? = null
    private var tag = "BasePlugin"
    override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
        Log.e(tag, "onAttachedToEngine-start")
        HostMessageApi.setUp(flutterPluginBinding.binaryMessenger, this)
        flutterMessageApi = FlutterMessageApi(flutterPluginBinding.binaryMessenger)
        Log.e(tag, "onAttachedToEngine-end")
    }

    override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
        HostMessageApi.setUp(binding.binaryMessenger, null)
    }

    override fun flutter2Native(message: String, type: Long): String {
        print("flutter2Native=message=start=>$message=type=$type")
        return "flutter2Native=message=$message=type=$type"
    }

    override fun flutter2NativeAsync(
        message: String,
        type: Long,
        callback: (Result<String>) -> Unit
    ) {
        print("flutter2NativeAsync=message=$message=type=$type")
        callback(Result.success("flutter2NativeAsync=message=$message=type=$type"))
        if (type == 1L) {
            closeCurrentActivity()
        }
    }

    private fun closeCurrentActivity() {
        activity?.finish()
    }

    override fun onAttachedToActivity(binding: ActivityPluginBinding) {
        this.activity = binding.activity
    }

    override fun onDetachedFromActivityForConfigChanges() {

    }

    override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {

    }

    override fun onDetachedFromActivity() {
        this.activity = null
    }
}
5. io.flutter.embedding.engine.plugins.util.GeneratedPluginRegister 自动注册插件
 public static void registerGeneratedPlugins(@NonNull FlutterEngine flutterEngine) {
    try {
      Class<?> generatedPluginRegistrant =
          Class.forName("io.flutter.plugins.GeneratedPluginRegistrant");
      Method registrationMethod =
          generatedPluginRegistrant.getDeclaredMethod("registerWith", FlutterEngine.class);
      registrationMethod.invoke(null, flutterEngine);
    } catch (Exception e) {
      Log.e(
          TAG,
          "Tried to automatically register plugins with FlutterEngine ("
              + flutterEngine
              + ") but could not find or invoke the GeneratedPluginRegistrant.");
      Log.e(TAG, "Received exception while registering", e);
    }
  }
package io.flutter.plugins;

import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import io.flutter.Log;

import io.flutter.embedding.engine.FlutterEngine;

/**
 * Generated file. Do not edit.
 * This file is generated by the Flutter tool based on the
 * plugins that support the Android platform.
 */
@Keep
public final class GeneratedPluginRegistrant {
  private static final String TAG = "GeneratedPluginRegistrant";
  public static void registerWith(@NonNull FlutterEngine flutterEngine) {
    try {
      Log.e(TAG, "registerWith-start");
      flutterEngine.getPlugins().add(new BasePlugin());
      Log.e(TAG, "registerWith-end");
    } catch (Exception e) {
      Log.e(TAG, "Error registering plugin base_plugin, com.app.base_plugin.BasePlugin", e);
    }
  }
}

6 手动注册

flutterEngine.getPlugins().add(new BasePlugin());

7. 通信关闭flutter页面

使用flutter和原生通信,在收到消息以后,关闭当前页面
BasePlugin实现ActivityAware,获取到activity
在收到flutter传入进来的消息的时候关闭activity

8. dartEntrypointArgs传入参数
//跳转带入参数
val initialRoute = listOf(  
                "aaa",
                "bbbb"
            )
            startActivity(
                withNewEngine()
                    .dartEntrypointArgs(initialRoute)  
                    .build(this)
            )
//args就是传入的参数
void main(List<String> args){
  print("args=$args");
  runApp(const MyApp());
}
9. 通信传入参数
9.1 发送参数
 val initialRoute = listOf(  
                "/page2",
                "bbbb"
            )
            BasePlugin.getFlutterMessageApi()?.native2Flutter(initialRoute.joinToString("#"), 1){
                Log.e(tag, "flutter2NativeAsync: $it")
                FlutterLibrary.startFlutterPage(this)
            }
9.1 接收参数

class RouterPage extends StatefulWidget {
 
  const RouterPage({super.key});

  
  State<RouterPage> createState() => _RouterPageState();
}

class _RouterPageState extends State<RouterPage> implements FlutterMessageApi {
  late String args;

  
  void initState() {
    super.initState();
    FlutterMessageApi.setUp(this);
  }

  
  String native2Flutter(String message, int type) {
    print("native2Flutter=$message $type");
    setState(() {
      args = message;
    });

    return "我是原生调用flutter方法返回的值=》native2Flutter";
  }

  
  Future<String> native2FlutterAsync(String message, int type) {
    args = message;
    print("native2Flutter=$message $type");
    return Future.value("我是原生调用flutter方法返回的值=》native2FlutterAsync");
  }

  
  Widget build(BuildContext context) {
    // final value = widget.args.isNotEmpty ? widget.args[0] : "/";
    if (args.isEmpty||!args.contains("#")) {
      return MyHomePage(title: "首页");
    }
    final value = args.split("#").first;
    switch (value) {
      case '/page2':
        return SecondPage();
    }
    print("_RouterPageState=build");
    return MyHomePage(title: "首页");
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>  {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  
  void initState() {
    super.initState();
  }

  
  Widget build(BuildContext context) {
    print("_MyHomePageState=build");
    return Scaffold(
      appBar: AppBar(title: Text(widget.title), leading: BackButton()),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            TextButton(
              onPressed: () {
                BasePlugin.flutter2NativeAsync("flutter2NativeAsync", 1).then((
                  value,
                ) {
                  print("flutter2NativeAsync=$value");
                });
              },
              child: Text('flutter2NativeAsync'),
            ),
            TextButton(
              onPressed: () {
                Navigator.of(context).pushNamed("/page2");
              },
              child: Text('flutter2NativeAsync'),
            ),
            const Text('You have pushed the button this many times:'),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }

}

class SecondPage extends StatelessWidget {
  const SecondPage({super.key});

  
  Widget build(BuildContext context) {
    print("SecondPage=build");
    return Scaffold(
      appBar: AppBar(title: Text("SecondPage")),
      body: Center(
        child: TextButton(
          onPressed: () {
            Navigator.of(context).pop();
          },
          child: Text('关闭'),
        ),
      ),
    );
  }
}

10. android代码
package com.example.hunheandroid

import android.app.Application
import android.content.Context
import android.content.Intent
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.embedding.engine.FlutterEngineCache
import io.flutter.embedding.engine.FlutterEngineGroup
import io.flutter.embedding.engine.dart.DartExecutor
import io.flutter.plugins.BasePlugin

const val ENGINE_ID = "my_engine_id"
object FlutterLibrary {
    fun init(application: Application) {
        FlutterEngineManager.getInstance().init(application)
    }
    fun startFlutterPage(context: Context) {
        val intent = FlutterActivity
            .withCachedEngine(ENGINE_ID)
            .build(context).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        context.startActivity(intent)
    }
}

// FlutterEngineManager.kt
class FlutterEngineManager private constructor() {
    private lateinit var engineGroup: FlutterEngineGroup
    private var engine: FlutterEngine? = null

    companion object {
        private var instance: FlutterEngineManager? = null

        fun getInstance(): FlutterEngineManager {
            return instance ?: synchronized(this) {
                instance ?: FlutterEngineManager().also { instance = it }

            }
        }
    }
    fun init(application: Application) {
        engineGroup = FlutterEngineGroup(application)
        engine = engineGroup.createAndRunEngine(
            application,
            DartExecutor.DartEntrypoint.createDefault()
        )
        FlutterEngineCache.getInstance().put(ENGINE_ID, engine)
        engine!!.plugins.add(BasePlugin())

    }

    fun getEngine(): FlutterEngine? {
        return engine
    }

    fun destroyEngine() {
        engine?.destroy()
        engine = null
    }
}

class GoFlutterActivity : FlutterActivity(), HostMessageApi {

    private val tag = "GoFlutterActivity"
    private lateinit var binding: ActivityGoFlutterBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityGoFlutterBinding.inflate(layoutInflater)

        setContentView(binding.root)
        binding.goFlutter.setOnClickListener {
            //跳转到flutter
            val initialRoute = listOf(  // Map 形式的参数
                "/",
                "aaaa"
            )
            BasePlugin.getFlutterMessageApi()?.native2Flutter(initialRoute.joinToString("#"), 1) {
                Log.e(tag, "flutter2NativeAsync: $it")
                FlutterLibrary.startFlutterPage(this)
            }

        }

        binding.goFlutter2.setOnClickListener {
            //跳转到flutter
            val initialRoute = listOf(  // Map 形式的参数
                "/page2",
                "bbbb"
            )
            BasePlugin.getFlutterMessageApi()?.native2Flutter(initialRoute.joinToString("#"), 1) {
                Log.e(tag, "flutter2NativeAsync: $it")
                FlutterLibrary.startFlutterPage(this)
            }

        }
    }

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        Log.e(tag, "configureFlutterEngine")
//        GeneratedPluginRegistrant.registerWith(flutterEngine)
    }

    override fun flutter2Native(message: String, type: Long): String {
        Log.e(tag, "$message$type")
        return "我是flutter调用原生方法的返回值=》flutter2Native"
    }

    override fun flutter2NativeAsync(
        message: String,
        type: Long,
        callback: (Result<String>) -> Unit
    ) {
        Log.e(tag, "$message$type")
        callback(Result.success("我是flutter调用原生方法的返回值=》flutter2NativeAsync"))

    }


}
11 源码

gitee

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

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

相关文章

unity学习47:寻路和导航,unity2022后版本如何使用 Navmesh 和 bake

目录 1 寻路和导航对移动的不同 1.1 基础的移动功能 1.1.1 基础移动 1.1.2 智能导航寻路 1.1.3 智能导航寻路还可以 2 如何实现这个效果&#xff1f; 2.1 通过地图网格的形式 2.1.1 警告信息 the static value has been deprecated的对应搜索 2.1.2 新的navigation ba…

跟着李沐老师学习深度学习(十二)

循环神经网络 序列模型 序列数据 实际中很多数据是有时序结构的 比如&#xff1a;电影的评价随时间变化而变化 拿奖后评分上升&#xff0c;直到奖项被忘记看了很多好电影后&#xff0c;人们的期望变高季节性:贺岁片、暑期档导演、演员的负面报道导致评分变低 核心思想&#…

深入解析NoSQL数据库:从文档存储到图数据库的全场景实践

title: 深入解析NoSQL数据库:从文档存储到图数据库的全场景实践 date: 2025/2/19 updated: 2025/2/19 author: cmdragon excerpt: 通过电商、社交网络、物联网等12个行业场景,结合MongoDB聚合管道、Redis Stream实时处理、Cassandra SSTable存储引擎、Neo4j路径遍历算法等42…

STM32物联网终端实战:从传感器到云端的低功耗设计

STM32物联网终端实战&#xff1a;从传感器到云端的低功耗设计 一、项目背景与挑战分析 1.1 物联网终端典型需求 &#xff08;示意图说明&#xff1a;传感器数据采集 → 本地处理 → 无线传输 → 云端存储&#xff09; 在工业物联网场景中&#xff0c;终端设备需满足以下核心需…

[实现Rpc] 客户端划分 | 框架设计 | common类的实现

目录 3. 客户端模块划分 3.1 Network模块 3.2 Protocol模块 3.3 Dispatcher模块 3.4 Requestor模块 3.5 RpcCaller模块 3.6 Publish-Subscribe模块 3.7 Registry-Discovery模块 3.8 Client模块 4. 框架设计 4.1 抽象层 4.2 具象层 4.3 业务层 ⭕4.4 整体设计框架…

【SFRA】笔记

GK_SFRA_INJECT(x) SFRA小信号注入函数,向控制环路注入一个小信号。如下图所示,当前程序,小信号注入是在固定占空比的基础叠加小信号,得到新的占空比,使用该占空比控制环路。 1.2 GK_SFRA_COLLECT(x, y) SFRA数据收集函数,将小信号注入环路后,该函数收集环路的数据,以…

基于Python的Diango旅游数据分析推荐系统设计与实现+毕业论文(15000字)

基于Python的Diango旅游数据分析推荐系系统设计与实现毕业论文指导搭建视频&#xff0c;带爬虫 配套论文1w5字 可定制到某个省份&#xff0c;加40 基于用户的协同过滤算法 有后台管理 2w多数据集 可配套指导搭建视频&#xff0c;加20 旅游数据分析推荐系统采用了Python语…

国自然青年基金|针对罕见神经上皮肿瘤的小样本影像深度数据挖掘关键技术研究|基金申请·25-02-15

小罗碎碎念 今天和大家分享一个国自然青年基金项目&#xff0c;执行年限为2021.01&#xff5e;2023.12&#xff0c;直接费用为24万元。 该项目聚焦罕见神经上皮肿瘤小样本影像深度数据挖掘技术&#xff0c;致力于攻克小样本数据和临床经验缺乏带来的难题。项目围绕影像规范化、…

Linux 网络安全技巧

网络安全是一个非常重要的课题,基本上你运行的服务后台越多,你就可能打开更多的安全漏洞.如果配置的恰当的话,Linux本身是非常安全可靠的,假使在Linux系统中有某个安全缺陷,由于Linux的源码是开放的&#xff0c;有成千上万的志愿者会立刻发现并修补它。本文旨在介绍用来增强你的…

Windows桌面系统管理7:国产操作系统与Linux操作系统

Windows桌面系统管理0&#xff1a;总目录-CSDN博客 Windows桌面系统管理1&#xff1a;计算机硬件组成及组装-CSDN博客 Windows桌面系统管理2&#xff1a;VMware Workstation使用和管理-CSDN博客 Windows桌面系统管理3&#xff1a;Windows 10操作系统部署与使用-CSDN博客 Wi…

百度百舸 DeepSeek 一体机发布,支持昆仑芯 P800 单机 8 卡满血版开箱即用

在私有云环境中成功部署 DeepSeek 满血版并实现性能调优&#xff0c;并不是一件容易的事情。选择合适的 GPU 配置、安装相应的环境、成功部署上线业务、加速推理任务加速、支撑多用户并发 …… 完成业务测试&#xff0c;成功融入生产业务中。 为了帮助企业快速实现 DeepSeek 服…

解锁 AIoT 无限可能,乐鑫邀您共赴 Embedded World 2025

2025 年 3 月 11-13 日&#xff0c;全球规模最大的嵌入式展览会——Embedded World 2025 将在德国纽伦堡盛大开幕。作为物联网和嵌入式技术领域的领先企业&#xff0c;乐鑫信息科技 (688018.SH) 将展示在 AI LLM、HMI、双频 Wi-Fi 6、低功耗 MCU 和 Matter 等领域的最新技术及解…

LlamaFactory可视化模型微调-Deepseek模型微调+CUDA Toolkit+cuDNN安装

LlamaFactory https://llamafactory.readthedocs.io/zh-cn/latest/ 安装 必须保证版本匹配&#xff0c;否则到训练时&#xff0c;找不到gpu cuda。 否则需要重装。下面图片仅供参考。因为cuda12.8装了没法用&#xff0c;重新搞12.6 cudacudnnpytorch12.69.612.6最新&#xf…

【GPT】从GPT1到GPT3

every blog every motto: Although the world is full of suffering&#xff0c; it is full also of the overcoming of it 0. 前言 从GPT1 到GPT3 1. GPT1 论文&#xff1a; https://s3-us-west-2.amazonaws.com/openai-assets/research-covers/language-unsupervised/lan…

openGauss 3.0 数据库在线实训课程18:学习视图管理

前提 我正在参加21天养成好习惯| 第二届openGauss每日一练活动 课程详见&#xff1a;openGauss 3.0.0数据库在线实训课程 学习目标 掌握openGauss视图的管理&#xff1a;创建视图、删除视图、查询视图的信息、修改视图的信息。 课程作业 1.创建表&#xff0c;创建普通视图…

基于flask+vue的租房信息可视化系统

✔️本项目利用 python 网络爬虫抓取某租房网站的租房信息&#xff0c;完成数据清洗和结构化&#xff0c;存储到数据库中&#xff0c;搭建web系统对各个市区的租金、房源信息进行展示&#xff0c;根据各种条件对租金进行预测。 1、数据概览 ​ 将爬取到的数据进行展示&#xff…

手写简易RPC(实践版)

首先了解rpc rpc-远程过程调用&#xff0c;openFeign&#xff0c;Dubbo都可以算作rpc&#xff0c;以微服务来具体说明&#xff0c;就是在本地不需要去发送请求&#xff0c;通过rpc框架&#xff0c;像调用本地方法一样调用其他服务的方法&#xff0c;本质上还是要经过网络&…

mysql学习笔记-多版本并发控制

1、什么是ReadView 在 MVCC机制中&#xff0c;多个事务对同一个行记录进行更新会产生多个历史快照&#xff0c;这些历史快照保存在 Undo Log里。如果一个事务想要查询这个行记录&#xff0c;需要读取哪个版本的行记录呢?这时就需要用到 ReadView 了&#xff0c;它帮我们解决了…

算法日记20:SC72最小生成树(prim朴素算法)

一、题目&#xff1a; 二、题解 2.1&#xff1a;朴素prim的步骤解析 O ( n 2 ) O(n^2) O(n2)(n<1e3) 0、假设&#xff0c;我们现在有这样一个有权图 1、我们随便找一个点&#xff0c;作为起点开始构建最小生成树(一般是1号)&#xff0c;并且存入intree[]状态数组中&#xf…

Redis7——基础篇(五)

前言&#xff1a;此篇文章系本人学习过程中记录下来的笔记&#xff0c;里面难免会有不少欠缺的地方&#xff0c;诚心期待大家多多给予指教。 基础篇&#xff1a; Redis&#xff08;一&#xff09;Redis&#xff08;二&#xff09;Redis&#xff08;三&#xff09;Redis&#x…