(Tutorial Android) Tutorial CRUD with Realm Android

Saturday, May 14, 2016

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 :)

Share this :

Previous
Next Post »
0 Komentar

Penulisan markup di komentar
  • Silakan tinggalkan komentar sesuai topik. Komentar yang menyertakan link aktif, iklan, atau sejenisnya akan dihapus.
  • Untuk menyisipkan kode gunakan <i rel="code"> kode yang akan disisipkan </i>
  • Untuk menyisipkan kode panjang gunakan <i rel="pre"> kode yang akan disisipkan </i>
  • Untuk menyisipkan quote gunakan <i rel="quote"> catatan anda </i>
  • Untuk menyisipkan gambar gunakan <i rel="image"> URL gambar </i>
  • Untuk menyisipkan video gunakan [iframe] URL embed video [/iframe]
  • Kemudian parse kode tersebut pada kotak di bawah ini
  • © 2015 Simple SEO ✔