├── .circleci └── config.yml ├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro ├── screenshots │ └── output.png └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── pranay │ │ └── kotlinroomdbtodo │ │ └── ExampleInstrumentedTest.kt │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── pranay │ │ └── kotlinroomdbtodo │ │ ├── MainActivity.kt │ │ ├── adapter │ │ └── ToDoRecyclerAdapter.kt │ │ ├── dao │ │ └── ToDoTaskDao.kt │ │ ├── database │ │ └── ToDoDatabase.kt │ │ └── entity │ │ └── ToDoTask.kt │ └── res │ ├── drawable-hdpi │ └── ic_action_delete.png │ ├── drawable-mdpi │ └── ic_action_delete.png │ ├── drawable-xhdpi │ └── ic_action_delete.png │ ├── drawable-xxhdpi │ └── ic_action_delete.png │ ├── layout │ ├── activity_main.xml │ └── list_item_todo.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Java Gradle CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-java/ for more details 4 | # 5 | version: 2 6 | jobs: 7 | build: 8 | docker: 9 | # specify the version you desire here 10 | - image: circleci/openjdk:8-jdk 11 | 12 | # Specify service dependencies here if necessary 13 | # CircleCI maintains a library of pre-built images 14 | # documented at https://circleci.com/docs/2.0/circleci-images/ 15 | # - image: circleci/postgres:9.4 16 | 17 | working_directory: ~/repo 18 | 19 | environment: 20 | # Customize the JVM maximum heap limit 21 | JVM_OPTS: -Xmx3200m 22 | TERM: dumb 23 | 24 | steps: 25 | - checkout 26 | 27 | # Download and cache dependencies 28 | - restore_cache: 29 | keys: 30 | - v1-dependencies-{{ checksum "build.gradle" }} 31 | # fallback to using the latest cache if no exact match is found 32 | - v1-dependencies- 33 | 34 | - run: gradle dependencies 35 | 36 | - save_cache: 37 | paths: 38 | - ~/.m2 39 | key: v1-dependencies-{{ checksum "build.gradle" }} 40 | 41 | # run tests! 42 | - run: gradle test 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | ### Android template 10 | # Built application files 11 | *.apk 12 | *.ap_ 13 | 14 | # Files for the ART/Dalvik VM 15 | *.dex 16 | 17 | # Java class files 18 | *.class 19 | 20 | # Generated files 21 | bin/ 22 | gen/ 23 | out/ 24 | 25 | # Gradle files 26 | .gradle/ 27 | build/ 28 | 29 | # Local configuration file (sdk path, etc) 30 | local.properties 31 | 32 | # Proguard folder generated by Eclipse 33 | proguard/ 34 | 35 | # Log Files 36 | *.log 37 | 38 | # Android Studio Navigation editor temp files 39 | .navigation/ 40 | 41 | # Android Studio captures folder 42 | captures/ 43 | 44 | # Keystore files 45 | *.jks 46 | 47 | # External native build folder generated in Android Studio 2.2 and later 48 | 49 | # Google Services (e.g. APIs or Firebase) 50 | google-services.json 51 | 52 | # Freeline 53 | freeline.py 54 | freeline/ 55 | freeline_project_description.json 56 | 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KotlinRoomDbExample 2 | Basic ToDo App using **Room Database(Room persistence library**) and **RxJava** in **Kotlin**. 3 | 4 | Check [Room Persistence Library](https://developer.android.com/topic/libraries/architecture/room.html) 5 | 6 | 7 | 8 | 9 | #### Built With 10 | 11 | * [Android Studio](https://developer.android.com/studio/index.html) - The Official IDE for Android 12 | * [Kotlin](https://kotlinlang.org/) - The Official Language for Android ❤️ 13 | * [Gradle](https://gradle.org/) - Build tool for Android Studio 14 | 15 | #### Pull Requests 16 | 17 | I welcome and encourage all pull requests to learn something new. 18 | 19 | #### Find this project useful ? ❤️ 20 | 21 | Support it by clicking the ⭐️ button on the upper right of this page. ✌️ 22 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | apply plugin: 'kotlin-android' 4 | 5 | apply plugin: 'kotlin-android-extensions' 6 | 7 | android { 8 | compileSdkVersion 25 9 | buildToolsVersion "25.0.2" 10 | defaultConfig { 11 | applicationId "com.pranay.kotlinroomdbtodo" 12 | minSdkVersion 15 13 | targetSdkVersion 25 14 | versionCode 1 15 | versionName "1.0" 16 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 17 | } 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | } 25 | def ANDROID_ARCH_ROOM_VERSION = "1.0.0-alpha3" 26 | def SUPPORT_LIB_VERSION = "25.4.0" 27 | def RX_VERSION="2.0.1" 28 | dependencies { 29 | implementation fileTree(dir: 'libs', include: ['*.jar']) 30 | androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { 31 | exclude group: 'com.android.support', module: 'support-annotations' 32 | }) 33 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" 34 | implementation "com.android.support:appcompat-v7:$SUPPORT_LIB_VERSION" 35 | compile "com.android.support:cardview-v7:$SUPPORT_LIB_VERSION" 36 | compile "com.android.support:recyclerview-v7:$SUPPORT_LIB_VERSION" 37 | testImplementation 'junit:junit:4.12' 38 | 39 | compile "android.arch.persistence.room:runtime:$ANDROID_ARCH_ROOM_VERSION" 40 | kapt "android.arch.persistence.room:compiler:$ANDROID_ARCH_ROOM_VERSION" 41 | compile "android.arch.persistence.room:rxjava2:$ANDROID_ARCH_ROOM_VERSION" 42 | compile "io.reactivex.rxjava2:rxjava:$RX_VERSION" 43 | compile "io.reactivex.rxjava2:rxandroid:$RX_VERSION" 44 | } 45 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\Admin\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/screenshots/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pranaypatel512/KotlinRoomDbExample/b354e0bf5dbe340ae07a09c6a0a6b5794a56330b/app/screenshots/output.png -------------------------------------------------------------------------------- /app/src/androidTest/java/com/pranay/kotlinroomdbtodo/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.pranay.kotlinroomdbtodo 2 | 3 | import android.support.test.InstrumentationRegistry 4 | import android.support.test.runner.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getTargetContext() 22 | assertEquals("com.pranay.kotlinroomdbtodo", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/pranay/kotlinroomdbtodo/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.pranay.kotlinroomdbtodo 2 | 3 | import android.arch.persistence.room.Room 4 | import android.arch.persistence.room.RoomDatabase 5 | import android.os.Bundle 6 | import android.support.v7.app.AppCompatActivity 7 | import android.support.v7.widget.LinearLayoutManager 8 | import android.support.v7.widget.RecyclerView 9 | import android.text.TextUtils 10 | import android.widget.Button 11 | import android.widget.EditText 12 | import com.pranay.kotlinroomdbtodo.adapter.ToDoRecyclerAdapter 13 | import com.pranay.kotlinroomdbtodo.dao.ToDoTaskDao 14 | import com.pranay.kotlinroomdbtodo.database.ToDoDatabase 15 | import com.pranay.kotlinroomdbtodo.entity.ToDoTask 16 | import io.reactivex.Observable 17 | import io.reactivex.android.schedulers.AndroidSchedulers 18 | import io.reactivex.disposables.CompositeDisposable 19 | import io.reactivex.schedulers.Schedulers 20 | 21 | /** 22 | * Note: We need to add room database operation in a 23 | */ 24 | class MainActivity : AppCompatActivity() { 25 | 26 | lateinit var toDB: RoomDatabase // Room Database instance 27 | lateinit var editTextTodo: EditText 28 | lateinit var add_btn: Button 29 | lateinit var allTodos: ArrayList 30 | lateinit var toRecyclerAdapter: ToDoRecyclerAdapter 31 | lateinit var todo_recycler_view: RecyclerView 32 | lateinit var todoTaskDao: ToDoTaskDao // Dao Object for Perform database operation 33 | val compositeDisposable = CompositeDisposable() 34 | 35 | override fun onCreate(savedInstanceState: Bundle?) { 36 | super.onCreate(savedInstanceState) 37 | setContentView(R.layout.activity_main) 38 | initViewAndDatabase() 39 | } 40 | 41 | /** 42 | * init View and room data base 43 | */ 44 | private fun initViewAndDatabase() { 45 | initDataBase() 46 | allTodos = ArrayList() 47 | initViews() 48 | todo_recycler_view.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) 49 | todo_recycler_view.adapter = toRecyclerAdapter 50 | 51 | getAllTodos() 52 | } 53 | 54 | private fun initDataBase() { 55 | // Init Room data base 56 | toDB = Room.databaseBuilder(this, 57 | ToDoDatabase::class.java, "todo_database").build() 58 | todoTaskDao = (toDB as ToDoDatabase).taskToDo() // Get Database Dao Object 59 | toRecyclerAdapter = ToDoRecyclerAdapter() // init Adapter 60 | toRecyclerAdapter.setDeleteListener(object : ToDoRecyclerAdapter.MyAdapterListener { 61 | override fun onDeleteViewClick(position: Int) { 62 | deleteFromDb(allTodos[position], position) // Get To-Do Id for delete 63 | } 64 | }) 65 | } 66 | 67 | private fun initViews() { 68 | editTextTodo = findViewById(R.id.editTextTodo) as EditText 69 | add_btn = findViewById(R.id.add_btn) as Button 70 | todo_recycler_view = findViewById(R.id.todo_recycler_view) as RecyclerView 71 | add_btn.setOnClickListener({ 72 | if (!TextUtils.isEmpty(editTextTodo.text)) { // Check if edit text have to description 73 | addNewTask(editTextTodo.text.toString()) 74 | } 75 | }) 76 | } 77 | 78 | /** 79 | * Call For Delete To-Do 80 | */ 81 | private fun deleteFromDb(taskToDelete: ToDoTask, position: Int) { 82 | compositeDisposable.add(Observable.fromCallable { todoTaskDao.deleteToDoTask(taskToDelete) } 83 | .subscribeOn(Schedulers.io()) 84 | .observeOn(AndroidSchedulers.mainThread()) 85 | .subscribe({ 86 | allTodos.removeAt(position) 87 | toRecyclerAdapter.notifyItemRemoved(position) 88 | })) 89 | } 90 | 91 | 92 | /** 93 | * Add New TO DO 94 | */ 95 | fun addNewTask(toDoDetails: String) { 96 | val newTask = ToDoTask(toDoDetails) // Create New To do entity to add new to-do 97 | compositeDisposable.add(Observable.fromCallable { todoTaskDao.addToDoTask(newTask) } 98 | .subscribeOn(Schedulers.io()) 99 | .observeOn(AndroidSchedulers.mainThread()) 100 | .subscribe({ 101 | allTodos.add(newTask) // Add new task in list 102 | toRecyclerAdapter.notifyItemChanged(allTodos.size) // notify data change for newly added to do 103 | (allTodos.size - 1). 104 | takeIf { it >= 0 } // only greater then 0 105 | ?.let { 106 | // Then do smoothscroll to position 107 | todo_recycler_view.smoothScrollToPosition(it) 108 | } 109 | 110 | })) 111 | } 112 | 113 | /** 114 | * Update New TO-DO 115 | */ 116 | private fun updateList(todoId: Long) { 117 | // Get Last added To-do and in recycler list 118 | compositeDisposable.add(todoTaskDao.getTaskUsingId(todoId) 119 | .subscribeOn(Schedulers.io()) 120 | .observeOn(AndroidSchedulers.mainThread()) 121 | .subscribe({ 122 | toRecyclerAdapter.addTodo(it) 123 | }) 124 | ) 125 | 126 | } 127 | 128 | /** 129 | * Get All To-Do 130 | */ 131 | private fun getAllTodos() { 132 | // TODO: Can't try to access room database on main thread 133 | //StackOverFlow Question : https://stackoverflow.com/q/44167111/2949612 134 | 135 | /*allTodos = (toDB as ToDoDatabase).taskToDo().allToDoTask() as ArrayList 136 | if (allTodos.size > 0) { 137 | toRecyclerAdapter.setData(allTodos) 138 | toRecyclerAdapter.notifyDataSetChanged() 139 | }*/ 140 | 141 | // Get Last added All To-do and in recycler list 142 | compositeDisposable.add((toDB as ToDoDatabase).taskToDo().allToDoTask() 143 | .subscribeOn(Schedulers.io()) 144 | .observeOn(AndroidSchedulers.mainThread()) // Observe on Android Main thread 145 | .subscribe({ 146 | allTodos.clear() // Clear app task 147 | allTodos.addAll(it) // Add All tasks 148 | toRecyclerAdapter.setData(allTodos) // Add All task in adapter 149 | 150 | }) 151 | 152 | ) 153 | } 154 | 155 | override fun onDestroy() { 156 | compositeDisposable.dispose() // Dispose 157 | super.onDestroy() 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /app/src/main/java/com/pranay/kotlinroomdbtodo/adapter/ToDoRecyclerAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.pranay.kotlinroomdbtodo.adapter 2 | 3 | import android.support.v7.widget.RecyclerView 4 | import android.widget.CheckBox 5 | import android.widget.ImageView 6 | import com.pranay.kotlinroomdbtodo.R 7 | import com.pranay.kotlinroomdbtodo.entity.ToDoTask 8 | import kotlinx.android.synthetic.main.list_item_todo.view.* 9 | 10 | /** 11 | * Created by Pranay on 7/1/2017. 12 | */ 13 | 14 | 15 | class ToDoRecyclerAdapter : RecyclerView.Adapter() { 16 | 17 | lateinit var tasks: ArrayList 18 | lateinit var mDeleteListener: MyAdapterListener 19 | override fun onCreateViewHolder(parent: android.view.ViewGroup, type: Int): TaskViewHolder { 20 | return TaskViewHolder(parent) 21 | } 22 | 23 | fun setData(tasks: ArrayList) { 24 | this.tasks = tasks 25 | notifyDataSetChanged() 26 | } 27 | 28 | fun addTodo(todoTask: ToDoTask) { 29 | this.tasks.add(todoTask) 30 | notifyItemChanged(tasks.size) 31 | } 32 | 33 | override fun onBindViewHolder(viewHolder: ToDoRecyclerAdapter.TaskViewHolder, position: Int) { 34 | viewHolder.bind(tasks[position], position) 35 | } 36 | 37 | override fun getItemCount(): Int = tasks.size 38 | 39 | inner class TaskViewHolder(parent: android.view.ViewGroup) : 40 | RecyclerView.ViewHolder(android.view.LayoutInflater.from(parent.context). 41 | inflate(R.layout.list_item_todo, parent, false)) { 42 | 43 | fun bind(task: ToDoTask, position: Int) = with(itemView) { 44 | val taskCb = findViewById(R.id.checkBoxTodo) as CheckBox 45 | val deleteTodo = findViewById(R.id.btnDelete) as ImageView 46 | taskCb.checkBoxTodo.text = task.todoTask 47 | deleteTodo.setOnClickListener({ 48 | mDeleteListener.onDeleteViewClick(position) 49 | }) 50 | } 51 | } 52 | 53 | 54 | public fun setDeleteListener(deleteListener: MyAdapterListener): Unit { 55 | this.mDeleteListener = deleteListener 56 | } 57 | 58 | interface MyAdapterListener { 59 | fun onDeleteViewClick(position: Int) 60 | } 61 | } -------------------------------------------------------------------------------- /app/src/main/java/com/pranay/kotlinroomdbtodo/dao/ToDoTaskDao.kt: -------------------------------------------------------------------------------- 1 | package com.pranay.kotlinroomdbtodo.dao 2 | 3 | import android.arch.persistence.room.* 4 | import android.arch.persistence.room.OnConflictStrategy.REPLACE 5 | import com.pranay.kotlinroomdbtodo.entity.ToDoTask 6 | import io.reactivex.Flowable 7 | 8 | /** 9 | * Created by Pranay on 7/1/2017. 10 | */ 11 | 12 | @Dao interface ToDoTaskDao { 13 | // Get All- to do Tasks 14 | @Query("select * from todo_table") 15 | //fun allToDoTask(): List // Simple Kotlin 16 | fun allToDoTask(): Flowable> // RxJava 17 | 18 | // Task using task ID 19 | @Query("select * from todo_table where id = :arg0") 20 | fun getTaskUsingId( todo_id: Long):Flowable 21 | 22 | // Insert Task 23 | @Insert(onConflict = REPLACE) 24 | fun addToDoTask(todoTask:ToDoTask):Long 25 | 26 | // Update Task 27 | @Update(onConflict = REPLACE) 28 | fun updateToDoTask(todoTask:ToDoTask) 29 | 30 | // Delete task 31 | @Delete() 32 | fun deleteToDoTask(todoTask:ToDoTask) 33 | } -------------------------------------------------------------------------------- /app/src/main/java/com/pranay/kotlinroomdbtodo/database/ToDoDatabase.kt: -------------------------------------------------------------------------------- 1 | package com.pranay.kotlinroomdbtodo.database 2 | 3 | import android.arch.persistence.room.Database 4 | import android.arch.persistence.room.RoomDatabase 5 | import com.pranay.kotlinroomdbtodo.dao.ToDoTaskDao 6 | import com.pranay.kotlinroomdbtodo.entity.ToDoTask 7 | 8 | /** 9 | * Created by Admin on 7/1/2017. 10 | */ 11 | 12 | @Database(entities = arrayOf(ToDoTask::class), version = 1, exportSchema = false) 13 | abstract class ToDoDatabase: RoomDatabase() { 14 | abstract fun taskToDo(): ToDoTaskDao 15 | } -------------------------------------------------------------------------------- /app/src/main/java/com/pranay/kotlinroomdbtodo/entity/ToDoTask.kt: -------------------------------------------------------------------------------- 1 | package com.pranay.kotlinroomdbtodo.entity 2 | 3 | import android.arch.persistence.room.ColumnInfo 4 | import android.arch.persistence.room.Entity 5 | import android.arch.persistence.room.PrimaryKey 6 | 7 | /** 8 | * Created by Pranay on 7/1/2017. 9 | */ 10 | @Entity(tableName = "todo_table") 11 | data class ToDoTask(@ColumnInfo(name = "todo_task") 12 | var todoTask: String) { 13 | constructor():this("") 14 | @ColumnInfo(name = "id") 15 | @PrimaryKey(autoGenerate = true) var id: Long = 0 16 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pranaypatel512/KotlinRoomDbExample/b354e0bf5dbe340ae07a09c6a0a6b5794a56330b/app/src/main/res/drawable-hdpi/ic_action_delete.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_action_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pranaypatel512/KotlinRoomDbExample/b354e0bf5dbe340ae07a09c6a0a6b5794a56330b/app/src/main/res/drawable-mdpi/ic_action_delete.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pranaypatel512/KotlinRoomDbExample/b354e0bf5dbe340ae07a09c6a0a6b5794a56330b/app/src/main/res/drawable-xhdpi/ic_action_delete.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pranaypatel512/KotlinRoomDbExample/b354e0bf5dbe340ae07a09c6a0a6b5794a56330b/app/src/main/res/drawable-xxhdpi/ic_action_delete.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 21 | 22 | 30 | 31 |