Anda di halaman 1dari 22

Modul 11 – SQLite

Slamet Budi Santoso

Banyak data dengan struktur serupa akan lebih mudah jika disimpan dalam basis data. Android menggunakan
SQLite untuk penyimpanan data lokal. Modul ini berasumsi bahwa anda telah terbiasa dengan basis data SQL
secara umum.
Pada modul ini akan dikenalkan bagaimana dasar-dasar interaksi dengan SQLite. Meskipun penangangan SQLite
ini dianggap rumit menurut situs resmi tentang Menyimpan data menggunakan SQLite namun perlu dipelajari
sebagai perkenalan awal dan dasar.

Desain User Interface


Pengenalan SQLite ini menggunakan studi kasus membuat aplikasi “Catatan” dengan tampilan kurang lebih
seperti berikut.

1
Rancangan Database & Tabel
Tabel yang digunakan dalam aplikasi ini hanya satu dan masih sangat sederhana dengan struktur sebagai berikut.

Aset Ikon
Aset gambar/ikon untuk keperluan modul ini bisa diunduh dari tautan ini. Ekstrak dan silahkan pilih “paket” yang
akan digunakan. Atau, anda bisa gunakan gambar lain yang lebih sesuai. Gambar pada modul ini berukuran 512 x
512 pixel dan diperoleh dari Flaticon.com sehingga harus dicantumkan sumber gambarnya.
Terdapat 3 (tiga) file dalam setiap “paket” dengan penamaan seperti berikut. File ikon.png dan ikon2.png adalah
file gambar berformat PNG dan berukuran 512 x 512 pixel. File sumber_ikon.txt adalah file teks yang berisi tautan
sumber dari gambar yang ada di folder tersebut.
Jika anda menggunakan file gambar dengan nama dan ukuran yang berbeda, silahkan disesuaikan sendiri.

Sangkalan: Gambar yang diperoleh secara cuma-cuma sebaiknya disertai dengan keterangan sumber yang jelas
dan menjadi tanggung jawab penggunanya. Penulis modul ini tidak bertanggung jawab terhadap pelanggaran
hak cipta yang dilakukan oleh pembaca.

Membuat Project
Selanjutnya membuat project di Android Studio. Pilih Start a new Android Studio project dan pilih Basic Activity
dan klik Next.

2
Basic Activity digunakan untuk mempercepat proses pembuatan aplikasi karena telah dilengkapi dengan
beberapa fitur dasar seperti menu dan Floating Action Button.
Isikan informasi dasar dari aplikasi yang akan dibuat, mulai dari Name, Package name, Language, dan Minimum
SDK yang ditargetkan. Modul ini menargetkan Minimum SDK pada Android 4.0 (IceCreamSandwich). Anda boleh
menargetkan versi Android yang lebih tinggi. Klik Finish untuk melanjutkan proses pembuatan project.

Tambahkan Aset Gambar


Setelah project selesai di-build, berikutnya adalah menambahkan aset gambar ke dalam folder drawable.
Caranya adalah dengan salin file ikon.png dan ikon2.png lalu paste-kan ke folder drawable.

3
Tambahkan Dependensi
Berikutnya, tambahkan library RecyclerView seperti pada materi sebelumnya, File > Project Setting >
Dependencies. Pada bagian ini anda harus terhubung ke internet agar proses Search dapat berlangsung. Pilih
pustaka seperti pada gambar berikut. Anda boleh menggunakan versi terbaru (1.2.0-alpha02 saat modul ini
ditulis). Modul ini menggunakan versi stabil 1.1.0.
Catatan: pada versi baru biasanya terdapat fitur baru atau (mungkin) perubahan fitur/sintaks. Silahkan
disesuaikan jika anda menggunakan versi yang berbeda dengan membaca lebih lanjut dari dokumentasi resminya.
Jika sudah dipilih, klik OK dan OK lagi agar gradle melakukan sync.

build.gradle (Module: app)


Perubahan pada file ini adalah tambahan baris implementation berikut. Anda dapat juga menambahkan baris ini
langsung ke dalam file build.gradle (Module: app) dan melakukan sync gradle.
dependencies {
...
implementation 'androidx.recyclerview:recyclerview:1.1.0'

Membuat User Interface


Selanjutnya adalah membuat desain user interface (UI) dari aplikasi. Android Studio menggunakan XML untuk
membuat tampilan UI.
Catatan: jika dijumpai error terkait resource seperti strings, dimens, colors, atau lainnya, anda bisa merujuk
pada bagian Edit File Pelengkap di akhir modul ini.

Layout: catatan_baris.xml
Layout pertama adalah untuk menampilkan baris-baris catatan. Klik-kanan pada folder layout, pilih New >
Layout Resource File dan atur seperti tampak pada gambar berikut.

4
Dan lengkapi skripnya seperti berikut.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
android:paddingBottom="@dimen/padding10"
android:paddingTop="@dimen/padding10"
android:paddingLeft="@dimen/padding16"
android:paddingRight="@dimen/padding16">

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tvTimestamp"
android:textColor="@color/timestampColor"
android:textSize="@dimen/timestampSize" />

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tvCatatan"
android:layout_below="@id/tvTimestamp"
android:textColor="@color/catatanColor"
android:textSize="@dimen/catatanSize" />

<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_below="@id/tvCatatan"
android:layout_marginTop="@dimen/padding10"
android:background="@android:color/darker_gray" />

</RelativeLayout>

Layout: content_main.xml
File content_main.xml adalah file bawaan ketika kita memilih templat Basic Activity. File ini akan berisi
RecyclerView yang menampung tampilan dari file catatan_baris.xml. File ini juga mengatur tampilan saat
“tidak ada catatan” dalam tabel basis data.
Buka dan edit skrip di dalamnya hingga seperti berikut.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout

5
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
tools:showIn="@layout/activity_main">

<androidx.recyclerview.widget.RecyclerView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/rvCatatan" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="@+id/catatanKosong">

<ImageView
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginTop="300dp"
android:layout_gravity="center_horizontal"
android:alpha="0.2"
android:src="@drawable/ikon2"
android:contentDescription="@string/ivCatatanKosong" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:fontFamily="sans-serif-light"
android:text="@string/catatanKosongText"
android:textColor="@color/catatanKosongColor"
android:textSize="@dimen/catatanKosongSize" />

</LinearLayout>
</RelativeLayout>

Layout: catatan_dialog.xml
Berikutnya adalah membuat layout untuk membuat atau mengedit catatan. Buat file layout baru dengan langkah
seperti sebelumnya, klik-kanan folder layout, pilih New > Layout Resource File dan atur seperti pada gambar
berikut. Klik OK.

6
Dan lengkapi skripnya seperti berikut.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingRight="@dimen/padding16"
android:paddingLeft="@dimen/padding16"
android:paddingTop="@dimen/padding16">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tvJudulDialog"
android:layout_marginBottom="@dimen/padding10"
android:fontFamily="sans-serif-medium"
android:lineSpacingExtra="8sp"
android:text="@string/catatanBaruLabel"
android:textColor="@color/colorPrimary"
android:textSize="@dimen/judulCatatanSize"
android:textStyle="normal" />

<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/etCatatan"
android:background="@android:color/transparent"
android:gravity="top"
android:hint="@string/hintCatatan"
android:inputType="textCapSentences|textMultiLine"
android:lines="10"
android:textColorHint="@color/hintCatatanColor"
android:textSize="@dimen/etCatatanSize" />
</LinearLayout>

Layout: activity_main.xml
File ini merupakan layout yang akan diterapkan pada MainActivity.java. File ini juga me-load beberapa layout lain
seperti: AppBarLayout, content_main, dan FloatingActionButton.
Buka dan edit skripnya hingga seperti berikut.
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">

<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />

</com.google.android.material.appbar.AppBarLayout>

<include layout="@layout/content_main" />

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
android:src="@drawable/ic_add_white_24dp" />

7
</androidx.coordinatorlayout.widget.CoordinatorLayout>

Pada skrip di atas, ikon untuk FAB juga diubah dengan file ic_add_white_24dp. Cara membuatnya dijelaskan
berikut ini.

Membuat Ikon
Klik-kanan pada folder drawable dan pilih New > Vector Asset. Pada jendela Asset Studio yang ditampilkan, edit
nama ikonnya, bebas aja. Pada contoh ini: ic_add_white_24dp.

Kemudian klik pada kotak Clip Art dan pilih gambarnya seperti tampak pada gambar berikut. Klik OK jika sudah
memilih.

8
Setelah kembali ke jendela Asset Studio, lanjutkan dengan klik pada kotak Color, pilih warna atau ketikkan kode
warna seperti pada gambar berikut. Anda boleh menggunakan warna apa saja, yang penting kontras dengan
warna FAB-nya. Contoh disini menggunakan warna putih (#FFF).
Klik Choose jika sudah menentukan warna yang akan digunakan.

Selanjutnya klik Next dan Finish.

Dan bisa dilihat pada folder drawable terdapat tambahan file baru.

9
Membuat Aplikasi
Setelah layout selesai dibuat, selanjutnya adalah membuat file-file program yang diperlukan. Berikut ini adalah
langkah-langkah yang disarankan. Sebelum dilanjutkan, penting untuk dipahami bahwa penulisan skrip sebaiknya
dituntaskan terlebih dahulu sebelum melakukan uji coba.
Jika dijumpai error saat menuliskan skrip, anda bisa menggunakan kombinasi tombol alt+enter untuk
menampilkan alternatif solusinya. Disarankan untuk melanjutkan penulisan seluruh skrip terlebih dahulu.

Model: Catatan.java
File pertama yang dibuat adalah Catatan.java. File ini merupakan model data yang isinya berupa struktur data,
struktur tabel, beserta consturctor dan set-getter-nya. Klik-kanan pada package utama, kemudian pilih New >
Java Class dan atur seperti pada gambar berikut.

Kemudian lengkapi skripnya seperti berikut.


public class Catatan {
public static final String NAMA_TABEL = "catatan";
public static final String KOLOM_ID = "id";
public static final String KOLOM_CATATAN = "catatan";
public static final String KOLOM_TIMESTAMP = "timestamp";

//query CREATE TABLE


public static final String CREATE_TABLE = "CREATE TABLE " + NAMA_TABEL
+ "(" + KOLOM_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ KOLOM_CATATAN + " TEXT, "
+ KOLOM_TIMESTAMP + " DATETIME DEFAULT CURRENT_TIMESTAMP)";

private int id;


private String catatan;
private String timestamp;

public Catatan(int id, String catatan, String timestamp) {


this.id = id;
this.catatan = catatan;
this.timestamp = timestamp;
}

public Catatan() {
}

public int getId() {

10
return id;
}

public void setId(int id) {


this.id = id;
}

public String getCatatan() {


return catatan;
}

public void setCatatan(String catatan) {


this.catatan = catatan;
}

public String getTimestamp() {


return timestamp;
}

public void setTimestamp(String timestamp) {


this.timestamp = timestamp;
}
}

Database Helper: CatatanDbHelper.java


Berikutnya adalah membuat file yang berfungsi untuk fungsi-fungsi pengelolaan basis data. Buatlah sebuah Java
Class dengan nama CatatanDbHelper.java yang meng-extends SQLiteOpenHelper. Perhatikan gambar berikut.

Kemudian lengkapi skripnya seperti berikut.


public class CatatanDbHelper extends SQLiteOpenHelper {
//versi database
private static final int DATABASE_VERSION = 1;
//nama database
private static final String DATABASE_NAME = "catatan_db";

public CatatanDbHelper(Context context){


super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

@Override
public void onCreate(SQLiteDatabase db) {
//membuat tabel
db.execSQL(Catatan.CREATE_TABLE);
//masukkan data awal sebagai petunjuk penggunaan aplikasi ini
String catatan = "Tap-lama utk edit/hapus catatan. Tap plus utk membuat catatan baru";

11
db.execSQL("INSERT INTO " + Catatan.NAMA_TABEL
+ "(" + Catatan.KOLOM_CATATAN +") VALUES('" + catatan + "')");
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//proses upgrade database, khususnya jika ada perubahan struktur tabel:
//1. drop tabel yang lama jika ada (semua data dihapus juga)
db.execSQL("DROP TABLE IF EXISTS " + Catatan.NAMA_TABEL);
//2. Buat tabel baru
onCreate(db);
}

//insert catatan
public long insertCatatan(String catatan){
//buka database utk ditulisi
SQLiteDatabase db = this.getWritableDatabase();
//proses menulisi ke tabel, id dan timestamp akan di-isi secara otomatis
ContentValues values = new ContentValues();
values.put(Catatan.KOLOM_CATATAN, catatan);
//tambahkan catatan ke tabel
long id = db.insert(Catatan.NAMA_TABEL, null, values);
//tutup koneksi ke database
db.close();
//return id yg baru ditambahkan
return id;
}

//membaca satu catatan


public Catatan getCatatan(long id){
//buka database utk dibaca saja
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(Catatan.NAMA_TABEL,
new String[]{Catatan.KOLOM_ID, Catatan.KOLOM_CATATAN, Catatan.KOLOM_TIMESTAMP},
Catatan.KOLOM_ID + "=?", new String[]{String.valueOf(id)},
null, null, null, null);

if(cursor != null)
cursor.moveToFirst();

//persiapkan object catatan


Catatan catatan = new Catatan(
cursor.getInt(cursor.getColumnIndex(Catatan.KOLOM_ID)),
cursor.getString(cursor.getColumnIndex(Catatan.KOLOM_CATATAN)),
cursor.getString(cursor.getColumnIndex(Catatan.KOLOM_TIMESTAMP))
);
cursor.close();
return catatan;
}

//ambil semua catatan


public List<Catatan> getSemuaCatatan(){
List<Catatan> catatanList = new ArrayList<>();

//query SELECT semua data


String selectQuery = "SELECT * FROM " + Catatan.NAMA_TABEL + " ORDER BY "
+ Catatan.KOLOM_TIMESTAMP + " DESC";

SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);

//looping semua baris dan tambahkan ke list


if(cursor.moveToFirst()){
do{
Catatan catatan = new Catatan();
catatan.setId(cursor.getInt(cursor.getColumnIndex(Catatan.KOLOM_ID)));
catatan.setCatatan(cursor.getString(cursor.getColumnIndex(Catatan.KOLOM_CATATAN)));
catatan.setTimestamp(cursor.getString(cursor.getColumnIndex(Catatan.KOLOM_TIMESTAMP)));

catatanList.add(catatan);
} while(cursor.moveToNext());
}
db.close();
return catatanList;
}

//mengambil jumlah catatan


public int getJumlahCatatan(){
String countQuery = "SELECT * FROM " + Catatan.NAMA_TABEL;
SQLiteDatabase db = this.getReadableDatabase();

12
Cursor cursor = db.rawQuery(countQuery, null);

int jml = cursor.getCount();


cursor.close();
return jml;
}

//update catatan
public int updateCatatan(Catatan catatan){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(Catatan.KOLOM_CATATAN, catatan.getCatatan());

//memperbarui baris catatan


return db.update(Catatan.NAMA_TABEL, values, Catatan.KOLOM_ID + "=?",
new String[]{String.valueOf(catatan.getId())});
}

//menghapus catatan
public void deleteCatatan(Catatan catatan){
SQLiteDatabase db = this.getWritableDatabase();
db.delete(Catatan.NAMA_TABEL, Catatan.KOLOM_ID + "=?",
new String[]{String.valueOf(catatan.getId())});
db.close();
}
}

CatatanTouchListener.java
Berikutnya adalah file untuk mengatur fungsi “touch” pada baris-baris catatan yang ditampilkan dalam
RecyclerView. File ini meng-implement interface RecyclerView.OnItemTouchListener.
Perhatikan gambar berikut, untuk bagian Interface(s), anda cukup ketikkan
RecyclerView.OnItemTouchListener dan Android Studio akan melengkapinya sesuai librari yang
digunakan.

Dan lengkapi skripnya seperti berikut ini.


public class CatatanTouchListener implements RecyclerView.OnItemTouchListener {
private ClickListener clickListener;
private GestureDetector gestureDetector;

@Override
public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(), e.getY());
if(child != null && clickListener != null && gestureDetector.onTouchEvent(e)){

13
clickListener.onClick(child, rv.getChildAdapterPosition(child));
}
return false;
}

@Override
public void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {

@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

interface ClickListener{
void onLongClick(View view, int position);
void onClick(View view, int position);
}

public CatatanTouchListener(Context context,


final RecyclerView recyclerView,
final ClickListener clickListener) {
this.clickListener = clickListener;
gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener(){
@Override
public boolean onSingleTapUp(MotionEvent e){
return true;
}

@Override
public void onLongPress(MotionEvent e){
View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
if(child != null && clickListener != null){
clickListener.onLongClick(child, recyclerView.getChildAdapterPosition(child));
}
}
});
}
}

CatatanAdapter.java
Berikutnya buat Java Class baru dan beri nama CatatanAdapter.java dan meng-extends
RecyclerView.Adapter pada bagian Superclass. File ini sebagai adapter dalam menampilkan data ke
RecyclerView. Perhatikan gambar berikut.

14
Dan lengkapi skripnya seperti berikut.
Catatan: baris-baris import yang ditunjukkan pada skrip berikut hanya sebagai referensi atau rujukan saja. Baris-
baris tersebut dibuat otomatis oleh Android Studio, termasuk ketika anda menggunakan alt+enter.

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

public class CatatanAdapter extends RecyclerView.Adapter<CatatanAdapter.CatatanViewHolder> {


private Context context;
private List<Catatan> catatanList;
private Calendar calendar;

public class CatatanViewHolder extends RecyclerView.ViewHolder {


public TextView tvCatatan;
public TextView tvTimestamp;

public CatatanViewHolder(@NonNull View view) {


super(view);
tvCatatan = view.findViewById(R.id.tvCatatan);
tvTimestamp = view.findViewById(R.id.tvTimestamp);
}
}

public CatatanAdapter(Context context, List<Catatan> catatanList){


this.context = context;
this.catatanList = catatanList;
}

@NonNull
@Override
public CatatanViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.catatan_baris, parent, false);
return new CatatanViewHolder(itemView);
}

@Override
public void onBindViewHolder(@NonNull CatatanViewHolder holder, int position) {
Catatan catatan = catatanList.get(position);

//tampilkan catatan
holder.tvCatatan.setText(catatan.getCatatan());
//tampilkan timestamp
holder.tvTimestamp.setText(formatDate(catatan.getTimestamp()));
}

private String formatDate(String timestamp) {


calendar = Calendar.getInstance();
SimpleDateFormat fmtTanggal = new SimpleDateFormat("yyyy-MM-dd");
String today = fmtTanggal.format(calendar.getTime()); //tanggal hari ini

try {
SimpleDateFormat fmtTanggalDb = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
fmtTanggalDb.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = fmtTanggalDb.parse(timestamp);
TimeZone timeZone = TimeZone.getDefault();
String tanggal = fmtTanggal.format(date);
SimpleDateFormat fmtOut = null;

if(tanggal.compareTo(today) == 0){
fmtOut = new SimpleDateFormat("HH:mm");
} else {
fmtOut = new SimpleDateFormat("dd MM yyyy");
}
fmtOut.setTimeZone(timeZone);
return fmtOut.format(date);

15
} catch (ParseException e) {
e.printStackTrace();
}

return "";
}

@Override
public int getItemCount() {
return catatanList.size();
}
}

MainActivity.java
Selanjutnya adalah mengedit file activity utama pada aplikasi Catatan ini. Edit skripnya hingga seperti berikut.
Catatan: baris-baris import yang ditampilkan di sini hanya sebagai referensi saja.
import android.content.DialogInterface;
import android.graphics.Color;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {


private CatatanAdapter catatanAdapter;
private List<Catatan> catatanList = new ArrayList<>();
private LinearLayout viewCatatanKosong;
private CatatanDbHelper db;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

FloatingActionButton fab = findViewById(R.id.fab);


fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
showDialogCatatan(false, null, -1);
}
});

RecyclerView recyclerView = findViewById(R.id.rvCatatan);


viewCatatanKosong = findViewById(R.id.catatanKosong);

db = new CatatanDbHelper(this);

catatanList.addAll(db.getSemuaCatatan());

catatanAdapter = new CatatanAdapter(this, catatanList);


RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(catatanAdapter);

toggleCatatanKosong();

recyclerView.addOnItemTouchListener(new CatatanTouchListener(this,

16
recyclerView, new CatatanTouchListener.ClickListener() {
@Override
public void onLongClick(View view, int position) {
showDialogAksi(position);
}

@Override
public void onClick(View view, int position) {

}
}));
}

private void showDialogAksi(final int position) {


CharSequence[] opsi = new CharSequence[]{"Edit", "Hapus"};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Pilih aksi");
builder.setItems(opsi, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if(which == 0){
showDialogCatatan(true, catatanList.get(position), position);
} else {
deleteCatatan(position);
}
}
});
builder.show();
}

private void showDialogCatatan(final boolean akanDiupdate, final Catatan catatan, final int position) {
LayoutInflater layoutInflater = LayoutInflater.from(getApplicationContext());
View view = layoutInflater.inflate(R.layout.catatan_dialog, null);

AlertDialog.Builder dialogInputCatatan = new AlertDialog.Builder(MainActivity.this);


dialogInputCatatan.setView(view);

final EditText etCatatan = view.findViewById(R.id.etCatatan);


TextView tvJudulDialog = view.findViewById(R.id.tvJudulDialog);
tvJudulDialog.setText(!akanDiupdate ? getString(R.string.catatanBaruLabel)
: getString(R.string.catatanEditLabel));
if(akanDiupdate && catatan != null){
etCatatan.setText(catatan.getCatatan());
}

dialogInputCatatan
.setCancelable(false)
.setPositiveButton(akanDiupdate ? "perbarui" : "simpan",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {

}
})
.setNegativeButton("batal", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});

final AlertDialog alertDialog = dialogInputCatatan.create();


alertDialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(Color.BLUE);
alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(Color.RED);
}
});
alertDialog.show();

alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//tampilkan toast jika tombol di-klik saat belum ada catatan
if(TextUtils.isEmpty(etCatatan.getText().toString())){
Toast.makeText(MainActivity.this, "Tulis catatan dulu.", Toast.LENGTH_SHORT).show();
return;
} else {
alertDialog.dismiss();

17
}

//cek jika user sedang update catatan


if(akanDiupdate && catatan != null){
updateCatatan(etCatatan.getText().toString(), position);
} else {
createCatatan(etCatatan.getText().toString());
}
}
});
}

private void createCatatan(String txtCatatan) {


long id = db.insertCatatan(txtCatatan);
Catatan ctt = db.getCatatan(id);
if(ctt != null){
catatanList.add(0, ctt);
catatanAdapter.notifyDataSetChanged();
toggleCatatanKosong();
}
}

private void updateCatatan(String txtCatatan, int position) {


Catatan ctt = catatanList.get(position);
ctt.setCatatan(txtCatatan);
db.updateCatatan(ctt);
catatanList.set(position, ctt);
catatanAdapter.notifyItemChanged(position);
toggleCatatanKosong();
}

private void deleteCatatan(int position) {


db.deleteCatatan(catatanList.get(position));
catatanList.remove(position);
catatanAdapter.notifyItemRemoved(position);
toggleCatatanKosong();
}

private void toggleCatatanKosong() {


if(db.getJumlahCatatan() > 0){
viewCatatanKosong.setVisibility(View.GONE);
} else {
viewCatatanKosong.setVisibility(View.VISIBLE);
}
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();

//noinspection SimplifiableIfStatement
if (id == R.id.menuAbout) {
Toast.makeText(this, "Catatan dibuat oleh", Toast.LENGTH_SHORT).show();
//return true;
}

return super.onOptionsItemSelected(item);
}
}

Edit File Pelengkap


File-file berikut adalah pelengkap yang juga perlu diperhatikan agar aplikasi berjalan sesuai desain. Pada bagian
ini, mungkin sebelumnya anda menjumpai beberapa error yang ditunjukkan oleh Android Studio. Error tersebut
kemungkinan karena beberapa file-file src berikut ini.

18
Menu: menu_main.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity">
<item
android:id="@+id/menuAbout"
android:orderInCategory="100"
android:title="@string/menuAbout"
app:showAsAction="never" />
</menu>

Values: strings.xml
<resources>
<string name="app_name">Catatan</string>
<string name="menuAbout">Tentang</string>
<string name="ivCatatanKosong">ikon catatan kosong</string>
<string name="catatanKosongText">Belum ada catatan!</string>
<string name="catatanBaruLabel">Buat Catatan</string>
<string name="hintCatatan">Ayo tuliskan catatanmu!</string>
<string name="catatanEditLabel">Edit Catatan</string>
</resources>

Values: colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#6200EE</color>
<color name="colorPrimaryDark">#3700B3</color>
<color name="colorAccent">#03DAC5</color>
<color name="timestampColor">#858585</color>
<color name="catatanColor">#232323</color>
<color name="catatanKosongColor">#999999</color>
<color name="hintCatatanColor">#c3c3c3</color>
</resources>

Values: dimens.xml
<resources>
<dimen name="fab_margin">16dp</dimen>
<dimen name="padding10">10dp</dimen>
<dimen name="padding16">16dp</dimen>
<dimen name="timestampSize">14sp</dimen>
<dimen name="catatanSize">18sp</dimen>
<dimen name="catatanKosongSize">26sp</dimen>
<dimen name="judulCatatanSize">20sp</dimen>
<dimen name="etCatatanSize">20sp</dimen>
</resources>

Hapus File Tidak Terpakai


File-file berikut dibuat secara otomatis saat kita memilih menggunakan Basic Activity untuk menunjukkan fitur-
fitur yang tersedia dan dapat di-hapus karena tidak digunakan dalam Aplikasi Catatan ini.
• FirstFragment.java
• SecondFragment.java
• Layout/fragment_first.xml
• Layout/fragment_second.xml
• Navigation/nav_graph.xml

19
Uji Coba
Jika semua selesai dan tidak dijumpai error dalam skrip, lanjutkan dengan me-run aplikasi ke Android Virtual
Device (AVD) atau ke perangkat android anda. Dan bila terpaksa, anda bisa Build Bundle(s)/APK dan meng-
instalnya secara manual di perangkat android yang dimiliki.
Hasilnya kurang lebih akan tampak seperti pada screenshot yang ditunjukkan di awal modul ini.

Catatan
Jika dijumpai forced close atau aplikasi tidak dapat dijalankan di AVD ataupun di-perangkat padahal tidak ada
error dalam skripnya, buka Logcat dan coba run kembali aplikasi anda. Perhatikan pesan error yang ditampilkan.
Contoh berikut ini menunjukkan lokasi error-nya dengan warna biru pada nama file dan baris skrip dimana error
itu terjadi.

Gulung ke atas untuk mengetahui sebab error-nya. Seperti contoh berikut. Teks berwarna merah diawali dengan
keterangan FATAL EXCEPTION dan pada baris berikutnya menunjukkan keterangan penyebabnya.

Dengan mengetahui lokasi error dan penyebabnya, anda dapat melakukan proses perbaikan (debugging). Apabila
anda menjumpai error saat mengikuti modul ini, silahkan dibaca dari awal modul dan ketahui bagian materi/skrip
yang terlewatkan.
Disarankan untuk mengikuti seperti yang dicontohkan sebelum melakukan modifikasi.

20
Tambahan

Menambahkan Dialog About


Dialog ini untuk menampilkan informasi pembuat aplikasi dan informasi lainnya yang dianggap perlu seperti teks
sumber dari ikon/gambar yang digunakan.
Layout: catatan_about.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:paddingTop="@dimen/padding10"
android:paddingBottom="@dimen/padding10"
android:paddingLeft="@dimen/padding10"
android:paddingRight="@dimen/padding10">

<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/ikon"
android:layout_gravity="center_horizontal"
android:layout_marginTop="50dp"/>

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/app_name"
android:textSize="40sp"
android:fontFamily="sans-serif-black"
android:textColor="@color/colorPrimaryDark"
android:layout_marginTop="10dp" />

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
android:textSize="18sp"
android:gravity="center"
android:layout_marginVertical="@dimen/padding10"
android:text="@string/deskripsiApp"/>

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textStyle="bold"
android:layout_marginBottom="@dimen/padding10"
android:text="Oleh: Slamet Budi Santoso"/>

<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center|bottom"
android:id="@+id/tvCopyright"
android:lines="3"
android:text="CopyRight"/>
</LinearLayout>

Edit MainActivity.java
Edit pada bagian ini.
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();

//noinspection SimplifiableIfStatement
if (id == R.id.menuAbout) {
showDialogAbout();
}

21
return true;
}

private void showDialogAbout() {


LayoutInflater layoutInflater = LayoutInflater.from(getApplicationContext());
View view = layoutInflater.inflate(R.layout.catatan_about, null);
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setView(view);

String str = "Sumber ikon ditampilkan di sini, kecuali bikin sendiri";


TextView text = view.findViewById(R.id.tvCopyright);
text.setText(Html.fromHtml(str));
builder.show();
}

Teks berwarna di atas silahkan diganti (copas) dengan teks yang terdapat pada file sumber_ikon.txt.
Dikarenakan teks sumber ikon berisi tautan ke situs asal dari gambar, maka digunakan fungsi
Html.fromHtml().

22

Anda mungkin juga menyukai