Flutter 应用数据持久化指南

1. 介绍

1.1 什么是数据持久化?

数据持久化是指将应用程序中的数据保存在持久存储介质(如硬盘、数据库等)中的过程。在计算机科学领域,持久化数据是指数据在程序退出或系统关机后仍然存在的能力。这种持久性使得数据可以在不同的应用程序运行周期之间保持不变,以便稍后进行检索、处理和使用。

在移动应用开发中,数据持久化是指将应用程序中的用户数据(如用户偏好设置、用户登录状态、应用配置等)保存在设备上,以便在应用关闭或设备重启后仍然保持。这样可以确保用户在不同的应用使用场景中,其数据状态可以得到保留和恢复。

1.2 为什么在Flutter应用中需要数据持久化?

在Flutter应用中,数据持久化是一项至关重要的任务,这是因为:

  1. 用户体验改善: 持久化数据可以确保用户的个性化设置、历史数据、登录状态等在应用关闭或重启后得以保留,提升了用户体验。

  2. 应用状态管理: 应用中的状态数据(如购物车内容、用户设置)可能需要在应用生命周期中保持不变,以确保应用的连续性和一致性。

  3. 离线支持: 某些应用场景下,用户可能会在没有网络连接的情况下使用应用,此时需要将数据持久化到本地以提供离线支持。

  4. 数据共享: 持久化数据可以使得不同的模块或组件之间共享数据更加方便,同时也可以实现跨设备的数据同步。

因此,数据持久化在Flutter应用中扮演着至关重要的角色,它不仅可以改善用户体验,还可以提高应用的可靠性和灵活性。

在这里插入图片描述

2. Flutter中的数据持久化方式

2.1 Shared Preferences

Shared Preferences是Flutter中用于轻量级数据存储的一种方式,它允许将简单的键值对保存到设备上的持久化存储中。通常用于存储用户的偏好设置、配置信息等。

优点:

  • 简单易用,不需要额外的依赖库。
  • 适用于存储少量的简单数据。
  • 跨应用共享数据。

缺点:

  • 仅适用于存储简单的键值对数据,不适合存储复杂数据结构。
  • 不支持查询操作,只能通过键获取值。

2.2 SQLite数据库

SQLite是一种轻量级的关系型数据库,Flutter提供了SQLite数据库的支持,可以通过dart语言的sqflite库进行操作。SQLite适用于需要存储大量结构化数据的情况。

优点:

  • 支持复杂的查询操作,适用于存储和管理大量结构化数据。
  • 数据库的持久化存储,适用于需要长期保存数据的应用场景。

缺点:

  • 使用相对较复杂,需要熟悉SQL语法。
  • 需要引入第三方库(如sqflite)来实现数据库操作。

2.3 文件存储(File Storage)

Flutter也支持直接将数据存储到文件中,可以通过dart语言的File类进行文件操作。文件存储适用于存储非结构化或半结构化的数据,如图片、文本等。

优点:

  • 灵活性高,可以存储各种类型的数据。
  • 适用于存储大文件或非结构化数据。

缺点:

  • 需要手动管理文件的读写操作,相对麻烦。
  • 不适合存储大量结构化数据,查询和操作相对复杂。

2.4 使用第三方库

除了上述原生的数据持久化方式外,Flutter还有许多第三方库可供选择,如Hive数据库、ObjectBox等。这些库提供了不同的特性和性能优化,可以根据具体需求选择最合适的库进行数据持久化操作。

优点:

  • 提供了丰富的功能和性能优化。
  • 可以根据需求选择最合适的库。

缺点:

  • 引入第三方库可能增加应用的体积。
  • 学习成本相对较高,需要熟悉库的使用方法和特性。

3. Shared Preferences

3.1 安装与导入

在Flutter项目中使用Shared Preferences,首先需要在项目的pubspec.yaml文件中添加依赖,并运行flutter pub get命令来安装依赖包。

dependencies:shared_preferences: ^2.0.0

安装完成后,在需要使用的Dart文件中导入shared_preferences库。

import 'package:shared_preferences/shared_preferences.dart';

3.2 使用示例

下面是一个简单的示例,演示了如何使用Shared Preferences在Flutter应用中存储和读取数据。

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {Widget build(BuildContext context) {return MaterialApp(home: MyHomePage(),);}
}class MyHomePage extends StatefulWidget {_MyHomePageState createState() => _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {int _counter = 0;void initState() {super.initState();_loadCounter();}_loadCounter() async {SharedPreferences prefs = await SharedPreferences.getInstance();setState(() {_counter = (prefs.getInt('counter') ?? 0);});}_incrementCounter() async {SharedPreferences prefs = await SharedPreferences.getInstance();setState(() {_counter = (prefs.getInt('counter') ?? 0) + 1;prefs.setInt('counter', _counter);});}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Shared Preferences Example'),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[Text('Button tapped $_counter time${_counter == 1 ? '' : 's'}.',style: TextStyle(fontSize: 20),),],),),floatingActionButton: FloatingActionButton(onPressed: _incrementCounter,tooltip: 'Increment',child: Icon(Icons.add),),);}
}

3.3 优缺点

优点:

  • 简单易用,不需要额外的依赖。
  • 跨应用共享数据,可以在应用之间共享用户偏好设置等信息。
  • 适用于存储少量的简单数据,如用户设置、配置信息等。

缺点:

  • 仅适用于存储简单的键值对数据,不适合存储复杂数据结构。
  • 不支持查询操作,只能通过键获取值。
  • 存储的数据量有限,不适合存储大量数据。

4. SQLite 数据库

4.1 安装与导入

在Flutter项目中使用SQLite数据库,需要添加sqflite依赖,并运行flutter pub get来安装依赖包。

dependencies:sqflite: ^2.0.0path_provider: ^2.0.0

安装完成后,在需要使用的Dart文件中导入sqflite库。

import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart';

4.2 使用示例

下面是一个简单的示例,演示了如何使用SQLite数据库在Flutter应用中创建表格、插入数据、查询数据等操作。

import 'package:flutter/material.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {Widget build(BuildContext context) {return MaterialApp(home: MyHomePage(),);}
}class MyHomePage extends StatefulWidget {_MyHomePageState createState() => _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {Database _database;void initState() {super.initState();_openDatabase();}_openDatabase() async {final Directory directory = await getApplicationDocumentsDirectory();final String path = join(directory.path, 'example.db');_database = await openDatabase(path, version: 1,onCreate: (Database db, int version) async {await db.execute('CREATE TABLE IF NOT EXISTS items(id INTEGER PRIMARY KEY, name TEXT)');});}_insertData() async {await _database.transaction((txn) async {int id = await txn.rawInsert('INSERT INTO items(name) VALUES("Item 1")');print('Inserted row id: $id');});}_queryData() async {List<Map> result = await _database.rawQuery('SELECT * FROM items');print(result);}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('SQLite Example'),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[ElevatedButton(onPressed: _insertData,child: Text('Insert Data'),),ElevatedButton(onPressed: _queryData,child: Text('Query Data'),),],),),);}
}

4.3 优缺点

优点:

  • 支持复杂的查询操作,适用于存储和管理大量结构化数据。
  • 数据库的持久化存储,适用于需要长期保存数据的应用场景。
  • 提供了事务管理,可以确保数据的一致性和完整性。

缺点:

  • 使用相对较复杂,需要熟悉SQL语法。
  • 需要引入第三方库(如sqflite)来实现数据库操作。
  • 对于简单的数据存储需求,使用SQLite可能显得过于复杂。

5. 文件存储

5.1 安装与导入

在Flutter项目中使用文件存储,无需额外安装依赖,因为文件操作相关的库已经包含在Flutter SDK中。

5.2 使用示例

下面是一个简单的示例,演示了如何使用文件存储在Flutter应用中读取和写入数据。

import 'dart:io';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {Widget build(BuildContext context) {return MaterialApp(home: MyHomePage(),);}
}class MyHomePage extends StatefulWidget {_MyHomePageState createState() => _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {String _filePath = '';void initState() {super.initState();_getFile();}Future<void> _getFile() async {Directory directory = await getApplicationDocumentsDirectory();_filePath = '${directory.path}/example.txt';}Future<void> _writeToFile() async {final File file = File(_filePath);await file.writeAsString('Hello, Flutter!');print('Data written to file.');}Future<void> _readFromFile() async {try {final File file = File(_filePath);String data = await file.readAsString();print('Data read from file: $data');} catch (e) {print('Error reading file: $e');}}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('File Storage Example'),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[ElevatedButton(onPressed: _writeToFile,child: Text('Write to File'),),ElevatedButton(onPressed: _readFromFile,child: Text('Read from File'),),],),),);}
}

5.3 优缺点

优点:

  • 灵活性高,可以存储各种类型的数据,如文本、图片等。
  • 不需要引入额外的依赖,文件操作相关的库已经包含在Flutter SDK中。
  • 适用于存储大文件或非结构化数据。

缺点:

  • 需要手动管理文件的读写操作,相对麻烦。
  • 不适合存储大量结构化数据,查询和操作相对复杂。
  • 文件存储的性能相对较低,不适合频繁的读写操作。

6. 第三方库

6.1 Hive数据库

Hive是一个轻量级的嵌入式数据库,专为Flutter开发而设计。它提供了快速、简单的数据存储方案,并具有高度的性能和低延迟。

优点:

  • 快速、轻量级,适用于移动设备上的资源受限环境。
  • 采用纯Dart实现,无需平台原生代码,易于集成和使用。
  • 支持类型安全的数据模型,可以轻松地将Dart对象序列化到数据库中。

缺点:

  • 相对较新,可能缺乏一些高级功能和成熟的社区支持。

6.2 ObjectBox

ObjectBox是一种高性能的对象数据库,专为移动设备和嵌入式系统而设计。它提供了快速、简单的数据存储解决方案,具有高度的性能和低延迟。

优点:

  • 高性能,适用于对速度要求较高的应用场景。
  • 支持多种平台,包括Android、iOS、Flutter等。
  • 提供了强大的查询语言和API,方便灵活的数据操作。

缺点:

  • 相对较新,可能缺乏一些成熟的社区支持和文档资源。

6.3 Moor数据库

Moor是一个强大的Flutter数据库库,提供了类型安全、可组合的数据库操作API。它允许使用Dart语言来定义数据库表和查询,而无需编写SQL语句。

优点:

  • 类型安全,可以在编译时捕获到数据库操作中的错误。
  • 支持使用Dart语言来定义数据库表和查询,简化了开发流程。
  • 提供了丰富的功能和灵活的API,适用于各种数据操作需求。

缺点:

  • 学习曲线较陡,需要一定的时间来熟悉其API和工作原理。
  • 相对较新,可能缺乏一些成熟的社区支持和文档资源。

7. 数据加密与安全

7.1 加密存储数据

在Flutter应用中,可以使用加密算法对敏感数据进行加密存储,以增加数据的安全性。常见的加密算法包括AES、RSA等。以下是一个简单的示例,演示了如何使用AES算法对数据进行加密和解密:

import 'package:flutter/material.dart';
import 'package:encrypt/encrypt.dart' as encrypt;void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {Widget build(BuildContext context) {return MaterialApp(home: MyHomePage(),);}
}class MyHomePage extends StatelessWidget {final String _plainText = 'Sensitive data';final String _secretKey = 'supersecretkey';String _encryptedText = '';String _decryptedText = '';MyHomePage() {final encrypter = encrypt.Encrypter(encrypt.AES(encrypt.Key.fromUtf8(_secretKey)));final encrypted = encrypter.encrypt(_plainText);_encryptedText = encrypted.base64;final decrypted = encrypter.decrypt(encrypted);_decryptedText = decrypted;}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Data Encryption Example'),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[Text('Encrypted Text: $_encryptedText'),Text('Decrypted Text: $_decryptedText'),],),),);}
}

7.2 安全存储敏感信息

对于敏感信息(如用户密码、密钥等),不建议直接存储在本地。可以使用Flutter提供的Secure Storage或第三方库(如flutter_secure_storage)来安全地存储敏感信息。这些库通常会使用系统提供的安全存储机制,如Android的Keystore、iOS的Keychain等,来保护数据免受未经授权的访问。

以下是一个示例,演示了如何使用flutter_secure_storage库来安全存储敏感信息:

import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {Widget build(BuildContext context) {return MaterialApp(home: MyHomePage(),);}
}class MyHomePage extends StatelessWidget {final FlutterSecureStorage _storage = FlutterSecureStorage();Future<void> _savePassword() async {await _storage.write(key: 'password', value: 'mysecretpassword');}Future<void> _readPassword() async {String password = await _storage.read(key: 'password');print('Password: $password');}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Secure Storage Example'),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[ElevatedButton(onPressed: _savePassword,child: Text('Save Password'),),ElevatedButton(onPressed: _readPassword,child: Text('Read Password'),),],),),);}
}

通过使用加密算法和安全存储机制,可以有效保护Flutter应用中的敏感信息,提高数据的安全性和可靠性。

8. 最佳实践与建议

8.1 选择合适的持久化方式

在选择数据持久化方式时,需要根据应用的需求和特点来决定。对于简单的键值对数据,可以选择使用Shared Preferences;对于结构化数据,可以考虑使用SQLite数据库或第三方库;对于大文件或非结构化数据,可以使用文件存储。综合考虑数据复杂度、性能要求、开发成本等因素,选择最适合的持久化方式。

8.2 管理数据结构与版本

在使用数据库进行数据持久化时,应注意管理数据结构和数据库版本。随着应用的迭代和更新,数据结构可能会发生变化,需要考虑如何处理旧版本数据的兼容性和迁移。可以使用数据库迁移工具或版本管理机制来管理数据结构和版本,确保数据的一致性和完整性。

8.3 处理异常与错误

在进行数据持久化操作时,可能会遇到各种异常和错误,如文件读写错误、数据库连接错误等。为了确保应用的稳定性和可靠性,应适当处理这些异常和错误情况,例如使用try-catch语句捕获异常并进行处理,或者使用错误处理机制进行错误报告和日志记录。同时,建议在进行数据操作前进行适当的检查和验证,以防止出现意外情况。

9. 总结

在Flutter应用中,数据持久化是确保数据在应用关闭或设备重启后仍然保持的重要机制之一。本文介绍了几种常用的数据持久化方式,包括Shared Preferences、SQLite数据库、文件存储以及使用第三方库,每种方式都有其适用的场景和优缺点。

Shared Preferences适用于存储少量简单的键值对数据,如用户偏好设置、配置信息等,使用简单方便。SQLite数据库适用于存储大量结构化数据,支持复杂的查询操作,提供了可靠的数据存储解决方案。文件存储适用于存储大文件或非结构化数据,灵活性高,但不适合存储大量结构化数据。

除了原生的数据持久化方式外,还可以使用第三方库如Hive数据库、ObjectBox、Moor数据库等,这些库提供了更多的功能和性能优化,可以根据具体需求选择最合适的库进行数据持久化操作。

在进行数据持久化时,需要注意选择合适的持久化方式,管理数据结构与版本,以及处理异常与错误。通过合理的数据持久化方案,可以提高应用的稳定性和可靠性,改善用户体验,从而更好地满足用户的需求。

附录:常见问题与解答

问题1:我应该使用哪种数据持久化方式?

答:选择数据持久化方式应该根据你的应用需求来决定。如果只需要存储少量的简单数据,可以使用Shared Preferences;如果需要存储大量的结构化数据并支持复杂的查询操作,可以选择SQLite数据库;如果需要存储大文件或非结构化数据,可以使用文件存储。另外,还可以考虑使用第三方库来满足特定需求。

问题2:如何处理数据结构的变化和数据库版本更新?

答:在进行数据结构变化和数据库版本更新时,可以使用数据库迁移工具或版本管理机制来管理数据结构和版本。这些工具可以帮助你确保数据的一致性和完整性,并提供了方便的方法来处理旧版本数据的兼容性和迁移。

问题3:如何确保数据的安全性?

答:为了确保数据的安全性,可以使用加密算法对敏感数据进行加密存储,同时可以使用安全存储机制(如Secure Storage)来安全地存储敏感信息。另外,还可以考虑实现访问控制和权限管理机制,限制数据的访问权限,确保数据只能被授权的用户访问。

问题4:如何处理数据持久化操作中的异常和错误?

答:在进行数据持久化操作时,可能会遇到各种异常和错误,如文件读写错误、数据库连接错误等。为了确保应用的稳定性和可靠性,可以适当处理这些异常和错误情况,例如使用try-catch语句捕获异常并进行处理,或者使用错误处理机制进行错误报告和日志记录。同时,建议在进行数据操作前进行适当的检查和验证,以防止出现意外情况。

问题5:我应该如何选择合适的第三方库进行数据持久化?

答:选择合适的第三方库应该考虑以下几个因素:

  • 功能需求:不同的库可能提供不同的功能和特性,需要根据你的应用需求来选择最合适的库。
  • 性能要求:一些库可能具有更高的性能和更低的延迟,适合对速度要求较高的应用场景。
  • 社区支持:选择一个活跃的社区支持良好的库,可以获得更好的技术支持和问题解答。
  • 文档资源:选择一个文档资源丰富、易于学习的库,可以加快开发速度和降低学习成本。

综合考虑以上因素,选择最合适的第三方库进行数据持久化操作。

问题6:我应该如何保护用户的隐私数据?

答:保护用户的隐私数据是非常重要的,可以考虑以下几个方面来保护用户的隐私数据:

  • 加密存储:使用加密算法对敏感数据进行加密存储,确保数据在存储和传输过程中不被窃取或篡改。
  • 安全传输:在数据传输过程中使用安全的传输协议(如HTTPS),确保数据在传输过程中不被窃取或窥探。
  • 访问控制:实现访问控制和权限管理机制,限制数据的访问权限,确保数据只能被授权的用户访问。
  • 合规性:遵守相关的隐私法律和法规,保护用户的隐私权益,不滥用用户的个人信息。

通过以上措施,可以有效保护用户的隐私数据,提高数据的安全性和可信度。

问题7:如何优化数据持久化操作的性能?

答:优化数据持久化操作的性能可以从以下几个方面入手:

  • 批量操作:尽量使用批量操作来减少数据库访问次数,提高数据操作的效率。
  • 索引优化:合理使用索引来加速数据查询操作,减少数据的扫描和匹配时间。
  • 异步操作:将耗时的数据操作放在异步任务中执行,避免阻塞UI线程,提高应用的响应速度。
  • 缓存机制:使用缓存机制来缓存常用的数据,减少数据读取和写入的次数,提高数据访问速度。

通过以上优化措施,可以有效提高数据持久化操作的性能,提升应用的用户体验和响应速度。

问题8:我应该如何备份和恢复应用中的数据?

答:备份和恢复应用中的数据是确保数据安全的重要措施之一。你可以考虑以下几种方法来备份和恢复应用中的数据:

  1. 数据库备份:对于使用SQLite等数据库存储数据的应用,可以定期进行数据库备份。你可以编写定期备份数据的任务,并将备份文件保存到安全的位置,以防止数据丢失。
  2. 云存储:将应用中的重要数据上传到云存储服务(如Google Drive、Dropbox等),可以实现数据的自动备份和恢复。你可以使用相关的云存储SDK来实现数据的上传和下载操作。
  3. 导出文件:为用户提供导出数据的功能,允许用户将数据导出为文件进行备份。你可以将数据导出为CSV、JSON等格式的文件,并提供下载或共享功能,方便用户进行数据备份和恢复。
  4. 数据同步:使用数据同步技术,将应用中的数据与服务器端或其他设备进行同步。这样可以确保数据的实时备份和同步,避免数据丢失和不一致。

通过以上方法,可以实现应用中数据的备份和恢复,保障数据的安全和完整性。同时,建议定期测试备份和恢复流程,确保备份数据的可用性和可靠性。

作者信息

作者 : 繁依Fanyi
CSDN: https://techfanyi.blog.csdn.net
掘金:https://juejin.cn/user/4154386571867191

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

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

相关文章

报告分享:2024 年小米汽车产业链分析及新品上市全景洞察报告

本文主要介绍了小米汽车在市场中的布局和优势&#xff0c;以及其面临的劣势与挑战。小米汽车凭借品牌、技术和成本三大核心优势&#xff0c;展现出强大的市场竞争力和品牌影响力&#xff0c;为消费者带来全新的汽车生活体验。文章还分析了小米汽车与小米生态链的协同效应&#…

CTF下加载CTFtraining题库以管理员身份导入 [HCTF 2018]WarmUp,之后以参赛者身份完成解题全过程

-------------------搭建CTFd------------------------------ 给大家介绍一个本地搭建比较好用的CTF比赛平台&#xff1a;CTFD。 CTFd是一个Capture The Flag框架&#xff0c;侧重于易用性和可定制性。它提供了运行CTF所需的一切&#xff0c;并且可以使用插件和主题轻松进行自…

如何在Java中,使用jackson实现json缩进美化

导入的maven依赖 <!--json--> <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.10.0</version> </dependency>示例代码 json要是String类型 public…

解决el-table设置固定高度后,展示不同列时表格高度变小bug

解决el-table设置固定高度后&#xff0c;展示不同列时表格高度变小bug 1、需求分析2、解决方案 1、需求分析 在el-table使用过程中&#xff0c;选择多个参数展示更多列时会出现高度变小问题究其原因可知是el-table列动态发生变化后&#xff0c;el-table__body-wrapper的高度变…

【NLP笔记】LLM应用之AI Agent LangChain实战

文章目录 AI Agent概述LangChain实战构建prompt模版LLM调用调用HuggingFace开源大模型&#xff08;在线&#xff09;调用HuggingFace开源大模型&#xff08;本地&#xff09;调用文心一言 ChainsSingle ChainSequential ChainSimple Sequential ChainComplex Sequential Chain …

Apache Pulsar源码解析之Lookup机制

引言 在学习Pulsar一段时间后&#xff0c;相信大家也或多或少听说Lookup这个词&#xff0c;今天就一起来深入剖析下Pulsar是怎么设计的它吧 Lookup是什么 在客户端跟服务端建立TCP连接前有些信息需要提前获取&#xff0c;这个获取方式就是Lookup机制。所获取的信息有以下几种…

java 解析c语言程序xml数据文件

GetMapping("/getHostMenuButtons")Operation(summary "创建试卷分类")PermitAll // PreAuthorize("ss.hasPermission(jd:index:query)")public JSONObject getJd() {//1、读取文件并转换为Document文档对象Document doc null;try {doc ne…

Spring Boot 学习(2)——HelloWorld

HelloWorld&#xff01;全宇宙码农的第一个&#xff08;行&#xff09;程序&#xff08;代码&#xff09;。 1、创建项目 打开idea&#xff0c;新建一个maven项目。 1&#xff09;选择项目sdk&#xff08;本例是1.8&#xff09; 2&#xff09;输入GroupId&#xff08;co…

Android JNI 调用第三方SO

最近一个项目使用了Go 编译了一个so库&#xff0c;但是这个so里面还需要使用第三方so库pdfium, 首先在Android工程把2个so库都放好 在jni中只能使用dlopen方式&#xff0c;其他的使用函数指针的方式来调用&#xff0c;和windows dll类似&#xff0c;不然虽然编译过了但是会崩溃…

日志服务 HarmonyOS NEXT 日志采集最佳实践

作者&#xff1a;高玉龙&#xff08;元泊&#xff09; 背景信息 随着数字化新时代的全面展开以及 5G 与物联网&#xff08;IoT&#xff09;技术的迅速普及&#xff0c;操作系统正面临前所未有的变革需求。在这个背景下&#xff0c;华为公司自主研发的鸿蒙操作系统&#xff08…

29-控制流(下):iam-apiserver服务核心功能实现讲解

我们再来看下 iam-apiserver 中的核心功能实现。 这些关键代码设计分为 3 类&#xff0c;分别是应用框架相关的特性、编程规范相关的特性和其他特性。 应用框架相关的特性 应用框架相关的特性包括三个&#xff0c;分别是优雅关停、健康检查和插件化加载中间件。 优雅关停 …

elementui 左侧或水平导航菜单栏与main区域联动

系列文章目录 一、elementui 导航菜单栏和Breadcrumb 面包屑关联 二、elementui 左侧导航菜单栏与main区域联动 三、elementui 中设置图片的高度并支持PC和手机自适应 四、elementui 实现一个固定位置的Pagination&#xff08;分页&#xff09;组件 文章目录 系列文章目录…