SQLite adalah light weight database yang dapat menyimpan data di device Android. Database ini sudah ditanamkan pada Android OS. SQLite sama halnya dengan DBMS lainnya, yaitu menggunakan query untuk memproses datanya, dan yang membedakannya dengan DBMS lainnya adalah tidak perlu connector untuk terhubung ke database ini karena sudah include di Android.
Pada kali ini saya akan membahas bagaimana menyimpan dan mengakses data di SQLite. Atau biasa kita sebut CRUD ajalah :D
Simak tutorialnya berikut :
Tambahkan library yang diperlukan.
Kita buat desain dulu. Pertama buat layout dengan nama 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" xmlns:app="http://schemas.android.com/apk/res-auto" tools:context="com.wimso.android_sqlite.MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/lvContact" android:layout_width="match_parent" android:layout_height="wrap_content"/> <android.support.design.widget.FloatingActionButton android:id="@+id/add" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:src="@drawable/ic_add_black_24dp" android:tint="#FFFFFF" app:rippleColor="#F48FB1" android:layout_marginRight="@dimen/activity_horizontal_margin" android:layout_marginBottom="@dimen/activity_horizontal_margin" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" android:layout_marginEnd="@dimen/activity_horizontal_margin" /> </RelativeLayout>
Kemudian layout activity_act.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:padding="@dimen/activity_horizontal_margin"> <EditText android:id="@+id/personText" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textPersonName" android:hint="Insert person name" android:ems="10" android:layout_marginBottom="@dimen/margin_10" /> <EditText android:id="@+id/phoneText" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="phone" android:ems="10" android:hint="Insert phone number" android:layout_marginBottom="@dimen/margin_10" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/btnAdd" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/add"/> <Button android:id="@+id/btnEdit" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/edit" /> <Button android:id="@+id/btnDelete" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/delete"/> </LinearLayout> </LinearLayout>
Kemudian. Layout list_contact_item.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:layout_margin="@dimen/margin_10"> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:id="@+id/thumb" android:layout_width="60dp" android:layout_height="60dp" android:src="@mipmap/ic_launcher" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="@dimen/margin_10" android:orientation="vertical"> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="16sp" android:text="Small Text"/> <TextView android:id="@+id/phone" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="14sp" android:text="Small Text" /> </LinearLayout> </LinearLayout> </LinearLayout>
Selanjutnya buat kelas sebagai “constant” dengan nama ContactField.java
package com.wimso.android_sqlite.constant; /** * Created by wim on 4/26/16. */ public class ContactField { public static final String TABLE_NAME = "contact"; public static final String COLUMN_ID = "contact_id"; public static final String COLUMN_NAME = "contact_name"; public static final String COLUMN_PHONE = "contact_phone"; }
Buat kelas model untuk kontak dengan nama Contact.java
package com.wimso.android_sqlite.model; import android.os.Parcel; import android.os.Parcelable; /** * Created by wim on 4/26/16. */ public class Contact implements Parcelable { private int id; private String name; private String phone; public Contact() { } protected Contact(Parcel in) { this.id = in.readInt(); this.name = in.readString(); this.phone = in.readString(); } public static final Parcelable.Creator<Contact> CREATOR = new Parcelable.Creator<Contact>() { @Override public Contact createFromParcel(Parcel source) { return new Contact(source); } @Override public Contact[] newArray(int size) { return new Contact[size]; } }; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(this.id); dest.writeString(this.name); dest.writeString(this.phone); } }
Kemudian buat kelas dengan nama LetterTile.java, jadi kelas ini nanti fungsinya untuk menampilkan thumbail kontak dengan huruf pertama dari nama kontak. Kebayang gag? Yah nanti aja lihat hasilnya.
package com.wimso.android_sqlite.widget; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.Typeface; import android.text.TextPaint; import com.wimso.android_sqlite.R; /** * Created by wim on 5/2/16. */ public class LetterTile { /** The number of available tile colors (see R.array.letter_tile_colors) */ private static final int NUM_OF_TILE_COLORS = 8; /** The {@link TextPaint} used to draw the letter onto the tile */ private final TextPaint mPaint = new TextPaint(); /** The bounds that enclose the letter */ private final Rect mBounds = new Rect(); /** The {@link Canvas} to draw on */ private final Canvas mCanvas = new Canvas(); /** The first char of the name being displayed */ private final char[] mFirstChar = new char[1]; /** The background colors of the tile */ private final TypedArray mColors; /** The font size used to display the letter */ private final int mTileLetterFontSize; /** The default image to display */ private final Bitmap mDefaultBitmap; /** * Constructor forLetterTileProvider
* * @param context The {@link Context} to use */ public LetterTile(Context context) { final Resources res = context.getResources(); mPaint.setTypeface(Typeface.create("sans-serif-light", Typeface.NORMAL)); mPaint.setColor(Color.WHITE); mPaint.setTextAlign(Paint.Align.CENTER); mPaint.setAntiAlias(true); mColors = res.obtainTypedArray(R.array.letter_tile_colors); mTileLetterFontSize = res.getDimensionPixelSize(R.dimen.tile_letter_font_size); mDefaultBitmap = BitmapFactory.decodeResource(res, android.R.drawable.sym_def_app_icon); } /** * @param displayName The name used to create the letter for the tile * @param key The key used to generate the background color for the tile * @param width The desired width of the tile * @param height The desired height of the tile * @return A {@link Bitmap} that contains a letter used in the English * alphabet or digit, if there is no letter or digit available, a * default image is shown instead */ public Bitmap getLetterTile(String displayName, String key, int width, int height) { final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); final char firstChar = displayName.charAt(0); final Canvas c = mCanvas; c.setBitmap(bitmap); c.drawColor(pickColor(key)); if (isEnglishLetterOrDigit(firstChar)) { mFirstChar[0] = Character.toUpperCase(firstChar); mPaint.setTextSize(mTileLetterFontSize); mPaint.getTextBounds(mFirstChar, 0, 1, mBounds); c.drawText(mFirstChar, 0, 1, 0 + width / 2, 0 + height / 2 + (mBounds.bottom - mBounds.top) / 2, mPaint); } else { c.drawBitmap(mDefaultBitmap, 0, 0, null); } return bitmap; } /** * @param c The char to check * @return True ifc
is in the English alphabet or is a digit, * false otherwise */ private static boolean isEnglishLetterOrDigit(char c) { return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9'; } /** * @param key The key used to generate the tile color * @return A new or previously chosen color forkey
used as the * tile background color */ private int pickColor(String key) { // String.hashCode() is not supposed to change across java versions, so // this should guarantee the same key always maps to the same color final int color = Math.abs(key.hashCode()) % NUM_OF_TILE_COLORS; try { return mColors.getColor(color, Color.BLACK); } finally { mColors.recycle(); } } }
Buat sebuah listener yang berfungsi ketika RecyclerView di klik.
package com.wimso.android_sqlite.listener; import android.view.View; /** * Created by wim on 5/2/16. */ public interface RecyclerItemClickListener { void onItemClick(int position, View view); }
Buat adapter dengan nama ContactListAdapter.java
package com.wimso.android_sqlite.adapter; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.wimso.android_sqlite.R; import com.wimso.android_sqlite.listener.RecyclerItemClickListener; import com.wimso.android_sqlite.model.Contact; import com.wimso.android_sqlite.widget.LetterTile; import java.util.ArrayList; import java.util.List; /** * Created by wim on 5/1/16. */ public class ContactListAdapter extends RecyclerView.Adapter<ContactListAdapter.ContactHolder>{ private List<Contact> contactList; private Context context; private RecyclerItemClickListener recyclerItemClickListener; public ContactListAdapter(Context context) { this.context = context; this.contactList = new ArrayList<>(); } private void add(Contact item) { contactList.add(item); notifyItemInserted(contactList.size() - 1); } public void addAll(List<Contact> contactList) { for (Contact contact : contactList) { add(contact); } } public void remove(Contact item) { int position = contactList.indexOf(item); if (position > -1) { contactList.remove(position); notifyItemRemoved(position); } } public void clear() { while (getItemCount() > 0) { remove(getItem(0)); } } public Contact getItem(int position) { return contactList.get(position); } @Override public ContactHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_contact_item, parent, false); final ContactHolder contactHolder = new ContactHolder(view); contactHolder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int adapterPos = contactHolder.getAdapterPosition(); if (adapterPos != RecyclerView.NO_POSITION) { if (recyclerItemClickListener != null) { recyclerItemClickListener.onItemClick(adapterPos, contactHolder.itemView); } } } }); return contactHolder; } @Override public void onBindViewHolder(ContactHolder holder, int position) { final Contact contact = contactList.get(position); final Resources res = context.getResources(); final int tileSize = res.getDimensionPixelSize(R.dimen.letter_tile_size); LetterTile letterTile = new LetterTile(context); Bitmap letterBitmap = letterTile.getLetterTile(contact.getName(), String.valueOf(contact.getId()), tileSize, tileSize); holder.thumb.setImageBitmap(letterBitmap); holder.name.setText(contact.getName()); holder.phone.setText(contact.getPhone()); } @Override public int getItemCount() { return contactList.size(); } public void setOnItemClickListener(RecyclerItemClickListener recyclerItemClickListener) { this.recyclerItemClickListener = recyclerItemClickListener; } static class ContactHolder extends RecyclerView.ViewHolder { ImageView thumb; TextView name; TextView phone; public ContactHolder(View itemView) { super(itemView); thumb = (ImageView) itemView.findViewById(R.id.thumb); name = (TextView) itemView.findViewById(R.id.name); phone = (TextView) itemView.findViewById(R.id.phone); } } }
Nah, sekarang kita buat kelas untuk konfiguras database SQLite berserta method-method untuk CRUD. Buat dengan nama SQLiteDB.
package com.wimso.android_sqlite.db; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import com.wimso.android_sqlite.constant.ContactField; import com.wimso.android_sqlite.model.Contact; /** * Created by wim on 4/26/16. */ public class SQLiteDB extends SQLiteOpenHelper { // If you change the database schema, you must increment the database version. public static final int DATABASE_VERSION = 1; public static final String DATABASE_NAME = "Contact.db"; private static final String TEXT_TYPE = " TEXT"; private static final String COMMA_SEP = ","; private static final String SQL_CREATE_ENTRIES = "CREATE TABLE " + ContactField.TABLE_NAME + " (" + ContactField.COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + ContactField.COLUMN_NAME + TEXT_TYPE + COMMA_SEP + ContactField.COLUMN_PHONE + TEXT_TYPE + " )"; private static final String SQL_DELETE_ENTRIES = "DROP TABLE IF EXISTS " + ContactField.TABLE_NAME; public SQLiteDB(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(SQL_CREATE_ENTRIES); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL(SQL_DELETE_ENTRIES); onCreate(db); } public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { onUpgrade(db, oldVersion, newVersion); } public void create(Contact contact){ // Gets the data repository in write mode SQLiteDatabase db = getWritableDatabase(); // Create a new map of values, where column names are the keys ContentValues values = new ContentValues(); values.put(ContactField.COLUMN_NAME, contact.getName()); values.put(ContactField.COLUMN_PHONE, contact.getPhone()); // Insert the new row, returning the primary key value of the new row long newRowId; newRowId = db.insert( ContactField.TABLE_NAME, null, values); } public Cursor retrieve(){ SQLiteDatabase db = getReadableDatabase(); // Define a projection that specifies which columns from the database // you will actually use after this query. String[] projection = { ContactField.COLUMN_ID, ContactField.COLUMN_NAME, ContactField.COLUMN_PHONE }; // How you want the results sorted in the resulting Cursor String sortOrder = ContactField.COLUMN_NAME + " ASC"; Cursor c = db.query( ContactField.TABLE_NAME, // The table to query projection, // The columns to return null, // The columns for the WHERE clause null, // The values for the WHERE clause null, // don't group the rows null, // don't filter by row groups sortOrder // The sort order ); return c; } public void update(Contact contact){ SQLiteDatabase db = getReadableDatabase(); // New value for one column ContentValues values = new ContentValues(); values.put(ContactField.COLUMN_NAME, contact.getName()); values.put(ContactField.COLUMN_PHONE, contact.getPhone()); // Which row to update, based on the ID String selection = ContactField.COLUMN_ID + " LIKE ?"; String[] selectionArgs = { String.valueOf(contact.getId()) }; int count = db.update( ContactField.TABLE_NAME, values, selection, selectionArgs); } public void delete(int id){ SQLiteDatabase db = getReadableDatabase(); // Define 'where' part of query. String selection = ContactField.COLUMN_ID + " LIKE ?"; // Specify arguments in placeholder order. String[] selectionArgs = { String.valueOf(id) }; // Issue SQL statement. db.delete(ContactField.TABLE_NAME, selection, selectionArgs); } }
Nah, sekarang kita masuk ke activity. Buat kelas dengan nama MainActivity.java
package com.wimso.android_sqlite; import android.database.Cursor; import android.support.design.widget.FloatingActionButton; 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 com.wimso.android_sqlite.adapter.ContactListAdapter; import com.wimso.android_sqlite.db.SQLiteDB; import com.wimso.android_sqlite.listener.RecyclerItemClickListener; import com.wimso.android_sqlite.model.Contact; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity implements RecyclerItemClickListener { private RecyclerView lvContact; private FloatingActionButton btnAdd; private ContactListAdapter contactListAdapter; private LinearLayoutManager linearLayoutManager; private SQLiteDB sqLiteDB; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lvContact = (RecyclerView) findViewById(R.id.lvContact); btnAdd = (FloatingActionButton) findViewById(R.id.add); linearLayoutManager = new LinearLayoutManager(this); contactListAdapter = new ContactListAdapter(this); contactListAdapter.setOnItemClickListener(this); lvContact.setLayoutManager(linearLayoutManager); lvContact.setAdapter(contactListAdapter); btnAdd.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ActActivity.start(MainActivity.this); } }); } @Override protected void onStart() { super.onStart(); loadData(); } void loadData(){ sqLiteDB = new SQLiteDB(this); List<Contact> contactList = new ArrayList<>(); Cursor cursor = sqLiteDB.retrieve(); Contact contact; if (cursor.moveToFirst()) { do { contact = new Contact(); contact.setId(cursor.getInt(0)); contact.setName(cursor.getString(1)); contact.setPhone(cursor.getString(2)); contactList.add(contact); }while (cursor.moveToNext()); } contactListAdapter.clear(); contactListAdapter.addAll(contactList); } @Override public void onItemClick(int position, View view) { ActActivity.start(this, contactListAdapter.getItem(position)); } }
Lanjut ke ActActivity.java
package com.wimso.android_sqlite; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import com.wimso.android_sqlite.db.SQLiteDB; import com.wimso.android_sqlite.model.Contact; /** * Created by docotel on 5/2/16. */ public class ActActivity extends AppCompatActivity implements View.OnClickListener{ private EditText personName; private EditText phone; private Button btnAdd, btnEdit, btnDelete; private SQLiteDB sqLiteDB; private Contact contact; public static void start(Context context){ Intent intent = new Intent(context, ActActivity.class); context.startActivity(intent); } public static void start(Context context, Contact contact){ Intent intent = new Intent(context, ActActivity.class); intent.putExtra(ActActivity.class.getSimpleName(), contact); context.startActivity(intent); } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_act); personName = (EditText) findViewById(R.id.personText); phone = (EditText) findViewById(R.id.phoneText); btnAdd = (Button) findViewById(R.id.btnAdd); btnEdit = (Button) findViewById(R.id.btnEdit); btnDelete = (Button) findViewById(R.id.btnDelete); btnAdd.setOnClickListener(this); btnEdit.setOnClickListener(this); btnDelete.setOnClickListener(this); contact = getIntent().getParcelableExtra(ActActivity.class.getSimpleName()); if(contact != null){ btnAdd.setVisibility(View.GONE); personName.setText(contact.getName()); phone.setText(contact.getPhone()); }else{ btnEdit.setVisibility(View.GONE); btnDelete.setVisibility(View.GONE); } sqLiteDB = new SQLiteDB(this); } @Override public void onClick(View v) { if(v == btnAdd){ contact = new Contact(); contact.setName(personName.getText().toString()); contact.setPhone(phone.getText().toString()); sqLiteDB.create(contact); Toast.makeText(this, "Inserted!", Toast.LENGTH_SHORT).show(); finish(); }else if(v == btnEdit){ contact.setName(personName.getText().toString()); contact.setPhone(phone.getText().toString()); sqLiteDB.update(contact); Toast.makeText(this, "Edited!", Toast.LENGTH_SHORT).show(); finish(); }else if(v == btnDelete){ sqLiteDB.delete(contact.getId()); Toast.makeText(this, "Deleted!", Toast.LENGTH_SHORT).show(); finish(); } } }
Build dan jalankan, maka hasilnya sebagai berikut :
*Biarkan jomblo berimajinasi :v
*Just kidding (abaikan)
Source code lengkap dapat dilihat di https://github.com/wimsonevel/Android-SQLite
Jika ada bagian yang error, liat aja di source codenya. Karena TS hanya menyampaikan yang penting-penting saja :D
Sekian dan semoga bermanfaat
Happy Coding :)
6 Komentar
Sebelumnya terimakasih atas tutorialnya gan. Jika saya menggunakan Fragment bukan activity untuk recycleview/list datanya, apakah ada script yg harus dirubah? Mohon bantuannya :)
Balasgak gan, scriptnya tetap sama,, paling yg dirubah cuma pas itemnya di klik jadi ActActivity.start(getActivity(), contactListAdapter.getItem(position));
Balasgan mohon pencerahannya, itu yang bagian mColors = "array" nya error
Balasbagian mTileLetterFontSize = "tile_letter_font_size" nya error,
mColors = res.obtainTypedArray(R.array.letter_tile_colors);
mTileLetterFontSize = res.getDimensionPixelSize(R.dimen.tile_letter_font_size);
ada di resource bagian values gan, lihat source code lengkapnya di sini gan https://github.com/wimsonevel/Android-SQLite
BalasThanks
BalasThanks bro
BalasPenulisan markup di komentar