SQLite Kotlin – Notes App – Android Studio Tutorial
In this tutorial we will make a "Notes App" using SQLite and Kotlin.
It will contain following features.
✓Enter Data
✓Retrieve Data in ListView
✓Update/Edit Data
✓Delete Data
✓Search Data
✓Copy Data
✓Share Data
It will contain following features.
✓Enter Data
✓Retrieve Data in ListView
✓Update/Edit Data
✓Delete Data
✓Search Data
✓Copy Data
✓Share Data
Step 01: Create a new Project or open new project
Step 02: Create layout resource file under res>layout folder
Step 03: Create new "Android Resource Directory" by clicking "res>New>Android Resource Directory", choose menu from Resource type
Step 04: Create menu_main.xml by clicking "menu>New>Menu resource file"
Step 05: Create empty Activity name it as "AddNoteActivity.kt"
Step 06: Create Class Note.kt
Step 07: Create Class DbManager.kt
Step 08: Source Code
build.gradle(module:App)
apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' android { compileSdkVersion 27 defaultConfig { applicationId "com.blogspot.atifsoftwares.sqlitecrud_notesapp_kotlin" minSdkVersion 16 targetSdkVersion 27 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" implementation 'com.android.support:appcompat-v7:27.1.1' implementation 'com.android.support:cardview-v7:27.1.1' implementation 'com.android.support.constraint:constraint-layout:1.1.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' }
menu_main.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_settings" android:title="settings" /> <item android:id="@+id/app_bar_search" android:icon="@drawable/ic_action_search" android:title="Search" app:actionViewClass="android.support.v7.widget.SearchView" app:showAsAction="always" /> <item android:id="@+id/addNote" android:icon="@drawable/ic_action_add" android:title="Add Nore" app:showAsAction="always" /> </menu> |
colors.xml
row.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#0488d1</color> <color name="colorPrimaryDark">#0477bd</color> <color name="colorAccent">#0488d1</color> <color name="gray">#e8e8e8</color> <color name="white">#fff</color> <color name="black">#000</color> </resources>
row.xml
<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView 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="wrap_content" app:cardBackgroundColor="@color/white" app:cardCornerRadius="3dp" app:cardElevation="3dp" app:cardUseCompatPadding="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp" android:gravity="end|bottom" android:orientation="vertical"> <TextView android:id="@+id/titleTv" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Title" android:textColor="@color/colorPrimary" android:textSize="22sp" android:textStyle="bold" /> <TextView android:id="@+id/descTv" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="There may be a very long description of the note" android:textSize="18sp" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginBottom="3dp" android:layout_marginTop="2dp" android:background="@color/colorPrimaryDark" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="end" android:orientation="horizontal"> <ImageButton android:id="@+id/deleteBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="5dp" android:layout_marginRight="5dp" android:background="@null" android:src="@drawable/ic_action_delete" /> <ImageButton android:id="@+id/editBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="5dp" android:layout_marginRight="5dp" android:background="@null" android:src="@drawable/ic_action_edit" /> <ImageButton android:id="@+id/copyBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="5dp" android:layout_marginRight="5dp" android:background="@null" android:src="@drawable/ic_action_copy" /> <ImageButton android:id="@+id/shareBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="5dp" android:layout_marginRight="5dp" android:background="@null" android:src="@drawable/ic_action_share" /> </LinearLayout> </LinearLayout> </android.support.v7.widget.CardView>
Note.kt
package com.blogspot.atifsoftwares.sqlitecrud_notesapp_kotlin class Note(nodeID: Int, nodeName: String, nodeDes: String) { var nodeID: Int? = nodeID var nodeName: String? = nodeName var nodeDes: String? = nodeDes }
DbManager.kt
package com.blogspot.atifsoftwares.sqlitecrud_notesapp_kotlin import android.app.DownloadManager import android.content.ContentValues import android.content.Context import android.database.Cursor import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteOpenHelper import android.database.sqlite.SQLiteQueryBuilder import android.widget.Toast class DbManager { //database name var dbName = "MyNotes" //table name var dbTable = "Notes" //columns var colID = "ID" var colTitle = "Title" var colDes = "Description" //database version var dbVersion = 1 //CREATE TABLE IF NOT EXISTS MyNotes (ID INTEGER PRIMARY KEY,title TEXT, Description TEXT);" val sqlCreateTable = "CREATE TABLE IF NOT EXISTS " + dbTable + " (" + colID + " INTEGER PRIMARY KEY," + colTitle + " TEXT, " + colDes + " TEXT);" var sqlDB: SQLiteDatabase? = null constructor(context: Context) { var db = DatabaseHelperNotes(context) sqlDB = db.writableDatabase } inner class DatabaseHelperNotes : SQLiteOpenHelper { var context: Context? = null constructor(context: Context) : super(context, dbName, null, dbVersion) { this.context = context } override fun onCreate(db: SQLiteDatabase?) { db!!.execSQL(sqlCreateTable) Toast.makeText(this.context, "database created...", Toast.LENGTH_SHORT).show() } override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) { db!!.execSQL("Drop table if Exists" + dbTable) } } fun insert(values: ContentValues): Long { val ID = sqlDB!!.insert(dbTable, "", values) return ID } fun Query(projection: Array<String>, selection: String, selectionArgs: Array<String>, sorOrder: String): Cursor { val qb = SQLiteQueryBuilder(); qb.tables = dbTable val cursor = qb.query(sqlDB, projection, selection, selectionArgs, null, null, sorOrder) return cursor } fun delete(selection: String, selectionArgs: Array<String>): Int { val count = sqlDB!!.delete(dbTable, selection, selectionArgs) return count } fun update(values: ContentValues, selection: String, selectionArgs: Array<String>): Int { val count = sqlDB!!.update(dbTable, values, selection, selectionArgs) return count } }
activity_main.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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/gray" android:orientation="vertical" tools:context=".MainActivity"> <!--Display list of notes from SQLite/database--> <ListView android:id="@+id/notesLv" android:layout_width="match_parent" android:layout_height="match_parent" android:divider="@null" android:dividerHeight="1dp" /> </LinearLayout>
MainActivity.kt
package com.blogspot.atifsoftwares.sqlitecrud_notesapp_kotlin import android.app.SearchManager import android.content.Context import android.content.Intent import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.support.v7.widget.SearchView import android.text.ClipboardManager import android.view.Menu import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.widget.BaseAdapter import android.widget.Toast import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.row.* import kotlinx.android.synthetic.main.row.view.* class MainActivity : AppCompatActivity() { var listNotes = ArrayList<Note>() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) //Load from DB LoadQuery("%") } override fun onResume() { super.onResume() LoadQuery("%") } private fun LoadQuery(title: String) { var dbManager = DbManager(this) val projections = arrayOf("ID", "Title", "Description") val selectionArgs = arrayOf(title) val cursor = dbManager.Query(projections, "Title like ?", selectionArgs, "Title") listNotes.clear() if (cursor.moveToFirst()) { do { val ID = cursor.getInt(cursor.getColumnIndex("ID")) val Title = cursor.getString(cursor.getColumnIndex("Title")) val Description = cursor.getString(cursor.getColumnIndex("Description")) listNotes.add(Note(ID, Title, Description)) } while (cursor.moveToNext()) } //adapter var myNotesAdapter = MyNotesAdapter(this, listNotes) //set adapter notesLv.adapter = myNotesAdapter //get total number of tasks from ListView val total = notesLv.count //actionbar val mActionBar = supportActionBar if (mActionBar != null) { //set to actionbar as subtitle of actionbar mActionBar.subtitle = "You have $total note(s) in list..." } } override fun onCreateOptionsMenu(menu: Menu?): Boolean { menuInflater.inflate(R.menu.main_menu, menu) //searchView val sv: SearchView = menu!!.findItem(R.id.app_bar_search).actionView as SearchView val sm = getSystemService(Context.SEARCH_SERVICE) as SearchManager sv.setSearchableInfo(sm.getSearchableInfo(componentName)) sv.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { LoadQuery("%" + query + "%") return false } override fun onQueryTextChange(newText: String?): Boolean { LoadQuery("%" + newText + "%") return false } }); return super.onCreateOptionsMenu(menu) } override fun onOptionsItemSelected(item: MenuItem?): Boolean { if (item != null) { when (item.itemId) { R.id.addNote -> { startActivity(Intent(this, AddNoteActivity::class.java)) } R.id.action_settings -> { Toast.makeText(this, "Settings", Toast.LENGTH_SHORT).show() } } } return super.onOptionsItemSelected(item) } inner class MyNotesAdapter : BaseAdapter { var listNotesAdapter = ArrayList<Note>() var context: Context? = null constructor(context: Context, listNotesAdapter: ArrayList<Note>) : super() { this.listNotesAdapter = listNotesAdapter this.context = context } override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { //inflate layout row.xml var myView = layoutInflater.inflate(R.layout.row, null) val myNote = listNotesAdapter[position] myView.titleTv.text = myNote.nodeName myView.descTv.text = myNote.nodeDes //delete button click myView.deleteBtn.setOnClickListener { var dbManager = DbManager(this.context!!) val selectionArgs = arrayOf(myNote.nodeID.toString()) dbManager.delete("ID=?", selectionArgs) LoadQuery("%") } //edit//update button click myView.editBtn.setOnClickListener { GoToUpdateFun(myNote) } //copy btn click myView.copyBtn.setOnClickListener { //get title val title = myView.titleTv.text.toString() //get description val desc = myView.descTv.text.toString() //concatinate val s = title + "\n" + desc val cb = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager cb.text = s // add to clipboard Toast.makeText(this@MainActivity, "Copied...", Toast.LENGTH_SHORT).show() } //share btn click myView.shareBtn.setOnClickListener { //get title val title = myView.titleTv.text.toString() //get description val desc = myView.descTv.text.toString() //concatenate val s = title + "\n" + desc //share intent val shareIntent = Intent() shareIntent.action = Intent.ACTION_SEND shareIntent.type = "text/plain" shareIntent.putExtra(Intent.EXTRA_TEXT, s) startActivity(Intent.createChooser(shareIntent, s)) } return myView } override fun getItem(position: Int): Any { return listNotesAdapter[position] } override fun getItemId(position: Int): Long { return position.toLong() } override fun getCount(): Int { return listNotesAdapter.size } } private fun GoToUpdateFun(myNote: Note) { var intent = Intent(this, AddNoteActivity::class.java) intent.putExtra("ID", myNote.nodeID) //put id intent.putExtra("name", myNote.nodeName) //ut name intent.putExtra("des", myNote.nodeDes) //put description startActivity(intent) //start activity } }
activity_add_note.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" tools:context=".AddNoteActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp" app:cardBackgroundColor="@color/white" app:cardCornerRadius="3dp" app:cardElevation="3dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <EditText android:id="@+id/titleEt" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@null" android:hint="Enter Title" android:padding="10dp" android:singleLine="true" android:textStyle="bold" /> <EditText android:id="@+id/descEt" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@null" android:gravity="top" android:hint="Enter description..." android:minHeight="100dp" android:padding="10dp" /> </LinearLayout> </android.support.v7.widget.CardView> <Button android:id="@+id/addBtn" style="@style/Base.Widget.AppCompat.Button.Colored" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="end" android:layout_marginEnd="5dp" android:layout_marginRight="5dp" android:onClick="addFunc" android:text="Add" /> </LinearLayout> </ScrollView>
AddNoteActivity.kt
package com.blogspot.atifsoftwares.sqlitecrud_notesapp_kotlin import android.content.ContentValues import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.view.View import android.widget.Toast import kotlinx.android.synthetic.main.activity_add_note.* class AddNoteActivity : AppCompatActivity() { val dbTable = "Notes" var id = 0 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_add_note) try { val bundle:Bundle = intent.extras id = bundle.getInt("ID", 0) if (id!=0){ titleEt.setText(bundle.getString("name")) descEt.setText(bundle.getString("des")) } }catch (ex:Exception){} } fun addFunc(view:View){ var dbManager = DbManager(this) var values = ContentValues() values.put("Title", titleEt.text.toString()) values.put("Description", descEt.text.toString()) if (id ==0){ val ID = dbManager.insert(values) if (ID>0){ Toast.makeText(this, "Note is added", Toast.LENGTH_SHORT).show() finish() } else{ Toast.makeText(this, "Error adding note...", Toast.LENGTH_SHORT).show() } } else{ var selectionArgs = arrayOf(id.toString()) val ID = dbManager.update(values, "ID=?", selectionArgs) if (ID>0){ Toast.makeText(this, "Note is added", Toast.LENGTH_SHORT).show() finish() } else{ Toast.makeText(this, "Error adding note...", Toast.LENGTH_SHORT).show() } } } }
Step 09: Run Project
Video
Very impresive bro.is there posibility to add date when new entry is added?
ReplyDelete