Setelah kemarin membuat tutorial tentang CRUD untuk database online, tidak lengkap rasanya jika tidak membuat tutorial juga untuk database offline yaitu SQLite Database. Penggunaan SQLite untuk menyimpan data lokal sangat sering digunakan dalam aplikasi-aplikasi. Oleh karena itu, sangatlah perlu untuk mempelajari cara penggunaannya.
Tutorial kali ini, aplikasi yang akan saya buat adalah aplikasi My Diary. Dari namanya, aplikasi ini memang seperti buku diari pada umumnya. Saya membuat aplikasi tersebut, karena menurut saya penerapan CRUD untuk SQLite sudah mencakup semuanya. Seperti Create untuk menambahkan diary baru misalnya. Yang beda dari tutorial kali ini, aplikasi yang saya buat akan saya upload di playstore, jadi anda dapat dengan mudah untuk mencobanya dan juga sebagai tambahan portofolio saya, hehe.
Silahkan jika ingin mencobanya bisa didownload lewat playstore:
Tidak usah bertele-tele, kita mulai saja membuat aplikasi ini. Seperti biasa, saya akan menjelaskan alur dari pembuatan aplikasi ini, sebagai berikut:
- Menambahkan beberapa library pendukung
- Mendisain antar muka
- Coding Time
Library Pendukung
Seperti biasa, AppCompat tidak pernah ditinggalkan
com.android.support:appcompat-v7:23.0.1
Lalu saya menggunakan support design untuk mempercantik interface
com.android.support:design:23.0.1
Untuk list saya menggunakan recyclerview dengan itemnya menggunakan cardview, untuk memberikan efek shadow
com.android.support:recyclerview-v7:23.0.1 com.android.support:cardview-v7:23.0.1
Keseluruhannya seperti ini:
Antar Muka
Terdapat 4 activity, 1 activity bertemakan dialog, 1 activity untuk splash screen dan 2 lainnya sebagai activity utama dan activity diary. Dan juga terdapat 1 custom layout untuk item dari recyclerview.
Didalam projek ini juga digunakan beberapa gambar dan icon. Untuk icon bisa anda generate sendiri jika mempunyai plugin material design icon. Atau bisa juga copy paste dari sourcecode tutorial ini.
SplashScreen
activity_splash_screen.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" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" android:fitsSystemWindows="true" tools:context="com.andevindo.andevindodiary.Activity.SplashScreenActivity" android:background="@color/colorPrimary"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageView" android:layout_centerVertical="true" android:layout_centerHorizontal="true" android:src="@drawable/logo"/> <ImageView android:layout_width="75dp" android:layout_height="wrap_content" android:adjustViewBounds="true" android:id="@+id/imageView2" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:src="@drawable/logo4"/> <ImageView android:layout_marginLeft="15dp" android:layout_width="125dp" android:layout_height="wrap_content" android:adjustViewBounds="true" android:id="@+id/imageView3" android:layout_alignBottom="@+id/imageView2" android:layout_alignLeft="@+id/imageView" android:src="@drawable/domainesia"/> </RelativeLayout>
Menu Utama
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <android.support.design.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" android:fitsSystemWindows="true" tools:context=".MainActivity"> <android.support.design.widget.AppBarLayout android:layout_height="wrap_content" android:layout_width="match_parent" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.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"/> </android.support.design.widget.AppBarLayout> <include layout="@layout/content_main"/> <android.support.design.widget.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"/> </android.support.design.widget.CoordinatorLayout>
Menu utama menggunakan include untuk menambahkan layout lain dalam activity_main.xml ini.
content_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" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:showIn="@layout/activity_main" tools:context=".MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler" android:layout_width="match_parent" android:layout_height="match_parent"/> </RelativeLayout>
Detail Diary
activity_detail.xml
<?xml version="1.0" encoding="utf-8"?> <ScrollView 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"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.andevindo.andevindodiary.Activity.DetailActivity" android:orientation="vertical"> <TextView android:id="@+id/title" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:textSize="20sp" android:fontFamily="@string/font_medium" android:alpha="0.87"/> <TextView android:id="@+id/content" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:textSize="14sp" android:fontFamily="@string/font_regular" android:alpha="0.87"/> <TextView android:id="@+id/loc_date" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="12sp" android:fontFamily="@string/font_regular" android:alpha="0.54"/> </LinearLayout> </ScrollView>
Diary Activity
Diary activity ini untuk membuat diary baru atau untuk merubah diary lama.
activity_diary.xml
<?xml version="1.0" encoding="utf-8"?> <android.support.design.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" android:fitsSystemWindows="true" tools:context="com.andevindo.andevindodiary.Activity.DiaryActivity"> <android.support.design.widget.AppBarLayout android:layout_height="wrap_content" android:layout_width="match_parent" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.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"/> </android.support.design.widget.AppBarLayout> <include layout="@layout/content_diary"/> <android.support.design.widget.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_save_white_24dp"/> </android.support.design.widget.CoordinatorLayout>
content_diary.xml
<?xml version="1.0" encoding="utf-8"?> <ScrollView 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" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context="com.andevindo.andevindodiary.Activity.DiaryActivity" tools:showIn="@layout/activity_diary" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" > <android.support.design.widget.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="8dp"> <EditText android:id="@+id/title" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Title"/> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/content" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Content"/> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="8dp"> <EditText android:id="@+id/location" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Location"/> </android.support.design.widget.TextInputLayout> <CheckBox android:id="@+id/update_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" android:text="Update time"/> </LinearLayout> </ScrollView>
Custom Layout
Layout untuk item dari recyclerview
custom_list_diary.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v7.widget.CardView android:id="@+id/card_view" android:layout_width="match_parent" android:layout_height="wrap_content" app:cardElevation="2dp" app:cardUseCompatPadding="true"> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="16dp" android:orientation="vertical"> <TextView android:id="@+id/title" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:text="title" android:fontFamily="@string/font_medium" android:alpha="0.87" android:textSize="20sp"/> <TextView android:id="@+id/content" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginRight="16dp" android:layout_marginBottom="8dp" android:text="content" android:fontFamily="@string/font_regular" android:alpha="0.87" android:textSize="14sp"/> <TextView android:id="@+id/loc_date" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="loc and date" android:fontFamily="@string/font_regular" android:alpha="0.54" android:textSize="12sp"/> </LinearLayout> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|right" android:layout_margin="8dp" android:src="@drawable/ic_mode_edit_white_24dp" app:elevation="0dp" app:fabSize="mini"/> </FrameLayout> </android.support.v7.widget.CardView> </LinearLayout>
Beberapa values yang diperlukan:
colors.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#e91e63</color> <color name="colorPrimaryDark">#c2185b</color> <color name="colorAccent">#aa00ff</color> </resources>
strings.xml
<resources> <string name="app_name">My Diary</string> <string name="action_settings">Settings</string> <string name="title_activity_diary">DiaryActivity</string> <string name="font_medium">sans-serif-medium</string> <string name="font_regular">sans-serif</string> <string name="title_activity_splash_screen">SplashScreenActivity</string> </resources>
styles.xml
<resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style> <style name="AppTheme.NoActionBar"> <item name="windowActionBar">false</item> <item name="windowNoTitle">true</item> </style> <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/> <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/> <style name="AppTheme.Dialog" parent="Theme.AppCompat.Light.Dialog"> <item name="windowActionBar">false</item> <item name="windowNoTitle">true</item> </style> <style name="AppTheme.FullScreen" parent="AppTheme.NoActionBar"> <item name="android:windowFullscreen">true</item> </style> </resources>
styles.xml versi 21
<resources> <style name="AppTheme.NoActionBar"> <item name="windowActionBar">false</item> <item name="windowNoTitle">true</item> <item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:statusBarColor">@android:color/transparent</item> </style> </resources>
Coding Time 😀
Inilah screenshot dari projek saya
Terdapat package Utils yang berisikan sebuah class bernama TimeHelper, berfungsi untuk conversi waktu saat itu ke dalam bentuk String dengan format Jam:Menit Tanggal:Bulan:Tahun.
TimeHelper.java
package com.andevindo.andevindodiary.Utils; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by -H- on 10/24/2015. */ public class TimeHelper { public static String getTimeRightNow(){ SimpleDateFormat desiredFormat = new SimpleDateFormat( "kk:mm dd-MM-yyyy"); return desiredFormat.format(new Date()); } }
Kemudian terdapat package Model, berisikan sebuah class bernama Diary, ini sebagai model dari data diary.
Diary.java
package com.andevindo.andevindodiary.Model; /** * Created by -H- on 10/24/2015. */ public class Diary { public static final String TABLE_NAME = "diary"; public static final String ID = "id"; public static final String TITLE = "title"; public static final String CONTENT = "content"; public static final String DATE = "date"; public static final String LOCATION = "location"; private int mId; private String mTitle; private String mContent; private String mDate; private String mLocation; public int getId() { return mId; } public void setId(int id) { mId = id; } public String getLocation() { return mLocation; } public void setLocation(String location) { mLocation = location; } public String getTitle() { return mTitle; } public void setTitle(String title) { mTitle = title; } public String getContent() { return mContent; } public void setContent(String content) { mContent = content; } public String getDate() { return mDate; } public void setDate(String date) { mDate = date; } }
Kemudian ada package Database, tentunya didalamnya berhubungan dengan database. Terdapat class DatabaseHelper dan DiaryHelper. Database Helper, digunakan untuk membuat database, table diary. Dan juga untuk menempatkan beberapa method untuk CRUD.
DatabaseHelper.java
package com.andevindo.andevindodiary.Database; import android.content.ContentValues; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import com.andevindo.andevindodiary.Model.Diary; /** * Created by -H- on 10/24/2015. */ public class DatabaseHelper extends SQLiteOpenHelper { private static final String sDiaryDB = "DIARY_DB"; private static final int sVersion = 1; private static final String sCreateDiaryTable = "create table " + Diary.TABLE_NAME + "(" + Diary.ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + Diary.TITLE + " TEXT, " + Diary.CONTENT + " TEXT, " + Diary.LOCATION + " TEXT, " + Diary.DATE + " TEXT)"; public DatabaseHelper(Context context) { super(context, sDiaryDB, null, sVersion); } @Override public void onCreate(SQLiteDatabase db) { db.beginTransaction(); db.execSQL(sCreateDiaryTable); db.setTransactionSuccessful(); db.endTransaction(); } public void update(Diary diary, SQLiteDatabase db) { ContentValues contentValues = new ContentValues(); contentValues.put(Diary.TITLE, diary.getTitle()); contentValues.put(Diary.CONTENT, diary.getContent()); contentValues.put(Diary.LOCATION, diary.getLocation()); contentValues.put(Diary.DATE, diary.getDate()); db.update(Diary.TABLE_NAME, contentValues, Diary.ID + "=" + diary.getId(), null); } public void insert(Diary diary, SQLiteDatabase db) { ContentValues contentValues = new ContentValues(); contentValues.put(Diary.TITLE, diary.getTitle()); contentValues.put(Diary.CONTENT, diary.getContent()); contentValues.put(Diary.LOCATION, diary.getLocation()); contentValues.put(Diary.DATE, diary.getDate()); db.insertOrThrow(Diary.TABLE_NAME, null, contentValues); } public void delete(int id, SQLiteDatabase db) { db.delete(Diary.TABLE_NAME, Diary.ID + "=" + id, null); } public void deleteAll(SQLiteDatabase db){ db.delete(Diary.TABLE_NAME, null, null); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
Diary Helper berisikan beberapa method untuk CRUD juga namun dengan beberapa tambahan, seperti beginTransaction yang berfungsi untuk memulai proses query database. Dan juga berisi converter, dari cursor ke diary.
DiaryHelper.java
package com.andevindo.andevindodiary.Database; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import com.andevindo.andevindodiary.Model.Diary; import java.util.ArrayList; import java.util.List; /** * Created by -H- on 10/24/2015. */ public class DiaryHelper { private static SQLiteDatabase getWritableAndOpen(DatabaseHelper databaseHelper){ SQLiteDatabase sqLiteDatabase = databaseHelper.getWritableDatabase(); sqLiteDatabase.beginTransaction(); return sqLiteDatabase; } private static SQLiteDatabase getReadableAndOpen(DatabaseHelper databaseHelper){ SQLiteDatabase sqLiteDatabase = databaseHelper.getReadableDatabase(); sqLiteDatabase.beginTransaction(); return sqLiteDatabase; } private static void closeTransaction(SQLiteDatabase sqLiteDatabase){ sqLiteDatabase.setTransactionSuccessful(); sqLiteDatabase.endTransaction(); } public static List<Diary> getDiaries(Context context){ DatabaseHelper databaseHelper = new DatabaseHelper(context); SQLiteDatabase sqLiteDatabase = getReadableAndOpen(databaseHelper); Cursor cursor = sqLiteDatabase.query(Diary.TABLE_NAME, null, null, null, null, null, Diary.DATE + " DESC"); closeTransaction(sqLiteDatabase); List<Diary> list = convertCursorToList(cursor); cursor.close(); return list; } public static Diary getDiary(Context context, int id){ DatabaseHelper databaseHelper = new DatabaseHelper(context); SQLiteDatabase sqLiteDatabase = getReadableAndOpen(databaseHelper); Cursor cursor = sqLiteDatabase.query(Diary.TABLE_NAME, null, Diary.ID + "=" + id, null, null, null, null); closeTransaction(sqLiteDatabase); cursor.moveToFirst(); Diary diary = convertFromCursor(cursor); cursor.close(); return diary; } public static void addDiary(Context context, Diary diary){ DatabaseHelper databaseHelper = new DatabaseHelper(context); SQLiteDatabase sqLiteDatabase = getWritableAndOpen(databaseHelper); databaseHelper.insert(diary, sqLiteDatabase); closeTransaction(sqLiteDatabase); } public static void updateDiary(Context context, Diary diary){ DatabaseHelper databaseHelper = new DatabaseHelper(context); SQLiteDatabase sqLiteDatabase = getWritableAndOpen(databaseHelper); databaseHelper.update(diary, sqLiteDatabase); closeTransaction(sqLiteDatabase); } public static void deleteDiary(Context context, int id){ DatabaseHelper databaseHelper = new DatabaseHelper(context); SQLiteDatabase sqLiteDatabase = getWritableAndOpen(databaseHelper); databaseHelper.delete(id, sqLiteDatabase); closeTransaction(sqLiteDatabase); } public static void deleteAllDiary(Context context){ DatabaseHelper databaseHelper = new DatabaseHelper(context); SQLiteDatabase sqLiteDatabase = getWritableAndOpen(databaseHelper); databaseHelper.deleteAll(sqLiteDatabase); closeTransaction(sqLiteDatabase); } private static List<Diary> convertCursorToList(Cursor cursor){ List<Diary> list = new ArrayList<>(); if(cursor.getCount()!=0){ cursor.moveToFirst(); do{ list.add(convertFromCursor(cursor)); }while(cursor.moveToNext()); return list; }else{ return list; } } private static Diary convertFromCursor(Cursor cursor){ Diary diary = new Diary(); final int id = cursor.getColumnIndex(Diary.ID); final int title = cursor.getColumnIndex(Diary.TITLE); final int content = cursor.getColumnIndex(Diary.CONTENT); final int location = cursor.getColumnIndex(Diary.LOCATION); final int date = cursor.getColumnIndex(Diary.DATE); diary.setId(cursor.getInt(id)); diary.setTitle(cursor.getString(title)); diary.setContent(cursor.getString(content)); diary.setLocation(cursor.getString(location)); diary.setDate(cursor.getString(date)); return diary; } }
Kemudian terdapat package Adapter, ini berhubungan dengan RecyclerView. Isinya terdapat adapter dan viewholder.
DiaryViewHolder.java
package com.andevindo.andevindodiary.Adapter.ViewHolder; import android.support.design.widget.FloatingActionButton; import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.TextView; import com.andevindo.andevindodiary.Adapter.DiaryAdapter; import com.andevindo.andevindodiary.Model.Diary; import com.andevindo.andevindodiary.R; /** * Created by -H- on 10/24/2015. */ public class DiaryViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { private TextView mTitle, mContent, mLocDate; private FloatingActionButton mFab; private DiaryAdapter.OnItemClickListener mOnItemClickListener; private DiaryAdapter.OnFabClickListener mOnFabClickListener; private Diary mDiary; public DiaryViewHolder(View itemView, DiaryAdapter.OnItemClickListener onItemClickListener, DiaryAdapter.OnFabClickListener onFabClickListener) { super(itemView); mOnItemClickListener = onItemClickListener; mOnFabClickListener = onFabClickListener; mTitle = (TextView) itemView.findViewById(R.id.title); mContent = (TextView) itemView.findViewById(R.id.content); mLocDate = (TextView) itemView.findViewById(R.id.loc_date); mFab = (FloatingActionButton) itemView.findViewById(R.id.fab); mFab.setOnClickListener(this); itemView.setOnClickListener(this); } public void setData(Diary diary) { mDiary = diary; mTitle.setText(diary.getTitle()); mContent.setText((diary.getContent().length() < 75) ? diary.getContent():diary.getContent().substring(0,74) + "..."); mLocDate.setText(diary.getLocation() + ", " + diary.getDate()); } @Override public void onClick(View view) { if (view.getId() == R.id.fab) { mOnFabClickListener.onFabCliCk(mDiary); } else { mOnItemClickListener.onItemClick(mDiary); } } }
DiaryAdapter.java
package com.andevindo.andevindodiary.Adapter; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.ViewGroup; import com.andevindo.andevindodiary.Adapter.ViewHolder.DiaryViewHolder; import com.andevindo.andevindodiary.Model.Diary; import com.andevindo.andevindodiary.R; import java.util.List; /** * Created by -H- on 10/24/2015. */ public class DiaryAdapter extends RecyclerView.Adapter<DiaryViewHolder> { private List<Diary> mList; private Context mContext; private OnItemClickListener mOnItemClickListener; private OnFabClickListener mOnFabClickListener; public DiaryAdapter(List<Diary> list, Context context, OnItemClickListener onItemClickListener, OnFabClickListener onFabClickListener) { mList = list; mContext = context; mOnItemClickListener = onItemClickListener; mOnFabClickListener = onFabClickListener; } public DiaryAdapter(Context context, OnItemClickListener onItemClickListener, OnFabClickListener onFabClickListener) { mContext = context; mOnItemClickListener = onItemClickListener; mOnFabClickListener = onFabClickListener; } public void setData(List<Diary> list){ mList = list; notifyDataSetChanged(); } @Override public DiaryViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new DiaryViewHolder(LayoutInflater.from(mContext).inflate(R.layout.custom_list_diary, parent, false), mOnItemClickListener, mOnFabClickListener); } @Override public void onBindViewHolder(DiaryViewHolder holder, int position) { holder.setData(mList.get(position)); } @Override public int getItemCount() { if(mList == null){ return 0; }else{ return mList.size(); } } public interface OnItemClickListener{ void onItemClick(Diary diary); } public interface OnFabClickListener{ void onFabCliCk(Diary diary); } }
Yang terakhir adalah package Activity.
DetailActivity.java
package com.andevindo.andevindodiary.Activity; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.widget.TextView; import com.andevindo.andevindodiary.R; public class DetailActivity extends AppCompatActivity { private TextView mTitle, mContent, mLocDate; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_detail); mTitle = (TextView)findViewById(R.id.title); mContent = (TextView)findViewById(R.id.content); mLocDate = (TextView)findViewById(R.id.loc_date); //Mendapatkan data dari MainActivity dan ditampilkan dalam TextView; mTitle.setText(getIntent().getExtras().getString("title")); mContent.setText(getIntent().getExtras().getString("content")); mLocDate.setText(getIntent().getExtras().getString("location") + ", " + getIntent().getExtras().getString("date")); } }
DiaryActivity.java
package com.andevindo.andevindodiary.Activity; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.CheckBox; import android.widget.EditText; import com.andevindo.andevindodiary.Database.DiaryHelper; import com.andevindo.andevindodiary.Model.Diary; import com.andevindo.andevindodiary.R; import com.andevindo.andevindodiary.Utils.TimeHelper; public class DiaryActivity extends AppCompatActivity { private EditText mTitle, mContent, mLocation; private String mStringTitle, mStringContent, mStringLocation, mStringDate, mStringTag; private int mId; private CheckBox mUpdateTime; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_diary); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //Jika respon yang didapat dari MainActivity adalah untuk membuat diary baru if (mStringTag.equals("create")) { create(); //Respon untuk update diary } else if (mStringTag.equals("update")) { update(); } //Mengembalikan nilai RESULT_OK untuk menandakan bahwa proses sukses setResult(RESULT_OK); finish(); } }); mUpdateTime = (CheckBox) findViewById(R.id.update_time); mTitle = (EditText) findViewById(R.id.title); mContent = (EditText) findViewById(R.id.content); mLocation = (EditText) findViewById(R.id.location); mStringTag = getIntent().getExtras().getString("tag"); //Mengatur tampilan untuk kategori update if (mStringTag.equals("update")) { getSupportActionBar().setTitle("Edit diary"); mUpdateTime.setVisibility(CheckBox.VISIBLE); mId = getIntent().getExtras().getInt("id"); Log.d("id", mId + ""); Diary diary = DiaryHelper.getDiary(getApplicationContext(), mId); mStringTitle = diary.getTitle(); mStringContent = diary.getContent(); mStringLocation = diary.getLocation(); mStringDate = diary.getDate(); mTitle.setText(mStringTitle); mContent.setText(mStringContent); mLocation.setText(mStringLocation); } else { getSupportActionBar().setTitle("New diary"); mUpdateTime.setVisibility(CheckBox.GONE); } } //Mendapatkan data dari edittext, lalu update database void update() { Diary diary = new Diary(); diary.setId(mId); diary.setTitle(mTitle.getText().toString()); diary.setContent(mContent.getText().toString()); diary.setLocation(mLocation.getText().toString()); if (mUpdateTime.isChecked()) diary.setDate(TimeHelper.getTimeRightNow()); else diary.setDate(mStringDate); DiaryHelper.updateDiary(getApplicationContext(), diary); } //Mendapatkan data dari edittext, lalu create diary baru void create() { Diary diary = new Diary(); diary.setTitle(mTitle.getText().toString()); diary.setContent(mContent.getText().toString()); diary.setLocation(mLocation.getText().toString()); diary.setDate(TimeHelper.getTimeRightNow()); DiaryHelper.addDiary(getApplicationContext(), diary); } //Menampilkan actionbar menu @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); if (mStringTag.equals("update")) inflater.inflate(R.menu.menu_main, menu); return true; } //Respon untuk actionbar menu @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.action_delete) { DiaryHelper.deleteDiary(getApplicationContext(), mId); setResult(RESULT_OK); finish(); return true; } else if (item.getItemId() == android.R.id.home) { setResult(RESULT_CANCELED); finish(); return true; } return false; } }
MainActivity.java
package com.andevindo.andevindodiary.Activity; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import com.andevindo.andevindodiary.Adapter.DiaryAdapter; import com.andevindo.andevindodiary.Database.DiaryHelper; import com.andevindo.andevindodiary.Model.Diary; import com.andevindo.andevindodiary.R; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity implements DiaryAdapter.OnItemClickListener, DiaryAdapter.OnFabClickListener { private RecyclerView mRecyclerView; private DiaryAdapter mDiaryAdapter; private List<Diary> mList = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //Menggunakan for result karena membutuhkan feedback dari DiaryActivity Intent intent = new Intent(MainActivity.this, DiaryActivity.class); intent.putExtra("tag", "create"); startActivityForResult(intent, 100); } }); mRecyclerView = (RecyclerView) findViewById(R.id.recycler); mDiaryAdapter = new DiaryAdapter(MainActivity.this, this, this); mRecyclerView.setAdapter(mDiaryAdapter); mRecyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext())); //Update list dengan asynctask agar tidak mengganggu thread utama new LoadDatabase().execute(); } //Sebagai respon dari DiaryActivity @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if(requestCode==100){ if(resultCode==RESULT_OK){ new LoadDatabase().execute(); } } } //Respon dari fab button yang terdapat dalam item dari recyclerview @Override public void onFabCliCk(Diary diary) { Intent intent = new Intent(MainActivity.this, DiaryActivity.class); intent.putExtra("tag", "update"); intent.putExtra("id", diary.getId()); startActivityForResult(intent, 100); } //Respon dari item yang terdapat dalam item dari recyclerview @Override public void onItemClick(Diary diary) { Intent intent = new Intent(MainActivity.this, DetailActivity.class); intent.putExtra("title", diary.getTitle()); intent.putExtra("content", diary.getContent()); intent.putExtra("location", diary.getLocation()); intent.putExtra("date", diary.getDate()); startActivity(intent); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { if(item.getItemId()==R.id.action_delete){ DiaryHelper.deleteAllDiary(getApplicationContext()); mDiaryAdapter.setData(null); return true; } return false; } //Class untuk update data list class LoadDatabase extends AsyncTask<Void, Void ,List<Diary>>{ @Override protected List<Diary> doInBackground(Void... params) { return DiaryHelper.getDiaries(MainActivity.this); } @Override protected void onPostExecute(List<Diary> diaries) { mDiaryAdapter.setData(diaries); } } }
SplashScreenActivity.java
package com.andevindo.andevindodiary.Activity; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.support.v7.app.AppCompatActivity; import com.andevindo.andevindodiary.R; public class SplashScreenActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_splash_screen); //Menunggu 3 seconds kemudian membuka MainActivity.class new Handler().postDelayed(new Runnable() { @Override public void run() { startActivity(new Intent(SplashScreenActivity.this, MainActivity.class)); finish(); } }, 3000); } }
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.andevindo.andevindodiary" > <!-- To auto-complete the email text field in the login form with the user's emails --> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.READ_PROFILE" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme" > <activity android:name=".Activity.MainActivity" android:label="@string/app_name" android:theme="@style/AppTheme.NoActionBar" > </activity> <activity android:name=".Activity.DiaryActivity" android:label="@string/title_activity_diary" android:theme="@style/AppTheme.NoActionBar" > </activity> <activity android:name=".Activity.DetailActivity" android:theme="@style/AppTheme.Dialog" > </activity> <activity android:name=".Activity.SplashScreenActivity" android:label="@string/app_name" android:theme="@style/AppTheme.FullScreen" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
Download Apk