Mengakses Database SQLite dengan Flutter

sheli indriani 5 Agustus 2019

Mengakses Database SQLite dengan Flutter

Flutter dapat dengan mudah dipelajari karna menggunakan bahasa pemrograman Dart yang pastinya terasa familiar jika sudah terbiasa menggunakan bahasa pemrograman Java atau Javascript. Selain itu Flutter juga menyertakan kerangka reactive-functional, mesin render 2D, widget siap pakai, dan tools untuk pengembangan.

Flutter dapat berinteraksi dengan database lokal yang berada pada suatu perangkat. Database ini dibuat dengan menggunakan SQLite. Pustaka Sqflite digunakan untuk mengakses database pada SQLite di aplikasi flutter.

1. Apa itu SQLite ?

SQLite merupakan salah satu jenis RDBMS yang memiliki ukuran pustaka yang relatif kecil, ditulis menggunakan bahasa C. SQLite ini merupakan proyek yang bersifat public domain.

2. Langkah-langkah Membuat Akses Database

Buat folder project awal beri nama flutterdb, lalu ketikkan perintah dibawah ini untuk membuat project baru:

flutter create sqlitedatabases
Image

Masuk terlebih dahulu ke folder lib dengan perintah dibawah ini:

$ cd lib

Buat folder baru dengan nama helpers, models, dan ui didalam folder library tersebut.

$ mkdir helpers ui models
Image

Silahkan Anda cek directory yang sudah dibuat

$ ls -la
Image

Setelah itu silahkan Anda buat lagi file Dart nya didalam masing-masing folder yang sudah Anda buat yaitu helper dbhelper.dart, models contact.dart, dan ui home.dart serta entryform.dart. Masukkan perintah seperti di bawah ini:

$ touch helpers/dbhelper.dart
$ touch models/contact.dart
$ touch ui/home.dart
$ touch ui/entryform.dart
Image

Anda dapat melihat struktur folder didalam project nya akan terlihat seperti gambar dibawah ini:

Image

Setelah itu buka folder project yang sudah dibuat. Konfigurasi pada file pubspec.yml source code-nya seperti ini:

dependencies: flutter: sdk: flutter sqflite: any path_provider: any
Image

Langkah berikutnya silahkan buka file main.dart, masukkan source code dibawah, kode tersebut akan digunakan pada saat aplikasi pertama kali dibuka.

//kode utama Aplikasi tampilan awal
import 'package:flutter/material.dart';
import 'package:cobalagi/ui/home.dart';
//package letak folder Anda
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
    //judul
      title: 'Tambahkan Daftar',
      theme: ThemeData(
        primarySwatch: Colors.red,
      ),
      home: Home(),
    );
  }
}

Pada kelas home.dart digunakan untuk membuat tampilan layar aplikasi.

import 'package:flutter/material.dart';
//letak package folder flutter
import 'package:cobalagi/ui/entryform.dart';
import 'package:cobalagi/models/contact.dart';
import 'package:cobalagi/helpers/dbhelper.dart';
import 'package:sqflite/sqflite.dart';
//untuk memanggil fungsi yg terdapat di daftar pustaka sqflite
import 'dart:async';
//pendukung program asinkron

class Home extends StatefulWidget {
  @override
  HomeState createState() => HomeState();
}

class HomeState extends State<Home> {
  
  DbHelper dbHelper = DbHelper();
  int count = 0;
  List<Contact> contactList;   

  @override
  Widget build(BuildContext context) {
    if (contactList == null) {
      contactList = List<Contact>();
    }

    return Scaffold(
      appBar: AppBar(
        title: Text('Daftar Data-Data'),
      ),
      body: createListView(),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        tooltip: 'Tambah Data',
        onPressed: () async {
          var contact = await navigateToEntryForm(context, null);
          if (contact != null) addContact(contact);
        },
      ),
    );
  }

  Future<Contact> navigateToEntryForm(BuildContext context, Contact contact) async {
    var result = await Navigator.push(
      context,
      MaterialPageRoute(
        builder: (BuildContext context) {
          return EntryForm(contact);
        }
      ) 
    );
    return result;
  }

  ListView createListView() {
    TextStyle textStyle = Theme.of(context).textTheme.subhead;
    return ListView.builder(
      itemCount: count,
      itemBuilder: (BuildContext context, int index) {
        return Card(
          color: Colors.white,
          elevation: 2.0,
          child: ListTile(
            leading: CircleAvatar(
              backgroundColor: Colors.red,
              child: Icon(Icons.people),
            ),
            title: Text(this.contactList[index].name, style: textStyle,),
            subtitle: Text(this.contactList[index].phone),
            trailing: GestureDetector(
              child: Icon(Icons.delete),
              onTap: () {
                deleteContact(contactList[index]);
              },   
            ),
            onTap: () async {
              var contact = await navigateToEntryForm(context, this.contactList[index]);
              if (contact != null) editContact(contact);
            },
          ),
        );
      },
    );
  }
  //buat contact
  void addContact(Contact object) async {
    int result = await dbHelper.insert(object);
    if (result > 0) {
      updateListView();
    }
  }
	//edit contact
  void editContact(Contact object) async {
    int result = await dbHelper.update(object);
    if (result > 0) {
      updateListView();
    }
  }
	//delete contact
  void deleteContact(Contact object) async {
    int result = await dbHelper.delete(object.id);
    if (result > 0) {
      updateListView();
    }
  }
	//update contact
  void updateListView() {
    final Future<Database> dbFuture = dbHelper.initDb();
    dbFuture.then((database) {
      Future<List<Contact>> contactListFuture = dbHelper.getContactList();
      contactListFuture.then((contactList) {
        setState(() {
          this.contactList = contactList;
          this.count = contactList.length;
        });
      });
    });
  }

}

Kemudian kelas entryform.dart digunakan untuk mengubah data atau menambah layar baru kedalam database.

import 'package:flutter/material.dart';
import 'package:cobalagi/models/contact.dart';

class EntryForm extends StatefulWidget {
  final Contact contact;

  EntryForm(this.contact);

  @override
  EntryFormState createState() => EntryFormState(this.contact);
}
//class controller
class EntryFormState extends State<EntryForm> {
  Contact contact;
  
  EntryFormState(this.contact);

  TextEditingController nameController = TextEditingController();
  TextEditingController phoneController = TextEditingController();  
  
  @override
  Widget build(BuildContext context) {
    //kondisi
    if (contact != null) {
      nameController.text = contact.name;
      phoneController.text = contact.phone;
    }
    //rubah
    return Scaffold(
      appBar: AppBar(
        title: contact == null ? Text('Tambah') : Text('Rubah'),
        leading: Icon(Icons.keyboard_arrow_left),
      ),
      body: Padding(
        padding: EdgeInsets.only(top: 15.0, left:10.0, right:10.0),
        child: ListView(
          children: <Widget> [
            // nama
            Padding (
              padding: EdgeInsets.only(top:20.0, bottom:20.0),
              child: TextField(
                controller: nameController,
                keyboardType: TextInputType.text,
                decoration: InputDecoration(
                  labelText: 'Nama Lengkap',             
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(5.0),
                  ),
                ),
                onChanged: (value) {                  
                  //                                                    
                },
              ),
            ),

            // telepon
            Padding (
              padding: EdgeInsets.only(top:20.0, bottom:20.0),
              child: TextField(
                controller: phoneController,
                keyboardType: TextInputType.phone,
                decoration: InputDecoration(
                  labelText: 'Telepon',                
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(5.0),
                  ),
                ),
                onChanged: (value) {                  
                  //
                },
              ),
            ),

            // tombol button
            Padding (
              padding: EdgeInsets.only(top:20.0, bottom:20.0),
              child: Row(
                children: <Widget> [
                  // tombol simpan
                  Expanded(
                    child: RaisedButton(
                      color: Theme.of(context).primaryColorDark,
                      textColor: Theme.of(context).primaryColorLight,
                      child: Text(
                        'Save',
                        textScaleFactor: 1.5,
                      ),
                      onPressed: () {
                        if (contact == null) {
                          // tambah data
                          contact = Contact(nameController.text, phoneController.text);
                        } else {
                          // ubah data
                          contact.name = nameController.text;
                          contact.phone = phoneController.text;
                        }
                        // kembali ke layar sebelumnya dengan membawa objek contact
                        Navigator.pop(context, contact);
                      },
                    ),
                  ),
                  Container(width: 5.0,),
                  // tombol batal
                  Expanded(
                    child: RaisedButton(
                      color: Theme.of(context).primaryColorDark,
                      textColor: Theme.of(context).primaryColorLight,
                      child: Text(
                        'Cancel',
                        textScaleFactor: 1.5,
                      ),
                      onPressed: () {
                        Navigator.pop(context);
                      },
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      )
    );
  }
}

Kemudian masukkan juga source code dibawah ini kedalam filecontact.dart project Anda.

class Contact {
  int _id;
  String _name;
  String _phone;

  // konstruktor versi 1
  Contact(this._name, this._phone);

  // konstruktor versi 2: konversi dari Map ke Contact
  Contact.fromMap(Map<String, dynamic> map) {
    this._id = map['id'];
    this._name = map['name'];
    this._phone = map['phone'];
  }
  //getter dan setter (mengambil dan mengisi data kedalam object)
  // getter
  int get id => _id;
  String get name => _name;
  String get phone => _phone;

  // setter  
  set name(String value) {
    _name = value;
  }

  set phone(String value) {
    _phone = value;
  }

  // konversi dari Contact ke Map
  Map<String, dynamic> toMap() {
    Map<String, dynamic> map = Map<String, dynamic>();
    map['id'] = this._id;
    map['name'] = name;
    map['phone'] = phone;
    return map;
  }  

}

Kelas dbhelper.dart digunakan sebagai pendukung aplikasi yang akan dibuat, kali ini kelas helper digunakan untuk menyimpan atau membuat database, tabel, dan melakukan CRUD (create,read,update,delete). Helper akan menggunakan kelas model yang telah dibuat pada langkah awal.

import 'package:sqflite/sqflite.dart';
import 'dart:async';
//mendukug pemrograman asinkron
import 'dart:io';
//bekerja pada file dan directory
import 'package:path_provider/path_provider.dart';
import 'package:cobalagi/models/contact.dart';
//pubspec.yml


//kelass Dbhelper
class DbHelper {
  static DbHelper _dbHelper;
  static Database _database;  

  DbHelper._createObject();

  factory DbHelper() {
    if (_dbHelper == null) {
      _dbHelper = DbHelper._createObject();
    }
    return _dbHelper;
  }

  Future<Database> initDb() async {
  
  //untuk menentukan nama database dan lokasi yg dibuat
    Directory directory = await getApplicationDocumentsDirectory();
    String path = directory.path + 'contact.db';
    
   //create, read databases
    var todoDatabase = openDatabase(path, version: 1, onCreate: _createDb);
    
    //mengembalikan nilai object sebagai hasil dari fungsinya
    return todoDatabase;
  }

	//buat tabel baru dengan nama contact
  void _createDb(Database db, int version) async {
    await db.execute('''
      CREATE TABLE contact (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT,
        phone TEXT
      )
    ''');
  }

  Future<Database> get database async {
    if (_database == null) {
      _database = await initDb();
    }
    return _database;
  }

  Future<List<Map<String, dynamic>>> select() async {
    Database db = await this.database;
    var mapList = await db.query('contact', orderBy: 'name');
    return mapList;
  }

//create databases
  Future<int> insert(Contact object) async {
    Database db = await this.database;
    int count = await db.insert('contact', object.toMap());
    return count;
  }
//update databases
  Future<int> update(Contact object) async {
    Database db = await this.database;
    int count = await db.update('contact', object.toMap(), 
                                where: 'id=?',
                                whereArgs: [object.id]);
    return count;
  }

//delete databases
  Future<int> delete(int id) async {
    Database db = await this.database;
    int count = await db.delete('contact', 
                                where: 'id=?', 
                                whereArgs: [id]);
    return count;
  }
  
  Future<List<Contact>> getContactList() async {
    var contactMapList = await select();
    int count = contactMapList.length;
    List<Contact> contactList = List<Contact>();
    for (int i=0; i<count; i++) {
      contactList.add(Contact.fromMap(contactMapList[i]));
    }
    return contactList;
  }

}

Tampilan awal aplikasi akan terlihat seperti gambar di bawah ini:

Image

Sedangkan tampilan untuk menambahkan data akan terlihat seperti ini:

Image

Setelah ditambah maka akan disimpan pada form dibawah ini, pada tampilan ini pengguna dapat melakukan aksi baik untuk menambahkan data, hapus ataupun untuk merubah data.

Image

Tampilan untuk merubah data pada daftar form akan terlihat seperti gambar dibawah ini:

Image

Selamat mencoba.

Sumber :

Flutter

teknojurnal