Code > School / MEA5_S9_Kotlin

Informations :

							Project name: Kotlin
Description: Kotlin Room Implementation
Date: 22/11/2020
Updated: 22/11/2020
Type: School
Project informations:
- 10 Files
- 1 Folder
- 364 Lines
- 11980 Characters
Group:
public

Tags:
Windows
Programming
Android Studio
Kotlin
Room
										

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.roomtest"> <application android:name=".DeptApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.RoomTest"> <activity android:name=".NewDept"></activity> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
										

build.gradle

plugins { id 'com.android.application' id 'kotlin-android' id 'kotlin-kapt' } android { compileSdkVersion 30 buildToolsVersion "30.0.2" defaultConfig { applicationId "com.example.roomtest" minSdkVersion 21 targetSdkVersion 30 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } packagingOptions { exclude 'META-INF/atomicfu.kotlin_module' } kotlinOptions { jvmTarget = '1.8' } } dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation 'androidx.core:core-ktx:1.3.2' implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.2.1' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' // Room implementation "androidx.room:room-ktx:$rootProject.roomVersion" implementation 'androidx.room:room-runtime:2.2.5' kapt "androidx.room:room-compiler:$rootProject.roomVersion" androidTestImplementation "androidx.room:room-testing:$rootProject.roomVersion" // Lifecycle implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$rootProject.lifecycleVersion" implementation "androidx.lifecycle:lifecycle-livedata-ktx:$rootProject.lifecycleVersion" implementation "androidx.lifecycle:lifecycle-common-java8:$rootProject.lifecycleVersion" // activity components implementation "androidx.activity:activity-ktx:$rootProject.activityVersion" }
										

src / Dept.kt

package com.example.roomtest import androidx.room.* import kotlinx.coroutines.flow.Flow // Entity @Entity(tableName = "departements") class Dept( @PrimaryKey @ColumnInfo(name = "name") val name: String )
										

src / DeptApplication.kt

package com.example.roomtest import android.app.Application import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob class DeptApplication : Application(){ val applicationScope = CoroutineScope(SupervisorJob()) val database by lazy { DeptDatabase.getDatabase(this, applicationScope) } val deptDao by lazy { database.deptDao() } }
										

src / DeptDAO.kt

package com.example.roomtest import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query import kotlinx.coroutines.flow.Flow @Dao interface DeptDAO { @Query("SELECT * FROM departements ORDER BY name ASC") fun getDeptNames(): Flow<List<Dept>> @Insert(onConflict = OnConflictStrategy.IGNORE) suspend fun insert(dept: Dept) @Query("DELETE FROM departements") suspend fun deleteAll() }
										

src / DeptDatabase.kt

package com.example.roomtest import android.content.Context import androidx.room.Database import androidx.room.Room import androidx.room.RoomDatabase import androidx.sqlite.db.SupportSQLiteDatabase import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import kotlin.reflect.KParameter @Database(entities = arrayOf(Dept::class), version = 1, exportSchema = false) public abstract class DeptDatabase : RoomDatabase() { abstract fun deptDao(): DeptDAO companion object { @Volatile private var INSTANCE: DeptDatabase? = null fun getDatabase( context: Context, scope: CoroutineScope ): DeptDatabase { return INSTANCE ?: synchronized(this) { val instance = Room.databaseBuilder( context.applicationContext, DeptDatabase::class.java, "dept_database" ).addCallback(DeptDatabaseCallback(scope)).build() INSTANCE = instance instance } } } private class DeptDatabaseCallback(private val scope: CoroutineScope ) : RoomDatabase.Callback() { override fun onCreate(db: SupportSQLiteDatabase) { super.onCreate(db) INSTANCE?.let { database -> scope.launch { populateDatabase(database.deptDao()) } } } suspend fun populateDatabase(deptDao: DeptDAO) { deptDao.deleteAll() var tab = arrayOf("MEA", "IG", "STE", "M&I", "Mat", "STIA") var dept: Dept for (name in tab) { dept = Dept(name) deptDao.insert(dept) } } } }
										

src / DeptListAdapter.kt

package com.example.roomtest import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView class DeptListAdapter : ListAdapter<Dept, DeptListAdapter. DeptViewHolder>(DeptsComparator()) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DeptViewHolder { return DeptViewHolder.create(parent) } override fun onBindViewHolder(holder: DeptViewHolder, position: Int) { val current = getItem(position) holder.bind(current.name) } class DeptViewHolder(itemView: View) : RecyclerView. ViewHolder(itemView) { private val wordItemView: TextView = itemView. findViewById(R.id.textView) fun bind(text: String?) { wordItemView.text = text } companion object { fun create(parent: ViewGroup): DeptViewHolder { val view: View = LayoutInflater.from(parent .context) .inflate(R.layout.recyclerview_item, parent, false) return DeptViewHolder(view) } } } class DeptsComparator : DiffUtil.ItemCallback<Dept>() { override fun areItemsTheSame(oldItem: Dept, newItem : Dept): Boolean { return oldItem === newItem } override fun areContentsTheSame(oldItem: Dept, newItem: Dept): Boolean { return oldItem.name == newItem.name } } }
										

src / DeptViewModel.kt

package com.example.roomtest import androidx.lifecycle.* import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.launch class DeptViewModel(private val dao: DeptDAO) : ViewModel() { val depts: Flow<List<Dept>> = dao.getDeptNames() val allDepts: LiveData<List<Dept>> = this.depts.asLiveData() fun insert(dept: Dept) = viewModelScope.launch { dao.insert(dept) } } class DeptViewModelFactory(private val dao: DeptDAO) : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>): T { if (modelClass.isAssignableFrom(DeptViewModel::class.java)) { @Suppress("UNCHECKED_CAST") return DeptViewModel(dao) as T } throw IllegalArgumentException("Unknown ViewModel class") } }
										

src / MainActivity.kt

package com.example.roomtest import android.app.Activity import android.content.Intent import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.widget.Toast import androidx.activity.viewModels import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.google.android.material.floatingactionbutton.FloatingActionButton import kotlinx.coroutines.flow.count class MainActivity : AppCompatActivity() { private val newDeptActivityRequestCode = 1 private val deptViewModel: DeptViewModel by viewModels { DeptViewModelFactory( (application as DeptApplication).deptDao ) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val recyclerView = findViewById<RecyclerView>(R.id.deptslist) val adapter = DeptListAdapter() recyclerView.adapter = adapter recyclerView.layoutManager = LinearLayoutManager(this) deptViewModel.allDepts.observe(this) { depts -> depts.let { adapter.submitList(it) } } val add = findViewById<FloatingActionButton>(R.id.addButton) add.setOnClickListener { val intent = Intent( this@MainActivity, NewDept::class.java) startActivityForResult( intent, newDeptActivityRequestCode) } val dept = Dept("new") deptViewModel.insert(dept) } override fun onActivityResult(requestCode: Int, resultCode: Int, intentData: Intent?) { super.onActivityResult( requestCode, resultCode, intentData) if(requestCode == newDeptActivityRequestCode && resultCode == Activity.RESULT_OK) { intentData?.getStringExtra(NewDept.EXTRA_REPLY)?.let{ reply -> val dept = Dept(reply) deptViewModel.insert(dept) } } else { Toast.makeText( applicationContext, "chaîne vide, aucun ajout n'est fait", Toast.LENGTH_LONG ).show() } } }
										

src / NewDept.kt

package com.example.roomtest import android.app.Activity import android.content.Intent import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.text.TextUtils import android.widget.Button import android.widget.EditText class NewDept : AppCompatActivity() { private lateinit var editWordView: EditText override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_new_dept) editWordView = findViewById(R.id.edit_word) val button = findViewById<Button>(R.id.button_save) button.setOnClickListener { val replyIntent = Intent() if (TextUtils.isEmpty(editWordView.text)) { setResult(Activity.RESULT_CANCELED, replyIntent) } else { val word = editWordView.text.toString() replyIntent.putExtra(EXTRA_REPLY, word) setResult(Activity.RESULT_OK, replyIntent) } finish() } } companion object { const val EXTRA_REPLY = "com.example.android.wordlistsql.REPLY" } }