--- title: 'Flutter Database(Hive)' tags: Flutter disqus: hackmd --- <style> .red { color: red; } .blue { color: blue; } </style> <font size="6">Flutter Database(Hive)</font> **目錄:** [TOC] --- Flutter提供了許多本地數據持久化選項供開發者選擇。shared_preferences是一個用於本地存儲小型鍵值對的好包,而sqflite,Flutter的SQLite包,當你處理強關係型數據,需要你在數據庫中處理複雜的關係時,是一個不錯的選擇。 但是如果你想要一個快速安全的本地數據庫,沒有本地的依賴性,也能在Flutter web上運行,那麼Hive是一個相當不錯的選擇。 在這篇文章中,在我們使用Flutter構建一個簡單的應用程序之前,你將學習如何開始使用Hive。我們還將研究一個允許你在Hive中處理簡單關係數據的概念。 ## 為什麼是Hive? Hive是一個輕量級和快速的鍵值數據庫解決方案,它是跨平台的(在移動、桌面和網絡上運行),並且是用純Dart編寫的。這使得它比<span class='red'>不支持Flutter網絡的sqflite</span>更有優勢--Hive沒有原生的依賴性,所以它可以在網絡上無縫運行。 順帶一題Hive是使用<span class='blue'>NoSQL</span>數據庫 下面是一張Hive與其他類似數據庫解決方案的基準圖。 ![](https://hackmd.io/_uploads/SkXWyZ11T.png) 這是一個在安卓Q系統的Oneplus 6T設備上進行的1000次讀寫操作的基準 ## 開始使用Hive ```shell= flutter pub add hive flutter pub add hive_flutter ``` ## 了解盒子 Hive使用"盒子"的概念來存儲數據庫中的數據。盒子類似於SQL數據庫中的表,只是盒子缺乏嚴格的結構。這意味著盒子很靈活,只能處理數據之間的簡單關係。 在本教程中,我們將只介紹典型的Hive盒子,但值得一提的是,你也可以創建[懶惰的盒子](https://docs.hivedb.dev/#/advanced/lazy_box)和[加密的盒子](https://docs.hivedb.dev/#/advanced/encrypted_box)。 ## 初始化Hive 在進入數據庫的CRUD操作之前,你必須初始化Hive並打開一個用於存儲數據的盒子。 Hive應該在我們加載任何盒子之前被初始化,所以最好在你的Flutter應用程序的main()函數中初始化它,以避免任何錯誤。 :::warning 如果你在一個非Flutter的純Dart應用程序中使用Hive,你應該使用Hive.init()來初始化Hive。 ::: ```dart= void main() async { // Required for async calls in `main` WidgetsFlutterBinding.ensureInitialized(); // Initialize hive await Hive.initFlutter(); runApp(const MyApp()); } ``` 使主函數異步化,並使用await來初始化Hive。 現在,你必須要打開一個Hive盒子。 :::warning 如果你打算在你的項目中使用盒子,你應該在使用一個盒子之前打開它。 ::: 在這個應用程序中,我們將使用一個盒子,在Hive完成初始化後再打開。 ```dart= void main() async { // Required for async calls in `main` WidgetsFlutterBinding.ensureInitialized(); // Initialize hive await Hive.initFlutter(); // Open the peopleBox await Hive.openBox('peopleBox'); runApp(const MyApp()); } ``` ## 執行CRUD操作 ```dart= class InfoScreen extends StatefulWidget { @override _InfoScreenState createState() => _InfoScreenState(); } class _InfoScreenState extends State<InfoScreen> { late final Box box; @override void initState() { super.initState(); // Get reference to an already opened box box = Hive.box('peopleBox'); } @override void dispose() { // Closes all Hive boxes Hive.close(); super.dispose(); } @override Widget build(BuildContext context) { return Container(); } } ``` 首先,我們在initState()方法裡面檢索一個對我們先前打開的盒子的引用。你應該在使用完之後,在關閉應用程序之前總是關閉已打開的盒子。 由於我們目前只需要這個部件裡面的盒子,我們可以在這個類的dispose()方法裡面關閉這個盒子。 創建方法來執行CRUD操作。 ### 存儲數據 如果你需要存儲數據,你可以使用對Hive盒子的引用並對其調用put()。 這個方法接受一個鍵值對。 ```dart= // Add info to people box _addInfo() async { // Storing key-value pair box.put('name', 'John'); box.put('country', 'Italy'); print('Info added to box!'); } ``` Hive也支持整數鍵,所以你可以使用自動遞增的鍵。 如果你要存儲多個值(有點類似於列表),並想通過它們的索引進行檢索,你可以像這樣存儲。 ```dart= box.add('Linda'); // index 0, key 0 box.add('Dan'); // index 1, key 1 ``` ### 檢索數據 要讀取數據,你可以使用盒子對像上的get()方法。 你只需要提供key來檢索它的值。 ```dart= // Read info from people box _getInfo() { var name = box.get('name'); var country = box.get('country'); print('Info retrieved from box: $name ($country)'); } ``` 如果你使用的是自動遞增的值,你可以使用索引來讀取。 ```dart= box.getAt(0); // retrieves the value with index 0 box.getAt(1); // retrieves the value with index 1 ``` ### 更新數據 要更新一個特定鍵的數據,你可以使用你最初用來存儲值的相同的put()方法。 這將用新提供的值更新存在於該鍵的值。 ```dart= // Update info of people box _updateInfo() { box.put('name', 'Mike'); box.put('country', 'United States'); print('Info updated in box!'); } ``` 如果你使用的是自動遞增的值,你可以使用putAt()方法來更新存在於特定索引的值。 ```dart= box.putAt(0, 'Jenifer'); ``` ### 刪除數據 對於刪除數據,你可以通過提供鍵來使用delete()方法。 這將刪除存在於這些特定鍵的值。 如果你試圖使用這些鍵調用get()方法,它將返回空值。 ```dart= // Delete info from people box _deleteInfo() { box.delete('name'); box.delete('country'); print('Info deleted from box!'); } ``` 如果你使用的是自動遞增的值,你可以通過提供索引來使用deleteAt()方法。 ```dart= box.deleteAt(0); ``` ## 使用TypeAdapter的自定義對象 :::danger 未完成 ::: ## 查看 點擊F12查看 ![](https://hackmd.io/_uploads/HJRSarxyp.png) 檔案位置 ```shell= ~/Library/Application\ Support/Google/Chrome/Default ```