0% found this document useful (0 votes)
181 views25 pages

CRUD (Create, Read, Update, Dan Delete) With SQL LITE The Notes App

This document discusses creating a simple Notes app with SQLite database storage using CRUD (Create, Read, Update, Delete) operations. It includes: 1. Creating the project structure and dependencies 2. Defining a Note model class with table schema 3. Creating a DatabaseHelper class extending SQLiteOpenHelper to perform CRUD operations like inserting, getting, and retrieving all notes from the database.

Uploaded by

wahyyyuu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
181 views25 pages

CRUD (Create, Read, Update, Dan Delete) With SQL LITE The Notes App

This document discusses creating a simple Notes app with SQLite database storage using CRUD (Create, Read, Update, Delete) operations. It includes: 1. Creating the project structure and dependencies 2. Defining a Note model class with table schema 3. Creating a DatabaseHelper class extending SQLiteOpenHelper to perform CRUD operations like inserting, getting, and retrieving all notes from the database.

Uploaded by

wahyyyuu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 25

CHAPTER 7, 8, 9 : SQL LITE

CRUD (Create, Read, Update, dan Delete) : The Notes App


This practicum to create a simple Notes App with SQLite as database storage. The
app will be very minimal and will have only one screen to manage the notes.

1. Creating New Project


Create a new project in Android Studio from File ⇒ New Project and select
Empty Activity from the templates

Open build.gradle under app directory and add RecyclerView dependency. The
RecyclerView will be used to display the Notes in list manner.

build.gradle
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
// ..

implementation 'com.android.support:recyclerview-v7:26.1.0'
}

2. Creating Input Menu


MainActivity.java
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
return true;
}
menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_input"
android:orderInCategory="100"
android:title="Input"
android:icon="@android:drawable/ic_menu_add"
app:showAsAction="always" />
</menu>

Add the below resources to colors.xml, dimens.xml and strings.xml


color.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#008577</color>
<color name="colorPrimaryDark">#00574B</color>
<color name="colorAccent">#D81B60</color>

1
<color name="msg_no_notes">#999</color>
<color name="hint_enter_note">#89c3c3c3</color>
<color name="timestamp">#858585</color>
<color name="note_list_text">#232323</color>
</resources>

dimens.xml
<resources>
<dimen name="fab_margin">16dp</dimen>
<dimen name="activity_margin">16dp</dimen>
<dimen name="dot_margin_right">10dp</dimen>
<dimen name="msg_no_notes">26sp</dimen>
<dimen name="margin_top_no_notes">120dp</dimen>
<dimen name="lbl_new_note_title">20sp</dimen>
<dimen name="dimen_10">10dp</dimen>
<dimen name="input_new_note">20sp</dimen>
<dimen name="dot_height">30dp</dimen>
<dimen name="dot_text_size">40sp</dimen>
<dimen name="timestamp">14sp</dimen>
<dimen name="note_list_text">18sp</dimen>
</resources>

string.xml
<resources>
<string name="app_name">CRUD SQL LITE APPS</string>
<string name="action_settings">Settings</string>
<string name="activity_title_home">Notes</string>
<string name="msg_no_notes">No notes found!</string>
<string name="lbl_new_note_title">New Note</string>
<string name="lbl_edit_note_title">Edit Note</string>
<string name="hint_enter_note">Enter your note!</string>
</resources>

Quickly create few packages named database, database/model, utils and view.
Below is the final project structure and files we gonna need.

2
3. Writing SQLite Helper Class
We need to create a class that extends from SQLiteOpenHelper. This class perform
CRUD operations (Create, Read, Update and Delete) on the database.

Under database/model package, create a class named Note.java. In this class we


define the SQLite table name, column names and create table SQL query along
with getter / setter methods.
• The ‘notes’ table needs three columns i.e ‘id’, ‘note’ and ‘timestamp’.
• Column ‘id’ is defined as Primary Key and Auto Increment which means each
note will be uniquely identified by its id.
• Column ‘note’ stores the actual note text.
• Column ‘timestamp’ stores the date and time of the note that is created.

Note.java
package com.dipanegara.crudsqlliteapps.database.model;

public class Note {


public static final String TABLE_NAME = "notes";
public static final String COLUMN_ID = "id";
public static final String COLUMN_NOTE = "note";
public static final String COLUMN_TIMESTAMP = "timestamp";

private int id;


private String note;
private String timestamp;

// Create table SQL query


public static final String CREATE_TABLE =
"CREATE TABLE " + TABLE_NAME + "("
+ COLUMN_ID + " INTEGER PRIMARY KEY
AUTOINCREMENT,"
+ COLUMN_NOTE + " TEXT,"
+ COLUMN_TIMESTAMP + " DATETIME DEFAULT
CURRENT_TIMESTAMP"
+ ")";
public Note() {

public Note(int id, String note, String timestamp) {


this.id = id;
this.note = note;
this.timestamp = timestamp;
}

public int getId() {


return id;
3
}

public String getNote() {


return note;
}

public void setNote(String note) {


this.note = note;
}

public String getTimestamp() {


return timestamp;
}

public void setId(int id) {


this.id = id;
}

public void setTimestamp(String timestamp) {


this.timestamp = timestamp;
}
}

Under database package, create a class named DatabaseHelper.java and


extend the class from SQLiteOpenHelper. This class holds the database
related methods to perform the CRUD operations.
• onCreate() will be called only once when the app is installed. In this method, we
execute the create table sql statements to create necessary tables.
• onUpgrade() called when an update is released. You need to modify the
DATABASE_VERSION in order to execute this method. You have to take care
of database migrations here without loosing the older data if necessary. For now,
we just drop the older tables and recreate them again.

DatabaseHelper.java
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import com.dipanegara.crudsqlliteapps.database.model.Note;

public class DatabaseHelper extends SQLiteOpenHelper {

// Database Version
private static final int DATABASE_VERSION = 1;

// Database Name
private static final String DATABASE_NAME = "notes_db";

4
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

// Creating Tables
@Override
public void onCreate(SQLiteDatabase db) {

// create notes table


db.execSQL(Note.CREATE_TABLE);
}

// Upgrading database
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int
newVersion) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + Note.TABLE_NAME);

// Create tables again


onCreate(db);
}
}

Now we’ll see the methods required to store or retrieve the notes. Add the
following methods to same class.
Inserting Note
Inserting data requires getting writable instance (getReadableDatabase()) on
database. Below, we are inserting new note in database.
• ContentValues() is used to define the column name and its data to be stored.
Here, we are just setting the note value only ignoring ‘id’ and ‘timestamp’ as
these two will be inserted automatically.
• Every time the database connection has to be closed once you are done with
database access. Calling db.close() closes the connection.
• Once the note is inserted, the ‘id’ of newly inserted note will be returned.

public long insertNote(String note) {


// get writable database as we want to write data
SQLiteDatabase db = this.getWritableDatabase();

ContentValues values = new ContentValues();


// ‘id’ and ‘timestamp’ will be inserted automatically.
// no need to add them
values.put(Note.COLUMN_NOTE, note);

// insert row
long id = db.insert(Note.TABLE_NAME, null, values);

// close db connection
5
db.close();

// return newly inserted row id


return id;
}

Reading Notes
Reading data requires only read access (getReadableDatabase()) on the database.
• getNote() takes already existed note ‘id’ and fetches the note object.
• getAllNotes() fetches all the notes in descending order by timestamp.
• getNotesCount() returns the count of notes stored in database.

public Note getNote(long id) {


// get readable database as we are not inserting anything
SQLiteDatabase db = this.getReadableDatabase();

Cursor cursor = db.query(Note.TABLE_NAME,


new String[]{Note.COLUMN_ID, Note.COLUMN_NOTE,
Note.COLUMN_TIMESTAMP},
Note.COLUMN_ID + "=?",
new String[]{String.valueOf(id)}, null, null, null,
null);

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

// prepare note object


Note note = new Note(
cursor.getInt(cursor.getColumnIndex(Note.COLUMN_ID)),

cursor.getString(cursor.getColumnIndex(Note.COLUMN_NOTE)),

cursor.getString(cursor.getColumnIndex(Note.COLUMN_TIMESTAMP)));

// close the db connection


cursor.close();

return note;
}

public List<Note> getAllNotes() {


List<Note> notes = new ArrayList<>();

// Select All Query


String selectQuery = "SELECT * FROM " + Note.TABLE_NAME + "
ORDER BY " +
Note.COLUMN_TIMESTAMP + " DESC";

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

6
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
Note note = new Note();

note.setId(cursor.getInt(cursor.getColumnIndex(Note.COLUMN_ID)));

note.setNote(cursor.getString(cursor.getColumnIndex(Note.COLUMN_NOT
E)));

note.setTimestamp(cursor.getString(cursor.getColumnIndex(Note.COLUM
N_TIMESTAMP)));

notes.add(note);
} while (cursor.moveToNext());
}

// close db connection
db.close();

// return notes list


return notes;
}

public int getNotesCount() {


String countQuery = "SELECT * FROM " + Note.TABLE_NAME;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(countQuery, null);

int count = cursor.getCount();


cursor.close();

// return count
return count;
}

Updating Note
Updating data again requires writable access. Below the note is updated by its ‘id’.
public int updateNote(Note note) {
SQLiteDatabase db = this.getWritableDatabase();

ContentValues values = new ContentValues();


values.put(Note.COLUMN_NOTE, note.getNote());

// updating row
return db.update(Note.TABLE_NAME, values, Note.COLUMN_ID + " =
?",
new String[]{String.valueOf(note.getId())});
}

7
Deleting Note
Deleting data also requires writable access. Below method deletes a note by finding
its ‘id’.
public void deleteNote(Note note) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(Note.TABLE_NAME, Note.COLUMN_ID + " = ?",
new String[]{String.valueOf(note.getId())});
db.close();
}

After adding all the methods, the DatabaseHelper.java class should be like this.
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import java.util.ArrayList;
import java.util.List;

import com.dipanegara.crudsqlliteapps.database.model.Note;

public class DatabaseHelper extends SQLiteOpenHelper {

// Database Version
private static final int DATABASE_VERSION = 1;

// Database Name
private static final String DATABASE_NAME = "notes_db";

public DatabaseHelper(Context context) {


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

// Creating Tables
@Override
public void onCreate(SQLiteDatabase db) {

// create notes table


db.execSQL(Note.CREATE_TABLE);
}

// Upgrading database
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int
newVersion) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + Note.TABLE_NAME);

// Create tables again


onCreate(db);
}
8
public long insertNote(String note) {
// get writable database as we want to write data
SQLiteDatabase db = this.getWritableDatabase();

ContentValues values = new ContentValues();


// ‘id’ and ‘timestamp’ will be inserted automatically.
// no need to add them
values.put(Note.COLUMN_NOTE, note);

// insert row
long id = db.insert(Note.TABLE_NAME, null, values);

// close db connection
db.close();

// return newly inserted row id


return id;
}

public Note getNote(long id) {


// get readable database as we are not inserting anything
SQLiteDatabase db = this.getReadableDatabase();

Cursor cursor = db.query(Note.TABLE_NAME,


new String[]{Note.COLUMN_ID, Note.COLUMN_NOTE,
Note.COLUMN_TIMESTAMP},
Note.COLUMN_ID + "=?",
new String[]{String.valueOf(id)}, null, null, null,
null);

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

// prepare note object


Note note = new Note(

cursor.getInt(cursor.getColumnIndex(Note.COLUMN_ID)),

cursor.getString(cursor.getColumnIndex(Note.COLUMN_NOTE)),

cursor.getString(cursor.getColumnIndex(Note.COLUMN_TIMESTAMP)));

// close the db connection


cursor.close();

return note;
}

public List<Note> getAllNotes() {


List<Note> notes = new ArrayList<>();

// Select All Query


String selectQuery = "SELECT * FROM " + Note.TABLE_NAME +
9
" ORDER BY " +
Note.COLUMN_TIMESTAMP + " DESC";

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

// looping through all rows and adding to list


if (cursor.moveToFirst()) {
do {
Note note = new Note();

note.setId(cursor.getInt(cursor.getColumnIndex(Note.COLUMN_ID)));

note.setNote(cursor.getString(cursor.getColumnIndex(Note.COLUMN_NOT
E)));

note.setTimestamp(cursor.getString(cursor.getColumnIndex(Note.COLUM
N_TIMESTAMP)));

notes.add(note);
} while (cursor.moveToNext());
}

// close db connection
db.close();

// return notes list


return notes;
}

public int getNotesCount() {


String countQuery = "SELECT * FROM " + Note.TABLE_NAME;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(countQuery, null);

int count = cursor.getCount();


cursor.close();

// return count
return count;
}

public int updateNote(Note note) {


SQLiteDatabase db = this.getWritableDatabase();

ContentValues values = new ContentValues();


values.put(Note.COLUMN_NOTE, note.getNote());

// updating row
return db.update(Note.TABLE_NAME, values, Note.COLUMN_ID +
" = ?",
new String[]{String.valueOf(note.getId())});
}
10
public void deleteNote(Note note) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(Note.TABLE_NAME, Note.COLUMN_ID + " = ?",
new String[]{String.valueOf(note.getId())});
db.close();
}
}

Under utils package, create two classes named RecyclerTouchListener.java and


MyDividerItemDecoration.java
• RecyclerTouchListener class adds touch event to RecyclerView row.
• MyDividerItemDecoration class adds divider line between rows.

RecyclerTouchListener.java
import android.content.Context;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;

import androidx.recyclerview.widget.RecyclerView;

public class RecyclerTouchListener implements


RecyclerView.OnItemTouchListener {

private ClickListener clicklistener;


private GestureDetector gestureDetector;

public RecyclerTouchListener(Context context, final


RecyclerView recycleView, final ClickListener clicklistener) {

this.clicklistener = clicklistener;
gestureDetector = new GestureDetector(context, new
GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}

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

11
@Override
public boolean onInterceptTouchEvent(RecyclerView rv,
MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(), e.getY());
if (child != null && clicklistener != null &&
gestureDetector.onTouchEvent(e)) {
clicklistener.onClick(child,
rv.getChildAdapterPosition(child));
}
return false;
}

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

@Override
public void onRequestDisallowInterceptTouchEvent(boolean
disallowIntercept) {

public interface ClickListener {


void onClick(View view, int position);

void onLongClick(View view, int position);


}
}

MyDividerItemDecoration.java
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.TypedValue;
import android.view.View;

import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

public class MyDividerItemDecoration 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 =
12
LinearLayoutManager.VERTICAL;

private Drawable mDivider;


private int mOrientation;
private Context context;
private int margin;

public MyDividerItemDecoration(Context context, int


orientation, int margin) {
this.context = context;
this.margin = margin;
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 + dpToPx(margin), top, right -
dpToPx(margin), bottom);
mDivider.draw(c);
}
13
}

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 + dpToPx(margin), right,
bottom - dpToPx(margin));
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);
}
}

private int dpToPx(int dp) {


Resources r = context.getResources();
return
Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dp, r.getDisplayMetrics()));
}
}

4. Adding Notes UI
Now we have the database helper class ready. Let’s quickly build the main interface
and integrate it with the database.
First we need an adapter to display the notes in list manner. For this, we need a
layout file and Adapter class.

Create new xml layout named note_list_row.xml. This layout holds the design of
single note item in the list.
note_list_row.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout

14
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:foreground="?attr/selectableItemBackground"
android:paddingBottom="@dimen/dimen_10"
android:paddingLeft="@dimen/activity_margin"
android:paddingRight="@dimen/activity_margin"
android:paddingTop="@dimen/dimen_10">

<TextView
android:id="@+id/dot"
android:layout_width="wrap_content"
android:layout_height="@dimen/dot_height"
android:layout_marginRight="@dimen/dot_margin_right"
android:layout_marginTop="@dimen/dimen_10"
android:includeFontPadding="false"
android:textColor="@color/colorAccent"
android:lineSpacingExtra="0dp"
android:textSize="@dimen/dot_text_size" />

<TextView
android:id="@+id/timestamp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/dot"
android:textColor="@color/timestamp"
android:textSize="@dimen/timestamp" />

<TextView
android:id="@+id/note"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/timestamp"
android:layout_toRightOf="@id/dot"
android:textColor="@color/note_list_text"
android:textSize="@dimen/note_list_text" />

</RelativeLayout>

Under view package, create a class named NotesAdapter.java. This adapter class
renders the RecyclerView with defined layout and data set.

NotesAdapter.java
import android.content.Context;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.recyclerview.widget.RecyclerView;
15
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import com.dipanegara.crudsqlliteapps.R;
import com.dipanegara.crudsqlliteapps.database.model.Note;

class NotesAdapter extends


RecyclerView.Adapter<NotesAdapter.MyViewHolder> {

private Context context;


private List<Note> notesList;

public class MyViewHolder extends RecyclerView.ViewHolder {


public TextView note;
public TextView dot;
public TextView timestamp;

public MyViewHolder(View view) {


super(view);
note = view.findViewById(R.id.note);
dot = view.findViewById(R.id.dot);
timestamp = view.findViewById(R.id.timestamp);
}
}

public NotesAdapter(Context context, List<Note> notesList) {


this.context = context;
this.notesList = notesList;
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int
viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.note_list_row, parent, false);

return new MyViewHolder(itemView);


}

@Override
public void onBindViewHolder(MyViewHolder holder, int position)
{
Note note = notesList.get(position);

holder.note.setText(note.getNote());

// Displaying dot from HTML character code


holder.dot.setText(Html.fromHtml("&#8226;"));

// Formatting and displaying timestamp


16
holder.timestamp.setText(formatDate(note.getTimestamp()));
}

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

/**
* Formatting timestamp to `MMM d` format
* Input: 2018-02-21 00:15:42
* Output: Feb 21
*/
private String formatDate(String dateStr) {
try {
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd
HH:mm:ss");
Date date = fmt.parse(dateStr);
SimpleDateFormat fmtOut = new SimpleDateFormat("MMM
d");
return fmtOut.format(date);
} catch (ParseException e) {

return "";
}
}

5. Adding Create / Edit Note Dialog


If you observe the app design, a note is created or updated using a Dialog. So, we
need to create a custom layout with EditText input and inflate it in AlertDialog.
Create another layout named note_dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingLeft="@dimen/activity_margin"
android:paddingRight="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin">

<TextView android:id="@+id/dialog_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/dimen_10"
android:fontFamily="sans-serif-medium"
android:lineSpacingExtra="8sp"
android:text="@string/lbl_new_note_title"
android:textColor="@color/colorAccent"

17
android:textSize="@dimen/lbl_new_note_title"
android:textStyle="normal" />

<EditText
android:id="@+id/note"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:gravity="top"
android:hint="@string/hint_enter_note"
android:inputType="textCapSentences|textMultiLine"
android:lines="4"
android:textColorHint="@color/hint_enter_note"
android:textSize="@dimen/input_new_note" />

</LinearLayout>

Open the layout files of main activity (activity_main.xml) and add RecyclerView
widget. I am also changing the icon of FAB here.

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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=".view.MainActivity"
tools:showIn="@layout/activity_main">

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

<TextView
android:id="@+id/empty_notes_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/margin_top_no_notes"
android:fontFamily="sans-serif-light"
android:text="@string/msg_no_notes"
android:textColor="@color/msg_no_notes"
android:textSize="@dimen/msg_no_notes" />

</RelativeLayout>

18
Finally open MainActivity.java and do the below changes.
• showNoteDialog() open the alert dialog to create new note. This dialog will be
shown by tapping FAB.
• createNote() inserts new note in database and adds the newly inserted note in
RecyclerView list.
• showActionsDialog() shows a dialog with Edit and Delete options. This dialog
can be invoked by long pressing the note in the list.
• Selecting Edit, opens the update note dialog with already existed note text. You
can modify the note text and update it in database by calling updateNote()
method.
• deleteNote() deletes a note from database. The deleted note is again removed
from list by calling notifyItemRemoved() on adapter.
• toggleEmptyNotes() toggles the visibility of notes and empty note view
depending on the count (db.getNotesCount() > 0) of notes.

MainActivity.java
package com.dipanegara.crudsqlliteapps.view;

import androidx.appcompat.app.AppCompatActivity;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.dipanegara.crudsqlliteapps.R;
import com.dipanegara.crudsqlliteapps.database.DatabaseHelper;
import com.dipanegara.crudsqlliteapps.database.model.Note;
import
com.dipanegara.crudsqlliteapps.utils.MyDividerItemDecoration;
import com.dipanegara.crudsqlliteapps.utils.RecyclerTouchListener;

import java.util.ArrayList;
19
import java.util.List;

public class MainActivity extends AppCompatActivity {


private NotesAdapter mAdapter;
private List<Note> notesList = new ArrayList<>();
private CoordinatorLayout coordinatorLayout;
private RecyclerView recyclerView;
private TextView noNotesView;

private DatabaseHelper db;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

recyclerView = findViewById(R.id.recycler_view);
noNotesView = findViewById(R.id.empty_notes_view);

db = new DatabaseHelper(this);
notesList.addAll(db.getAllNotes());

mAdapter = new NotesAdapter(this, notesList);


RecyclerView.LayoutManager mLayoutManager = new
LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.addItemDecoration(new
MyDividerItemDecoration(this, LinearLayoutManager.VERTICAL, 16));
recyclerView.setAdapter(mAdapter);

toggleEmptyNotes();

/**
* On long press on RecyclerView item, open alert dialog
* with options to choose
* Edit and Delete
* */
recyclerView.addOnItemTouchListener(new
RecyclerTouchListener(this,
recyclerView, new
RecyclerTouchListener.ClickListener() {
@Override
public void onClick(View view, final int position) {
}

@Override
public void onLongClick(View view, int position) {
showActionsDialog(position);
}
}));

20
/**
* Inserting new note in db
* and refreshing the list
*/
private void createNote(String note) {
// inserting note in db and getting
// newly inserted note id
long id = db.insertNote(note);

// get the newly inserted note from db


Note n = db.getNote(id);

if (n != null) {
// adding new note to array list at 0 position
notesList.add(0, n);

// refreshing the list


mAdapter.notifyDataSetChanged();

toggleEmptyNotes();
}
}

/**
* Updating note in db and updating
* item in the list by its position
*/
private void updateNote(String note, int position) {
Note n = notesList.get(position);
// updating note text
n.setNote(note);

// updating note in db
db.updateNote(n);

// refreshing the list


notesList.set(position, n);
mAdapter.notifyItemChanged(position);
toggleEmptyNotes();
}

/**
* Deleting note from SQLite and removing the
* item from the list by its position
*/
private void deleteNote(int position) {
// deleting the note from db
db.deleteNote(notesList.get(position));

// removing the note from the list


notesList.remove(position);
mAdapter.notifyItemRemoved(position);

toggleEmptyNotes();
21
}

/**
* Opens dialog with Edit - Delete options
* Edit - 0
* Delete - 0
*/
private void showActionsDialog(final int position) {
CharSequence colors[] = new CharSequence[]{"Edit",
"Delete"};

AlertDialog.Builder builder = new


AlertDialog.Builder(this);
builder.setTitle("Choose option");
builder.setItems(colors, new
DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which)
{
if (which == 0) {
showNoteDialog(true, notesList.get(position),
position);
} else {
deleteNote(position);
}
}
});
builder.show();
}
/**
* Shows alert dialog with EditText options to enter / edit
* a note.
* when shouldUpdate=true, it automatically displays old note
and changes the
* button text to UPDATE
*/
private void showNoteDialog(final boolean shouldUpdate, final
Note note, final int position) {
LayoutInflater layoutInflaterAndroid =
LayoutInflater.from(getApplicationContext());
View view =
layoutInflaterAndroid.inflate(R.layout.note_dialog, null);

AlertDialog.Builder alertDialogBuilderUserInput = new


AlertDialog.Builder(MainActivity.this);
alertDialogBuilderUserInput.setView(view);

final EditText inputNote = view.findViewById(R.id.note);


TextView dialogTitle =
view.findViewById(R.id.dialog_title);
dialogTitle.setText(!shouldUpdate ?
getString(R.string.lbl_new_note_title) :
getString(R.string.lbl_edit_note_title));

22
if (shouldUpdate && note != null) {
inputNote.setText(note.getNote());
}
alertDialogBuilderUserInput
.setCancelable(false)
.setPositiveButton(shouldUpdate ? "update" :
"save", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogBox,
int id) {

}
})
.setNegativeButton("cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface
dialogBox, int id) {
dialogBox.cancel();
}
});

final AlertDialog alertDialog =


alertDialogBuilderUserInput.create();
alertDialog.show();

alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListen
er(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Show toast message when no text is entered
if
(TextUtils.isEmpty(inputNote.getText().toString())) {
Toast.makeText(MainActivity.this, "Enter
note!", Toast.LENGTH_SHORT).show();
return;
} else {
alertDialog.dismiss();
}

// check if user updating note


if (shouldUpdate && note != null) {
// update note by it's id
updateNote(inputNote.getText().toString(),
position);
} else {
// create new note
createNote(inputNote.getText().toString());
}
}
});
}

/**
* Toggling list and empty notes view
*/
23
private void toggleEmptyNotes() {
// you can check notesList.size() > 0

if (db.getNotesCount() > 0) {
noNotesView.setVisibility(View.GONE);
} else {
noNotesView.setVisibility(View.VISIBLE);
}
}

@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, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_input) {
showNoteDialog(false, null, -1);
return true;
}
return super.onOptionsItemSelected(item);
}
}

Result
Insert Data :

24
Update Data :

Delete Data :

Refrence :
https://www.androidhive.info/2011/11/android-sqlite-database-
tutorial/

25

You might also like