Flutter — O que é e como utilizar o banco de dados hive
Hive é um banco de dados do tipo chave-valor, leve e extremamente rápido feito em Dart puro. Essa é a descrição que você encontra no pub.dev e documentação do projeto.
Como o hive trabalha
O hive utiliza o conceito de caixas para armazenar os dados. Uma caixa pode ser comparada com uma tabela do SQL, mas as caixas não tem uma estrutura fixa e podem conter qualquer coisa.
Vantagens
O hive se apresenta como uma opção extremamente vantajosa em relação as outras opções de persistência de dados no Flutter, o conhecido shared_preferences e o SQLite por dois motivos:
O primeiro, atualmente o shared_preferences não funciona na plataforma web pois encapsula os nativos NSUserDefaults no iOS e SharedPreferences no Android.
E o segundo, o desempenho do hive é muito superior ao SQLite tanto em leitura quanto escrita. Em relação ao shared_preferences, os dois são equiparáveis em leitura, porém o hive ganha na escrita.
A diferença na escrita é bem grande, mas você não precisa acreditar nos resultados apresentados na documentação, você mesmo pode executar o benchmark.
Como executar o benchmark
Para fazer o benchmark primeiro faça um git clone do repositório:
git clone https://github.com/hivedb/hive_benchmark
Para executar o projeto você precisa do NDK. A instalação é bem simples e pode ser feita através do Android Studio.
Vá em SDK Manager, na aba SDK Tools e selecione:
LLDB
NDK
CMake
Após isso você precisa da variável de ambiente ANDROID_NDK_HOME.
Linux
Se você usa Linux e seguiu o meu artigo de instalação do Flutter você sabe que precisa ir até o diretório home e editar o arquivo .bashrc:
cd $home
sudo nano .bashrc
E adicione no final do arquivo a linha:
export ANDROID_NDK_HOME=/home/vinicius/Android/Sdk/ndk/versao
No meu caso fica assim:
export ANDROID_NDK_HOME=/home/vinicius/Android/Sdk/ndk/20.0.5594570
Aperte CTRL-X para sair, Y para salvar e ENTER para fechar.
Depois, ainda no diretório home execute a linha:
source .bashrc
Windows 10
Se você utiliza o Windows 10 vá até Painel de Controle > Sistema e Segurança > Sistema, depois clique em Configurações avançadas do sistema.
Depois clique em Variáveis de Ambiente. Clique duas vezes em Path, clique em novo e insira o caminho da pasta do NDK e clique em Ok.
Depois de configurar a variável de ambiente você pode abrir o projeto no Android Studio e ir em File > Project Structure pra confirmar se a localização do NDK está correta no projeto.
Depois disso você já conseguirá executar o benchmark.
Meus resultados
No projeto do benchmark nós temos as mesmas opções de Read, Write e adicionalmente a Delete.
Também temos cinco comparações:
Hive
Hive Lazy
SQLite
Shared_Preferences
SQLite com moor_ffi
Aqui estão os resultados que eu tive utilizando um aparelho muito mais fraco que o usado no benchmark da documentação:
A diferença entre o hive e SQLite parece ser menor nos meus resultados, porém devemos lembrar que o tempo no aparelho usado é muito maior, chegando a 53832ms, enquando no benchmark da documentação o tempo máximo é 14760ms.
Como utilizar
Agora que já ficou comprovado o desempenho do hive vamos conferir como utilizá-lo.
Crie um projeto
Primeiro crie um projeto padrão do flutter.
Adicionando hive no projeto
Em pubspec.yaml adicione:
dependencies:
hive: ^1.0.0
path_provider: ^1.2.0dev_dependencies:
hive_generator: ^0.5.1
build_runner: ^1.7.1
Nós precisamos além do hive, incluir o path_provider para podermos pegar o diretório atual do aplicativo.
Agora apague todo o conteúdo do arquivo main.dart e inclua uma estrutura básica de um StatelessWidget:
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart';void main() => runApp(MaterialApp(home: MyApp()));class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Exemplo hive',
home: Container()
);
}
}
Agora vamos criar uma função para pegar os dados de uma caixa:
Future _abrirCaixa() async {
var dir = await getApplicationDocumentsDirectory();
Hive.init(dir.path);
return await Hive.openBox('minhaCaixa');
}
Como essa operação envolve a leitura de um arquivo você precisa utilizar o modificador async e usar o await.
Se você estiver utilizando o flutter web você não precisa do path_provider no projeto e também não precisa utilizar o Hive.init().
Nós vamos utilizar um FutureBuilder pra criar a estrutura do nosso projeto. No future será utilizado a função _abrirCaixa, se algo der errado nós vamos exibir um Center com essa mensagem, se estiver tudo ok retornaremos nossa página principal.
Altere a classe MyApp:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Exemplo hive',
home: FutureBuilder(
future: _abrirCaixa(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.error != null) {
return Scaffold(
body: Center(
child: Text('Algo deu errado :('),
),
);
} else {
return MinhaPagina();
}
} else {
return CircularProgressIndicator();
}
},
),
);
}
}
Agora nós vamos criar o widget MinhaPagina:
class MinhaPagina extends StatefulWidget {
@override
_MinhaPaginaState createState() => _MinhaPaginaState();
}class _MinhaPaginaState extends State<MinhaPagina> {
Box _caixa;
@override
void initState() {
_caixa = Hive.box('minhaCaixa');
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Exemplo hive'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Reinicie o aplicativo para testar'),
SizedBox(height: 8),
Text('You have pushed the button this many times:'),
WatchBoxBuilder(
box: _caixa,
builder: (context, box) {
return Text(
box.get('contador', defaultValue: 0).toString(),
style: Theme.of(context).textTheme.display1,
);
},
),],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_caixa.put(
'contador',
_caixa.get('contador', defaultValue: 0) + 1);
},
tooltip: 'Aumentar',
child: Icon(Icons.add),
),);
}}
Para exibir o valor do contador nós vamos utilizar um widget criado pelo desenvolvedor do hive. O WatchBoxBuilder se recria toda vez que o valor de uma caixa ou de uma chave específica muda.
Para usar vamos inserir no pubspec.yaml:
dependencies:
hive: ^1.0.0
path_provider: ^1.2.0
hive_flutter: anydev_dependencies:
hive_generator: ^0.5.1
build_runner: ^1.7.1
Depois adicione o import em main.dart:
import 'package:hive_flutter/hive_flutter.dart';
Sempre que o aplicativo é iniciado ele lê o valor de contador e exibe na tela. Sempre que o botão é pressionado o valor também é atualizado na caixa, o que faz com que o WatchBoxBuilder seja atualizado.
Esse é um exemplo bem simples porém já consegue mostrar um pouco de como utilizar o hive. Ele aparenta ser uma ótima opção de persistência no flutter, com um desempenho excelente e sem dependências nativas.
Esse projeto foi baseado na documentação do hive e pode ser encontrado no Github.