Flutter 数据持久化存储之Hive库

news2025/4/21 19:00:41

Flutter 数据持久化存储之Hive库

  • 前言
  • 正文
    • 一、配置项目
    • 二、UI
      • ① 增加UI
      • ② 显示和删除UI
    • 三、使用Hive
      • ① 初始化Hive
      • ② TypeAdapter自定义对象
      • ③ 注册TypeAdapter
      • ③ CURD
    • 四、源码

前言

  在Flutter中,有多种方式可以进行数据持久化存储。以下是一些常见的方式:

  1. Shared Preferences:
    使用shared_preferences插件,可以将数据存储在设备的轻量级持久化存储中。这种方式适合存储少量简单的键值对数据,比如用户偏好设置等。

  2. 文件存储:
    使用dart:io库可以进行文件存储,可以将数据以文件的形式存储在设备上。这种方式适合存储结构化数据,可以使用JSON格式或者其他格式进行数据的读写。

  3. SQLite数据库:
    可以使用sqflite插件在Flutter应用中使用SQLite数据库。SQLite是一种轻量级的关系型数据库,适合于需要存储结构化数据,并进行高效查询的场景。

  4. NoSQL数据库:
    一些Flutter插件(如moor)也提供了对NoSQL数据库的支持,比如使用对象数据库(如Hive)来存储数据。

  5. 云存储:
    通过与云存储(如Firebase Firestore、AWS Amplify等)进行集成,可以将数据存储在云端,实现跨设备数据同步和备份。

以上的这些我们都不使用,这里要使用的是Hive库,地址是 Hive,感兴趣的可以自行了解,本文运行效果图。

在这里插入图片描述

正文

  Hive是一个轻量级、快速的本地数据库解决方案,适用于在移动应用程序中进行数据持久化存储。Hive采用高效的自定义序列化算法,能够在移动设备上快速读写数据,适用于处理结构化数据。并且Hive是用纯Dart编写的,这使得它比不支持Flutter网络的SQLite更有优势。

一、配置项目

  首先我们创建一个名为study_hive的项目。

在这里插入图片描述

  创建项目之后,我们配置一下依赖库,在项目的pubspec.yaml文件中,添加如下所示代码:

dependencies:
  get:

  hive:
  hive_flutter:

dev_dependencies:

  hive_generator:
  build_runner:

  在dependencies中我添加了get和hive的库,在dev_dependencies中添加了一个构建对象的依赖库。冒号后面没有写版本号就是获取该库最新的版本。添加位置如下图所示:

在这里插入图片描述

然后点击Pub get获取对应的依赖库即可,到这里为止我们的配置工作就完成了。

二、UI

  在使用Hive库时我们需要想一下,用这个库去做什么?先设想一个应用场景,而不是写到哪里就是哪里,乱枪打鸟不可取。我们就写这样一个场景,对于人员信息的操作,可以增加、查询、修改、删除、删除所有。基于这个场景我们就可以去设计UI了,我们尽量在一个页面去解决,更直观一些(PS:我也是偷一个懒)。

  首先我们在lib目录下新建一个page包,page包下新建一个hive_page.dart,里面的代码如下:

import 'package:flutter/material.dart';

class HivePage extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Hive Demo"),
      ),
      body: Container(
        color: Colors.blue,
      ),
    );
  }
}

  当前页面很简单,就是一个标题和蓝色背景,当然你现在还看不到的,我们需要修改一下main.dart中的代码:

import 'package:flutter/material.dart';
import 'package:study_hive/page/hive_page.dart';

void main() async {
  runApp(const MyApp());
}

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Hive Demo',
      theme: ThemeData(
        primaryColor: Colors.blueAccent,
        appBarTheme: const AppBarTheme(elevation: 0),
      ),
      home: HivePage(),
    );
  }
}

  这里的修改就是去掉了原来默认代码,并且加载我们刚写好的HivePage,下面我们可以运行一下,虚拟器或者真机都可以。

在这里插入图片描述

① 增加UI

在HivePage的build()中增加如下代码:

    ///通用输入框
    Widget baseEdit(String hintText, TextInputType type,
        TextEditingController textController) {
      return Container(
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(10),
          border: Border.all(
            color: Colors.black87,
            width: 1.0,
          ),
        ),
        margin: const EdgeInsets.only(top: 6),
        padding: const EdgeInsets.all(0),
        height: 44,
        child: TextField(
          textInputAction: TextInputAction.none,
          keyboardType: type,
          cursorColor: Colors.black87,
          cursorWidth: 1,
          controller: textController,
          decoration: InputDecoration(
            contentPadding: const EdgeInsets.only(left: 10),
            filled: true,
            fillColor: Colors.white,
            hintText: hintText,
            hintStyle: const TextStyle(
              textBaseline: TextBaseline.alphabetic,
              color: Colors.grey,
            ),
            border: OutlineInputBorder(
              borderRadius: BorderRadius.circular(10),
              borderSide: BorderSide.none,
            ),
          ),
        ),
      );
    }

  这里的代码就是构建一个输入框的组件,将里面的提示文本、键盘类型和输入框控制器抽离了出来。控制器我们就放到GetX中使用,在page包下新建一个hive_controller.dart,代码如下所示:

import 'package:flutter/material.dart';
import 'package:get/get.dart';

class HiveController extends GetxController {

  late TextEditingController nameEditController,ageEditController;

  
  void onInit() {
    super.onInit();
    nameEditController = TextEditingController();
    ageEditController = TextEditingController();
  }
}

  这里主要就是对于输入框控制器的初始化。回到HivePage的build中再写两个组件,代码如下:

    var size4 = const SizedBox(
      height: 4,
      width: 4,
    );

    ///保存按钮
    var saveBtn = TextButton(
        onPressed: () {
          print('Save');
        },
        child: const Text(
          'Save',
          style: TextStyle(color: Colors.blue),
        ));

  一个是间隔,一个是保存按钮,然后我们可以再写一个组件用来包含刚才所写的内容。这里面就需要用到baseEdit去构建两个输入框,因此我们加上GetX,在page包下新建一个hive_controller.dart,代码如下所示:

import 'package:flutter/material.dart';
import 'package:get/get.dart';

class HiveController extends GetxController {

  late TextEditingController nameEditController,ageEditController;

  
  void onInit() {
    super.onInit();
    nameEditController = TextEditingController();
    ageEditController = TextEditingController();
  }
}

回到HivePage中,在build中增加一个组件,代码如下:

	///保存组件
    var saveWidget = Container(
      width: MediaQuery.of(context).size.width,
      margin: const EdgeInsets.all(8),
      padding: const EdgeInsets.all(8),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(12.0),
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          baseEdit('Name', TextInputType.name, controller.nameEditController),
          size4,
          baseEdit('Age', TextInputType.number, controller.ageEditController),
          saveBtn
        ],
      ),
    );

最后我们再修改一下返回的Scaffold中的代码,在这里我们加载刚才写好的保存组件,如下所示:

	return Scaffold(
      appBar: AppBar(
        title: const Text("Hive Demo"),
      ),
      body: Container(
        color: Colors.blue,
        child: Column(
          children: [saveWidget],
        ),
      ),
    );

这里你需要注意的就是代码的顺序了,当前这个组件在最下边,通过一张图来说明。

在这里插入图片描述

运行一下:

在这里插入图片描述

这样增加的UI就写好了,下面我们构建显示和删除的。

② 显示和删除UI

在build中添加如下代码:

    ///列表组件
    var listWidget = Expanded(
        child: Container(
      width: MediaQuery.of(context).size.width,
      // 允许高度自适应
      margin: const EdgeInsets.only(left: 8, right: 8, bottom: 8),
      padding: const EdgeInsets.all(8),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(12.0),
      ),
    ));
    
    var deleteAllBtn = ElevatedButton(
        onPressed: () {
          print('DeleteAll');
        },
        child: const Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            Icon(Icons.delete, color: Colors.red),
            SizedBox(width: 4),
            Text(
              'DeleteAll',
              style: TextStyle(color: Colors.red),
            )
          ],
        ));

再修改一下返回的Scaffold,将列表和按钮组件添加进去,代码如下所示:

    return Scaffold(
      appBar: AppBar(
        title: const Text("Hive Demo"),
      ),
      body: Container(
        color: Colors.blue,
        child: Column(
          children: [saveWidget, listWidget, deleteAllBtn],
        ),
      ),
    );

再保存一下,热重载,效果如图所示:

在这里插入图片描述

三、使用Hive

下面我们就可以开始使用Hive了,之前我们已经添加过依赖了,下面我们首先进行初始化。

① 初始化Hive

  在Flutter中使用Hive,我们需要在main()函数中进行初始化,注意导包语句:

import 'package:hive_flutter/hive_flutter.dart';

main()函数代码如下所示:

void main() async {
  //初始化Hive
  await Hive.initFlutter();
  
  runApp(const MyApp());
}

  初始化之后我们就可以去使用了,在此之前我们需要明确使用的方式,因为我们操作的是对象,包含常规的数据类型,因此我们就需要自定义对象。

② TypeAdapter自定义对象

  在lib下创建一个models目录,该目录下创建person.dart文件,代码如下:

class Person {
  
  String name;
  int age;

  Person({required this.name,required this.age});
}

  这是标准的对象代码,然后我们可以使用Hive注释这个类和类里面的变量,然后快速生成一个TypeAdapter类代码,下面我们修改一下Person的代码如下:

import 'package:hive/hive.dart';

part 'person.g.dart';

(typeId: 1)
class Person {
  (0)
  String name;

  (1)
  int age;

  Person({required this.name, required this.age});
}

  首先注意导包的语句,这里的part 'person.g.dart';语句会标红,这是因为目前还没有这个文件,这个文件就是我们需要快捷生成的。HiveType 和 HiveField 是 Hive 数据库中用来定义对象映射和序列化的注解。

  1. HiveType:

    • HiveType 是一个标记注解,用于标识 Hive 中的自定义对象类。它告诉 Hive 数据库,被注解的类是一个 Hive 对象,需要进行序列化和反序列化。
    • 当你在定义自己的模型类时,可以使用 @HiveType() 注解来标记这个类,以便 Hive 可以识别并处理这个类。
    • 所有的 typeId 允许在 0 到 223 之间,不可以重复。
  2. HiveField:

    • HiveField 是用来标记类中的字段(成员变量)的注解,用于指定字段在 Hive 数据库中的位置和顺序。
    • 当你在定义自己的模型类时,可以使用 @HiveField() 注解来标记类中的字段,以便 Hive 可以按照指定的顺序进行序列化和反序列化。
    • 字段编号的范围可为 0~255,不可以重复。

  下面我们通过在Terminal中输入一行代码,生成对应的TypeAdapter对象类,代码如下所示:

flutter packages pub run build_runner build

输入后回车,如下图所示:

在这里插入图片描述

  你会看到对应的person.g.dart文件就已经生成在models文件夹中,里面的代码如下所示:

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'person.dart';

// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************

class PersonAdapter extends TypeAdapter<Person> {
  
  final int typeId = 1;

  
  Person read(BinaryReader reader) {
    final numOfFields = reader.readByte();
    final fields = <int, dynamic>{
      for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
    };
    return Person(
      name: fields[0] as String,
      age: fields[1] as int,
    );
  }

  
  void write(BinaryWriter writer, Person obj) {
    writer
      ..writeByte(2)
      ..writeByte(0)
      ..write(obj.name)
      ..writeByte(1)
      ..write(obj.age);
  }

  
  int get hashCode => typeId.hashCode;

  
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is PersonAdapter &&
          runtimeType == other.runtimeType &&
          typeId == other.typeId;
}

下面我们注册TypeAdapter对象

③ 注册TypeAdapter

  依然是修改main()函数,注意一点,在打开使用Hive的盒子之前,需要先注册TypeAdapter,代码如下所示:

import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:study_hive/models/person.dart';
import 'package:study_hive/page/hive_page.dart';

void main() async {
  //初始化Hive
  await Hive.initFlutter();
  //注册TypeAdapter
  Hive.registerAdapter(PersonAdapter());
  //打开盒子
  await Hive.openBox<Person>('personBox');
  runApp(const MyApp());
}

  注意导包语句,现在我们的盒子就打开了,盒子名称是personBox,这个可以自己去定义的,下面我们就可以正式去使用这个盒子来进行CURD了。

③ CURD

  在进行CURD时,我们将代码写在GetxController中,提供相关的函数进行操作,下面我们修改一下HiveController中的代码:

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:study_hive/models/person.dart';

class HiveController extends GetxController {
  late TextEditingController nameEditController, ageEditController;
  final personBox = Hive.box<Person>('personBox');

  
  void onInit() {
    super.onInit();
    nameEditController = TextEditingController();
    ageEditController = TextEditingController();
  }

  void save() {
    var person = Person(
        name: nameEditController.text, age: int.parse(ageEditController.text));
    personBox.add(person);
    nameEditController.clear();
    ageEditController.clear();
  }

  void modify(int index, Person person) {
    personBox.putAt(index, person);
  }

  void delete(int index) {
    personBox.deleteAt(index);
  }

  void deleteAll() {
    personBox.clear();
  }

  
  void onClose() {
    nameEditController.dispose();
    ageEditController.dispose();
    super.onClose();
  }
}

  上面的代码解释一下,首先我们获取personBox盒子对象,final personBox = Hive.box<Person>('personBox');,然后就是save()函数中获取输入框的值进行保存,保存之后再清空输入框,这里就没有对输入框的内容判空处理,需要注意一下。modify()函数中通过下标和person对象就可以完成,删除和删除所有就是可以直接处理的,就没有什么好说的。你会发现没有查询,这是因为Hive提供了一个名为ValueListenableBuilder 的小部件,它只在数据库内的任何数值被修改时才会刷新。下面我们就可以在HivePage中去使用刚才所写的函数。

首先我们修改一下listWidget组件的代码:

    var listWidget = Expanded(
        child: Container(
            width: MediaQuery.of(context).size.width,
            margin: const EdgeInsets.only(left: 8, right: 8, bottom: 8),
            padding: const EdgeInsets.all(8),
            decoration: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.circular(12.0),
            ),
            child: ValueListenableBuilder(
                valueListenable: controller.personBox.listenable(),
                builder: (context, box, widget) {
                  if (box.isEmpty) {
                    return const Center(
                      child: Text('Empty'),
                    );
                  } else {
                    return ListView.builder(
                        itemCount: box.length,
                        itemBuilder: (context, index) {
                          var personData = box.getAt(index)!;
                          return ListTile(
                            title: Text(personData.name),
                            subtitle: Text(personData.age.toString()),
                            trailing: Row(
                              mainAxisSize: MainAxisSize.min,
                              children: <Widget>[
                                IconButton(
                                  icon: const Icon(Icons.edit),
                                  onPressed: () {
                                    showModifyDialog(index, personData);
                                  },
                                ),
                                IconButton(
                                  icon: const Icon(Icons.delete),
                                  onPressed: () {
                                    controller.delete(index);
                                  },
                                ),
                              ],
                            ),
                          );
                        });
                  }
                })));

  这里的核心代码就是ValueListenableBuilder 的使用,这里我们判断了box是否为空,空就显示文字提示一下,不为空就构建一个ListView显示Item数据。如下图所示:

在这里插入图片描述

  在列表的Item中我们除了显示用户的名称和年龄之外还有两个功能按钮,分别用于修改和删除,如下图所示:

在这里插入图片描述

  针对于删除很简单之后调用控制器里面写好的函数就可以了,删除之后列表会自动刷新的。而修改的话屏幕上没有空间了,因此我就写一个弹窗去显示需要修改的内容,代码如下所示:

    void showModifyDialog(int index, Person personData) => showDialog(
        context: context,
        builder: (BuildContext context) {
          TextEditingController nameController =
              TextEditingController(text: personData.name);
          TextEditingController ageController =
              TextEditingController(text: personData.age.toString());

          return AlertDialog(
            title: const Text('Modify Data'),
            content: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                TextField(controller: nameController),
                TextField(controller: ageController)
              ],
            ),
            actions: [
              ElevatedButton(
                  child: const Text('Modify'),
                  onPressed: () {
                    var person = Person(
                        name: nameController.text,
                        age: int.parse(ageController.text));
                    controller.modify(index, person);
                    Navigator.of(context).pop(); // 关闭对话框
                  })
            ],
          );
        });

弹窗修改之后就关闭弹窗。最后我们再修改一下保存按钮和删除所有按钮组件的代码,如下所示:


    var saveBtn = TextButton(
        onPressed: () {
          controller.save();
        },
        child: const Text(
          'Save',
          style: TextStyle(color: Colors.blue),
        ));
        
    var deleteAllBtn = ElevatedButton(
        onPressed: () {
          controller.deleteAll();
        },
        child: const Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            Icon(Icons.delete, color: Colors.red),
            SizedBox(width: 4),
            Text(
              'DeleteAll',
              style: TextStyle(color: Colors.red),
            )
          ],
        ));

那么基本上代码就写完了,下面我们整体看一下运行效果。

在这里插入图片描述

效果符合我的预期,文章到这里就结束了,元宵节快乐呀!

四、源码

源码地址:study_hive

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

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

相关文章

linux下查看某个命令在哪里个安装包程序下,以ifconfig命令举例子

yum list | grep net-tools &#xff08;查看yum安装列表中有没有安装指定的软件工具&#xff09;

Leetcoder Day29| 贪心算法part03

1005.K次取反后最大化的数组和 给定一个整数数组 A&#xff0c;我们只能用以下方法修改该数组&#xff1a;我们选择某个索引 i 并将 A[i] 替换为 -A[i]&#xff0c;然后总共重复这个过程 K 次。&#xff08;我们可以多次选择同一个索引 i。&#xff09; 以这种方式修改数组后&a…

Fast admin改变对话框的文字,并且绑定参数,确认和取消都可以做修改

需求&#xff1a;点击确认和拒绝都要做出对应的操作 列表添加一个buttos按钮用来单击触发对话框 {field: operate, title: __(Operate), table: table, events: Table.api.events.operate, buttons: [{name: click,title: __(点击执行事件),classname: btn btn-xs btn-info bt…

逆变器专题(6)-正负序分离(二阶广义积分器DSOGI)

相应仿真原件请移步资源下载 DSOGI作为一种常用的正负序分离方法&#xff0c;其可以在电压三相不平衡的状态下实现较为精准的锁相环。 原理 构建基于二阶广义积分器的自适应滤波器来实现90相角偏移和谐波的滤除。 其中&#xff0c;&#xff0c;表示原信号进行滞后90&#xff…

成功解决IndexError: Target 20 is out of bounds.

【PyTorch】成功解决IndexError: Target 20 is out of bounds. &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1f448; 希望得到您…

Redisson限流算法

引入依赖 <dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.12.3</version> </dependency>建议版本使用3.15.5以上 使用 这边写了一个demo示例&#xff0c;定…

kswapd0挖矿病毒攻击记录

文章目录 一、起因与病毒分析1、起因2、阿里云告警2.1 恶意脚本代码执行12.2 恶意脚本代码执行22.3恶意脚本代码执行32.4 恶意脚本代码执行4 3、病毒简单分析3.1 病毒的初始化3.2 病毒本体执行 4、总结 二、ubuntu自救指南1、病毒清理2、如何防御 一、起因与病毒分析 1、起因 …

跳跃游戏Ⅱ

问题 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说&#xff0c;如果你在 nums[i] 处&#xff0c;你可以跳转到任意 nums[i j] 处: 0 < j < nums[i] i j < n 返回到达 nums[n - …

【深蓝学院】移动机器人运动规划--第7章 集群机器人运动规划--笔记

文章目录 0. Contents1. Multi-Agent Path Finding (MAPF)1.1 HCA*1.2 Single-Agent A*1.3 ID1.4 M*1.5 Conflict-Based Search(CBS)1.6 ECBS1.6.1 heuristics1.6.2 Focal Search 2. Velocity Obstacle (VO&#xff0c;速度障碍物)2.1 VO2.2. RVO2.3 ORCA 3. Flocking model&am…

EAS web 界面加载后,隐藏按钮

效果&#xff1a;隐藏下列按钮&#xff1a; 实现方法&#xff1a; 1、创建数据装载事件&#xff1a; 2、隐藏按钮&#xff1a; afterOnloadHideEntryTBBBBBB:function(e){console.log("----------失败222&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&a…

Redis主从、哨兵、Redis Cluster集群架构

Redis主从、哨兵、Redis Cluster集群架构 Redis主从架构 Redis主从架构搭建 主从搭建的问题 如果同步数据失败&#xff0c;查看log日志报错无法连接&#xff0c;检查是否端口未开放出现”Error reply to PING from master:...“日志&#xff0c;修改参数protected-mode no …

WebDAV之π-Disk派盘 + DAVx⁵

DAVx⁵是一款通过标准 CardDAV 和 CalDAV 协议同步通讯录、日历的 Android 应用,支持 iCloud 等云服务,只需要在 Android 端安装,即可实现在 iPhone 与 Android 间双向同步通讯录、日历、提醒事项等数据。 资源自动检测,支持自签名证书,通过客户端证书进行身份验证;可以…

如何使用Windows系统电脑无公网ip远程桌面Ubuntu系统

文章目录 前言1. ubuntu安装VNC2. 设置vnc开机启动3. windows 安装VNC viewer连接工具4. 内网穿透4.1 安装cpolar【支持使用一键脚本命令安装】4.2 创建隧道映射4.3 测试公网远程访问 5. 配置固定TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址5.3 测试…

SpringBoot整合rabbitmq-直连交换机队列(二)

说明&#xff1a;本文章主要是Direct定向/直连类型交换机的使用&#xff0c;它的大致流程是将一个队列绑定到一个直连交换机上&#xff0c;并赋予一个路由键 routingkey&#xff0c;当一个消息携带着路由值为routingkey&#xff0c;这个消息通过生产者发送给交换机时&#xff0…

Unity UI适配规则和对热门游戏适配策略的拆解

前言 本文会介绍一些关于UI适配的基础概念&#xff0c;并且统计了市面上常见的设备的分辨率的情况。同时通过拆解目前市面上较为成功的两款休闲游戏Royal Match和Monopoly GO(两款均为近期游戏付费榜前几的游戏)&#xff0c;大致推断出他们的适配策略&#xff0c;以供学习和参…

CP AutoSar之LIN Driver详细说明

本文遵循autosar标准&#xff1a;R22-11 1 简介 本文指定了 AUTOSAR 基础软件模块 LIN 驱动程序的功能、API 和配置。 1.1 范围 LIN驱动程序适用于ISO 17987主节点和从节点。AUTOSAR中的LIN实现偏离了本LIN驱动器规范中所述的ISO 17987规范&#xff0c;但LIN总线上的行为不…

Allure报告归纳与总结

一、环境准备&#xff1a; 提前准备环境:Java1.8 Allure2 解析过程: 1.安装 allure2(信赖Java1.8) allure官方下载地址&#xff1a; https://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline/ 2.安装 allure-pytest 命令:pip install allure-pytest 3.生成…

Mamba 作者谈 LLM 未来架构

文章目录 前言 1、为什么注意力机制有效&#xff1f; 2、注意力计算量呈平方级增长 3、Striped Hyena 是个什么模型&#xff1f; 4、什么是 Mamba? 5、Mamba 硬件优化 6、2024年架构预测 7、对 AI 更多的预测 本片文章来自【机器之心】对Mamba作者进行采访所进行的编译整理。 …