Salah satu database yang wajib di coba oleh para developer mobile adalah Realm. Realm adalah mobile database pengganti SQLite dan Core Data. Realm dapat berjalan secara langsung di dalam perangkat smartphone, tablet atau wearebles. Selain itu, Realm memiliki beberapa kelebihan dibanding SQLite diantaranya :
1. Simple : Data dipresentasikan dalam bentuk object dan menjalankan query dengan kode.
2. Cepat : Realm lebih cepat daripada SQLite maupun ORM.
3. Cross-Platform : Realm mendukung berbagai platform diantaranya iOS, OSX dan Android.
4. Modern : Realm mendukung thread-safety, relationships dan encryption.
Dan masih banyak lagi keunggulan dari Realm.
Oke, pada tutorial ini kita akan membuat aplikasi CRUD sederhana dengan Realm. Aplikasinya saya namakan Simple Note App.
Untuk project ini saya menggunakan Realm versi 0.87.5. (kalau yang sekarang sudah versi 0.90.1).
Latest version bisa dilihat di https://realm.io/docs/java/latest/
Pertama kita menambahkan dependencies di build.gradle.
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.3.0' compile 'com.android.support:recyclerview-v7:23.3.0' compile 'io.realm:realm-android:0.87.5' }Buat beberapa layout berikut :
list_item_note.xml
<?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="wrap_content" android:padding="@dimen/activity_horizontal_margin"> <TextView android:id="@+id/note" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="14sp" android:text="Note" /> <TextView android:id="@+id/date" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="11sp" android:text="Date" android:layout_gravity="right" /> </LinearLayout>activity_save.xml
<?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:descendantFocusability="beforeDescendants" android:focusableInTouchMode="true"> <EditText android:id="@+id/noteText" android:layout_width="match_parent" android:layout_height="match_parent" android:inputType="text" android:ems="10" android:gravity="top" android:imeOptions="flagNoExtractUi" android:hint="Write note here..."/> </LinearLayout>activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".activities.MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/lvNote" android:layout_width="match_parent" android:layout_height="wrap_content" android:scrollbars="vertical" android:layout_above="@+id/btnAdd" android:layout_alignParentTop="true" /> <Button android:id="@+id/btnAdd" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Add" android:background="@color/colorPrimary" android:textColor="@android:color/white" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> </RelativeLayout>Nah berikutnya kita akan membuat kelas yang berisi settingan realm dengan method-method CRUD.
package com.example.android_realm.db; import android.content.Context; import java.util.List; import io.realm.Realm; import io.realm.RealmConfiguration; import io.realm.RealmMigration; import io.realm.RealmObject; import io.realm.RealmResults; /** * Created by wim on 5/10/16. */ public class RealmDB { private Realm realm; private Context context; public RealmDB(Context context) { this.context = context; realm = Realm.getInstance(context); } public void setMigration(RealmMigration migration) { RealmConfiguration config = new RealmConfiguration.Builder(context) .schemaVersion(0) .name("example.realm") .migration(migration) .build(); realm = Realm.getInstance(config); } public Realm getRealm(){ return realm; } @SuppressWarnings("unchecked") public <T extends RealmObject> T getById(Class<? extends RealmObject> cls, int id) { return (T) this.getRealm().where(cls.asSubclass(RealmObject.class)).equalTo("id", id).findFirst(); } public RealmResults<? extends RealmObject> getAllData(Class<? extends RealmObject> cls) { return this.getRealm().where(cls.asSubclass(RealmObject.class)).findAll(); } public void add(RealmObject object) { this.getRealm().beginTransaction(); this.getRealm().copyToRealm(object); this.getRealm().commitTransaction(); } public void add(List<RealmObject> listObject) { this.getRealm().beginTransaction(); this.getRealm().copyToRealm(listObject); this.getRealm().commitTransaction(); } public void delete(Class<? extends RealmObject> cls, int id) { RealmResults results = this.getRealm().where(cls.asSubclass(RealmObject.class)).equalTo("id", id).findAll(); this.getRealm().beginTransaction(); results.clear(); this.getRealm().commitTransaction(); } public void update(RealmObject object){ this.getRealm().beginTransaction(); this.getRealm().copyToRealmOrUpdate(object); this.getRealm().commitTransaction(); } }Buat kelas MainApplication berikut.
package com.example.android_realm; import android.app.Application; import com.example.android_realm.db.RealmDB; import io.realm.DynamicRealm; import io.realm.RealmMigration; import io.realm.RealmSchema; /** * Created by wim on 5/12/16. */ public class MainApplication extends Application { @Override public void onCreate() { super.onCreate(); RealmDB realmDB = new RealmDB(this); realmDB.setMigration(new DataMigration()); } private class DataMigration implements RealmMigration { @Override public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { RealmSchema schema = realm.getSchema(); if (oldVersion == 0) { schema.create("Note") .addField("id", int.class) .addField("note", String.class) .addField("dateModified", String.class); oldVersion++; } } } }Kemudian kita membuat model datanya. Kelas ini wajib untuk meng-extends RealmObject.
package com.example.android_realm.model; import io.realm.RealmObject; import io.realm.annotations.PrimaryKey; /** * Created by wim on 5/14/16. */ public class Note extends RealmObject{ @PrimaryKey private int id; private String note; private String dateModified; public Note() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getNote() { return note; } public void setNote(String note) { this.note = note; } public String getDateModified() { return dateModified; } public void setDateModified(String dateModified) { this.dateModified = dateModified; } }Kemudian buat adapter untuk recyclerview.
package com.example.android_realm.adapter; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.example.android_realm.R; import com.example.android_realm.listener.RecyclerItemClickListener; import com.example.android_realm.model.Note; import com.example.android_realm.util.TimeUtil; import io.realm.RealmResults; /** * Created by wim on 5/14/16. */ public class NoteListAdapter extends RecyclerView.Adapter<NoteListAdapter.NoteViewHolder>{ private RealmResults<Note> noteList; private RecyclerItemClickListener recyclerItemClickListener; public NoteListAdapter(RecyclerItemClickListener recyclerItemClickListener) { this.recyclerItemClickListener = recyclerItemClickListener; } public void setNoteList(RealmResults<Note> noteList){ this.noteList = noteList; notifyDataSetChanged(); } public Note getItem(int position){ return noteList.get(position); } @Override public NoteViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_note, parent, false); final NoteViewHolder noteViewHolder = new NoteViewHolder(view); noteViewHolder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int adapterPos = noteViewHolder.getAdapterPosition(); if (adapterPos != RecyclerView.NO_POSITION) { if (recyclerItemClickListener != null) { recyclerItemClickListener.onItemClick(adapterPos, noteViewHolder.itemView); } } } }); return noteViewHolder; } @Override public void onBindViewHolder(NoteViewHolder holder, int position) { final Note note = noteList.get(position); holder.note.setText(note.getNote().length() > 50 ? note.getNote().substring(0, 50) : note.getNote()); holder.date.setText(TimeUtil.unixToTimeAgo(note.getDateModified())); } @Override public int getItemCount() { return noteList.size(); } public static class NoteViewHolder extends RecyclerView.ViewHolder { TextView note; TextView date; public NoteViewHolder(View itemView) { super(itemView); note = (TextView) itemView.findViewById(R.id.note); date = (TextView) itemView.findViewById(R.id.date); } } }Listener ketika recyclerview diklik.
package com.example.android_realm.listener; import android.view.View; /** * Created by wim on 5/14/16. */ public interface RecyclerItemClickListener { void onItemClick(int position, View view); }Buat beberapa utility yang akan kita gunakan sebagai berikut :
DividerItemDecoration.java
package com.example.android_realm.util; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; /** * Created by wim on 5/14/16. */ public class DividerItemDecoration extends RecyclerView.ItemDecoration { private static final int[] ATTRS = new int[]{ android.R.attr.listDivider }; public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; private Drawable mDivider; private int mOrientation; public DividerItemDecoration(Context context, int orientation) { final TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); a.recycle(); setOrientation(orientation); } public void setOrientation(int orientation) { if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { throw new IllegalArgumentException("invalid orientation"); } mOrientation = orientation; } @Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { if (mOrientation == VERTICAL_LIST) { drawVertical(c, parent); } else { drawHorizontal(c, parent); } } public void drawVertical(Canvas c, RecyclerView parent) { final int left = parent.getPaddingLeft(); final int right = parent.getWidth() - parent.getPaddingRight(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int top = child.getBottom() + params.bottomMargin; final int bottom = top + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } public void drawHorizontal(Canvas c, RecyclerView parent) { final int top = parent.getPaddingTop(); final int bottom = parent.getHeight() - parent.getPaddingBottom(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int left = child.getRight() + params.rightMargin; final int right = left + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { if (mOrientation == VERTICAL_LIST) { outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); } else { outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); } } }
TimeUtil.java
package com.example.android_realm.util; import android.text.format.DateUtils; import java.util.Date; /** * Created by wim on 5/14/16. */ public class TimeUtil { public static long getUnix(){ return new Date().getTime(); } public static String unixToTimeAgo(String unix){ CharSequence timeAgo = DateUtils.getRelativeTimeSpanString( Long.parseLong(unix), System.currentTimeMillis(), DateUtils.SECOND_IN_MILLIS); return timeAgo.toString(); } }Setelah itu, buat kelas activity dengan nama SaveActivity.java. Nah di kelas ini kita mengimplementasikan method berupa insert, update dan delete.
package com.example.android_realm.activities; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.text.TextUtils; import android.view.Menu; import android.view.MenuItem; import android.widget.EditText; import com.example.android_realm.R; import com.example.android_realm.db.RealmDB; import com.example.android_realm.model.Note; import com.example.android_realm.util.TimeUtil; /** * Created by wim on 5/14/16. */ public class SaveActivity extends AppCompatActivity { private EditText noteText; private int id; public static void start(Context context, int id){ Intent intent = new Intent(context, SaveActivity.class); intent.putExtra(SaveActivity.class.getSimpleName(), id); context.startActivity(intent); } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_save); ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(true); } noteText = (EditText) findViewById(R.id.noteText); id = getIntent().getExtras().getInt(SaveActivity.class.getSimpleName()); if(id != 0){ // get by id Note note = new RealmDB(this).getById(Note.class, id); noteText.setText(String.valueOf(note.getNote())); } } // add note public void addNote(String noteText) { Note note = new Note(); note.setId((int) (System.currentTimeMillis()) / 1000); note.setNote(noteText); note.setDateModified(String.valueOf(TimeUtil.getUnix())); new RealmDB(this).add(note); } // update note public void updateNote(int id, String noteText){ Note note = new Note(); note.setId(id); note.setNote(noteText); note.setDateModified(String.valueOf(TimeUtil.getUnix())); new RealmDB(this).update(note); } // delete note public void deleteNote(int id) { new RealmDB(this).delete(Note.class, id); } private void createOrUpdate(){ if(!TextUtils.isEmpty(noteText.getText().toString())) { if (id == 0) { addNote(noteText.getText().toString()); } else { updateNote(id, noteText.getText().toString()); } }else{ return; } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_save, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. switch (item.getItemId()) { case android.R.id.home: createOrUpdate(); finish(); return true; case R.id.menu_save: createOrUpdate(); finish(); return true; case R.id.menu_delete: if(id != 0) deleteNote(id); finish(); return true; default: return super.onOptionsItemSelected(item); } } }Terakhir, buat MainActivity.java. Di sini kita akan mengakses semua datanya kemudian menampilkannya dalam bentuk list.
package com.example.android_realm.activities; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.Button; import com.example.android_realm.R; import com.example.android_realm.adapter.NoteListAdapter; import com.example.android_realm.db.RealmDB; import com.example.android_realm.listener.RecyclerItemClickListener; import com.example.android_realm.model.Note; import com.example.android_realm.util.DividerItemDecoration; import io.realm.RealmResults; import io.realm.Sort; public class MainActivity extends AppCompatActivity implements RecyclerItemClickListener{ private RecyclerView lvNote; private Button btnAdd; private NoteListAdapter noteListAdapter; private LinearLayoutManager linearLayoutManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lvNote = (RecyclerView) findViewById(R.id.lvNote); btnAdd = (Button) findViewById(R.id.btnAdd); noteListAdapter = new NoteListAdapter(this); linearLayoutManager = new LinearLayoutManager(this); lvNote.setLayoutManager(linearLayoutManager); lvNote.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL)); lvNote.setAdapter(noteListAdapter); btnAdd.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SaveActivity.start(MainActivity.this, 0); } }); } @Override protected void onResume() { super.onResume(); loadData(); } private void loadData(){ if(retrieve() != null) noteListAdapter.setNoteList(retrieve()); } public RealmResults<Note> retrieve() { RealmResults<Note> result = (RealmResults<Note>) new RealmDB(this).getAllData(Note.class); result.sort("dateModified", Sort.DESCENDING); return result; } @Override public void onItemClick(int position, View view) { SaveActivity.start(this, noteListAdapter.getItem(position).getId()); } @Override public void onBackPressed() { super.onBackPressed(); finish(); } }Build dan jalankan maka hasilnya sebagai berikut :
Oke segitu dulu tutorial untuk kali ini.
Source code lengkap dapat dilihat di https://github.com/wimsonevel/Android-Realm
Sekian dan semoga bermanfaat.
Happy Coding :)
0 Komentar
Penulisan markup di komentar