📜  如何使用MVVM和Room Database构建杂货Android应用?

📅  最后修改于: 2021-05-10 16:07:27             🧑  作者: Mango

在本文中,我们将使用android studio在android中构建杂货店应用程序。很多时候,我们忘记购买要购买的东西,毕竟我们忘记了所有物品,因此,借助此应用程序,您可以记下要购买的杂货您不会忘记要购买的任何物品。下面给出了一个示例图像,以使您对本文中要做的事情有一个了解。请注意,我们将使用Kotlin语言实施此项目。

构建一个杂货Android应用

在此项目中,我们将MVVM(模型视图ViewModel)用于建筑模式,将Room用于数据库,协程和RecyclerView用于显示项目列表。在跳到项目之前,让我们了解这些术语。

MVVM(模型视图ViewModel)

android中的MVVM体系结构用于为项目的代码提供结构并轻松理解代码。 MVVM是Android中的架构设计模式。 MVVM将Activity类和XML文件视为View。这种设计模式将UI与逻辑完全分开。这是快速了解MVVM的图像。

MVVM(模型视图ViewModel)

看完该图像后,如果您不了解其工作原理,请不要担心,因为我们将编写完全理解的代码。

ROOM数据库

Room Persistence库是一个数据库管理库,用于存储诸如杂货项目名称,杂货项目数量和杂货价格等应用程序的数据。 Room是SQLite的覆盖层,可帮助轻松地对数据库执行操作。

回收站

RecyclerView是一个容器,用于显示大量数据集中的数据集合,可以通过维护有限数量的视图来非常有效地滚动数据集。

协程

协程是轻量级线程,我们使用协程对其他线程执行操作,因此,我们的主线程不会阻塞,并且我们的应用程序不会崩溃。

分步实施

步骤1:创建一个新项目

要在Android Studio中创建新项目,请参阅如何在Android Studio中创建/启动新项目。请注意,选择Kotlin作为编程语言。

第2步:首先进入编码部分,您必须做一些准备工作

在进行编码之前,首先将这些库添加到gradle文件中,然后将插件应用为“ kotlin-kapt”。要添加这些库,请转到Gradle脚本> build.gradle(Module:app)。

以下是build.gradle(:app)文件的完整代码。

Kotlin
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
  
android {
    compileSdkVersion 29
    buildToolsVersion "30.0.3"
  
    defaultConfig {
        applicationId "com.example.grocerylist"
        minSdkVersion 16
        targetSdkVersion 29
        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 = 1.8
        targetCompatibility = 1.8
    }
    kotlinOptions {
        jvmTarget = "1.8"
    }
}
  
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.core:core-ktx:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
  
    def room_version = "2.2.1"
    def lifecycle_version = "2.0.0"
  
    // Room and Architectural Components
    implementation "androidx.room:room-runtime:$room_version"
    implementation "androidx.legacy:legacy-support-v4:1.0.0"
    implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0'
    implementation "androidx.room:room-ktx:2.2.1"
    kapt "androidx.room:room-compiler:$room_version"
  
    // Coroutines
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0"
  
    // New Material Design
    implementation "com.google.android.material:material:1.0.0"
  
    // ViewModel
    implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
    kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
  
}


XML

    Fresh Basket
  
    
    Hello blank fragment
    Banana
    35
    250Rs
    20
    Total Cost
    Add Items to your cart
    Item
    Quantity
    Price
    Save
    Cancel
      


XML


    #0AD042
    #03551A
    #03DAC5
    #000000
    #ffffff


Kotlin
package com.example.grocerylist.Database.Entity
  
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
  
// This is a data class which store data.
// Entities class create a table in database, 
// in our database we will create three column
  
@Entity(tableName = "grocery_items")
  
data class GroceryItems(
  
    // create itemName variable to 
    // store grocery items.
    @ColumnInfo(name = "itemName")
    var itemName: String,
  
    // create itemQuantity variable
    // to store grocery quantity.
    @ColumnInfo(name = "itemQuantity")
    var itemQuantity: Int,
  
    // create itemPrice variable to 
    // store grocery price.
    @ColumnInfo(name = "itemPrice")
    var itemPrice: Int
) {
    // Primary key is a unique key
    // for different database.
    @PrimaryKey(autoGenerate = true)
    var id: Int? = null
}


Kotlin
package com.example.grocerylist.Database
  
import androidx.lifecycle.LiveData
import androidx.room.*
import com.example.grocerylist.Database.Entity.GroceryItems
  
// This class is used to create
// function for database.
@Dao
interface GroceryDao {
  
    // Insert function is used to 
    // insert data in database.
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(item: GroceryItems)
  
    // Delete function is used to
    // delete data in database.
    @Delete
    suspend fun delete(item: GroceryItems)
  
    // getAllGroceryItems function is used to get 
    // all the data of database.
    @Query("SELECT * FROM grocery_items")
    fun getAllGroceryItems(): LiveData>
}


Kotlin
package com.example.grocerylist.Database
  
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import com.example.grocerylist.Database.Entity.GroceryItems
  
@Database(entities = [GroceryItems::class], version = 1)
abstract class GroceryDatabase : RoomDatabase() {
  
    abstract fun getGroceryDao(): GroceryDao
  
    companion object {
        @Volatile
        private var instance: GroceryDatabase? = null
        private val LOCK = Any()
  
        operator fun invoke(context: Context) = instance ?: synchronized(LOCK) {
            instance ?: createDatabase(context).also {
                instance = it
            }
        }
  
        private fun createDatabase(context: Context) =
            Room.databaseBuilder(context.applicationContext, GroceryDatabase::class.java, "GroceryDatabase.db").build()
    }
}


Kotlin
package com.example.grocerylist.Database
  
import com.example.grocerylist.Database.Entity.GroceryItems
  
class GroceryRepository(private val db: GroceryDatabase) {
  
    suspend fun insert(item: GroceryItems) = db.getGroceryDao().insert(item)
    suspend fun delete(item: GroceryItems) = db.getGroceryDao().delete(item)
  
    fun allGroceryItems() = db.getGroceryDao().getAllGroceryItems()
}


Kotlin
package com.example.grocerylist.UI
  
import androidx.lifecycle.ViewModel
import com.example.grocerylist.Database.Entity.GroceryItems
import com.example.grocerylist.Database.GroceryRepository
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
  
class GroceryViewModel(private val repository: GroceryRepository) : ViewModel() {
  
    // In coroutines thread insert item in insert function.
    fun insert(item: GroceryItems) = GlobalScope.launch {
        repository.insert(item)
    }
  
    // In coroutines thread delete item in delete function.
    fun delete(item: GroceryItems) = GlobalScope.launch {
        repository.delete(item)
    }
  
    //Here we initialized allGroceryItems function with repository
    fun allGroceryItems() = repository.allGroceryItems()
  
}


Kotlin
package com.example.grocerylist.UI
  
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.example.grocerylist.Database.GroceryRepository
  
class GroceryViewModelFactory(private val repository: GroceryRepository):ViewModelProvider.NewInstanceFactory() {
  
    override fun  create(modelClass: Class): T {
        return GroceryViewModel(repository) as T
    }
}


XML


  
    
    
  
    
    
  
    
    
          
    
  
    
    


XML


  
    
    
  
    
    
  
    
    
  
    
  
    
    
  
    
    
  
    
    
      


Kotlin
package com.example.grocerylist.Adapter
  
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.grocerylist.Database.Entity.GroceryItems
import com.example.grocerylist.R
import com.example.grocerylist.UI.GroceryViewModel
import kotlinx.android.synthetic.main.groceryadapter.view.*
  
class GroceryAdapter(var list: List, val viewModel: GroceryViewModel) :
    RecyclerView.Adapter() {
  
    // In this function we will add our groceryadapter.xml to kotlin class
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GroceryViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.groceryadapter, parent, false)
        return GroceryViewHolder(view)
    }
  
    // This function is used to return total number of size of list.
    override fun getItemCount(): Int {
        return list.size
    }
  
    // In onBindViewHolder we will bind our itemViews with adapter
    override fun onBindViewHolder(holder: GroceryViewHolder, position: Int) {
        var currentPosition = list[position]
        holder.itemView.txtItemName.text = currentPosition.itemName
        holder.itemView.txtItemPrice.text = "${currentPosition.itemPrice}"
        holder.itemView.txtItemQuantity.text = "${currentPosition.itemQuantity}"
        holder.itemView.ibDelete.setOnClickListener {
            viewModel.delete(currentPosition)
        }
  
        // To get total cost 
        if (position == list.size - 1) {
            var totalCost = 0
            for (i in 0 until list.size) {
                totalCost += list[i].itemPrice
            }
            holder.itemView.txtItemTotalCost.visibility = View.VISIBLE
            holder.itemView.txtTotalCostTitle.visibility = View.VISIBLE
            holder.itemView.txtItemTotalCost.text = "$totalCost"
        }
    }
    // Inner class for viewHolder
    inner class GroceryViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
}


XML


  
    
    
  
    
    
  
        
        
  
        
        
  
        
        
  
    
  
    
    
  
    
    
  


Kotlin
package com.example.grocerylist.UI
  
import com.example.grocerylist.Database.Entity.GroceryItems
  
interface DialogListener {
    
    // Create a function to add items
      // in GroceryItems on clicking
    fun onAddButtonClicked(item:GroceryItems)
}


Kotlin
package com.example.grocerylist.UI
  
import android.content.Context
import android.os.Bundle
import android.view.Window
import android.widget.Toast
import androidx.appcompat.app.AppCompatDialog
import com.example.grocerylist.Database.Entity.GroceryItems
import com.example.grocerylist.R
import kotlinx.android.synthetic.main.grocerydialog.*
  
class GroceryItemDialog(context: Context, var dialogListener: DialogListener) : AppCompatDialog(context) {
  
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE)
        setContentView(R.layout.grocerydialog)
  
        // Click listener on Save button
        // to save all data.
        tvSave.setOnClickListener {
  
            // Take all three inputs in different variables from user
            // and add it in Grocery Items database
            val name = etItemName.text.toString()
            val quantity = etItemQuantity.text.toString().toInt()
            val price = etItemPrice.text.toString().toInt()
  
            // Toast to display enter items in edit text
            if (name.isEmpty()) {
                Toast.makeText(context, "Please Enter Item Name", Toast.LENGTH_SHORT).show()
            }
  
            val item = GroceryItems(name, quantity, price)
            dialogListener.onAddButtonClicked(item)
            dismiss()
        }
  
        // On click listener on cancel text to close dialog box
        tvCancel.setOnClickListener {
            cancel()
        }
    }
}


Kotlin
package com.example.grocerylist.UI
  
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.grocerylist.Adapter.GroceryAdapter
import com.example.grocerylist.Database.Entity.GroceryItems
import com.example.grocerylist.Database.GroceryDatabase
import com.example.grocerylist.Database.GroceryRepository
import com.example.grocerylist.R
import kotlinx.android.synthetic.main.activity_main.*
  
class MainActivity : AppCompatActivity() {
      
    lateinit var ViewModel: GroceryViewModel
    lateinit var list: List
  
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
          
        val groceryRepository = GroceryRepository(GroceryDatabase(this))
        val factory = GroceryViewModelFactory(groceryRepository)
  
        // Initialised View Model
        ViewModel = ViewModelProvider(this, factory).get(GroceryViewModel::class.java)
        val groceryAdapter = GroceryAdapter(listOf(), ViewModel)
        rvList.layoutManager = LinearLayoutManager(this)
        rvList.adapter = groceryAdapter
          
        // To display all items in recycler view
        ViewModel.allGroceryItems().observe(this, Observer {
            groceryAdapter.list = it
            groceryAdapter.notifyDataSetChanged()
        })
          
        // on ClickListener on button to open dialog box
        btnAdd.setOnClickListener {
            GroceryItemDialog(this, object : DialogListener {
                override fun onAddButtonClicked(item: GroceryItems) {
                    ViewModel.insert(item)
                }
            }).show()
        }
    }
}


以下是字符串.xml文件的代码。在这里,我们添加了将在项目中使用的必要字符串。

XML格式


    Fresh Basket
  
    
    Hello blank fragment
    Banana
    35
    250Rs
    20
    Total Cost
    Add Items to your cart
    Item
    Quantity
    Price
    Save
    Cancel
      

以下是colors.xml文件的代码。在这里,我们添加了将在项目中使用的必要颜色。

XML格式



    #0AD042
    #03551A
    #03DAC5
    #000000
    #ffffff

步骤3:建立会议室资料库

a)实体类

实体类包含数据库中的所有列,并应使用@Entity(tablename =“表名”)进行注释。实体类是数据类。 @Column info批注用于输入列变量名称和数据类型。我们还将添加自动增加的主键。转到应用> Java > com.example.application-name。右键单击com.example.application-name,然后转到new并创建Kotlin文件/类,然后将该文件命名为GroceryEntities 请参阅下面的代码以完全理解和实现。

科特林

package com.example.grocerylist.Database.Entity
  
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
  
// This is a data class which store data.
// Entities class create a table in database, 
// in our database we will create three column
  
@Entity(tableName = "grocery_items")
  
data class GroceryItems(
  
    // create itemName variable to 
    // store grocery items.
    @ColumnInfo(name = "itemName")
    var itemName: String,
  
    // create itemQuantity variable
    // to store grocery quantity.
    @ColumnInfo(name = "itemQuantity")
    var itemQuantity: Int,
  
    // create itemPrice variable to 
    // store grocery price.
    @ColumnInfo(name = "itemPrice")
    var itemPrice: Int
) {
    // Primary key is a unique key
    // for different database.
    @PrimaryKey(autoGenerate = true)
    var id: Int? = null
}

b)道接口

Dao是一个接口,我们可以在其中创建要在数据库上实现的所有功能。该接口还用@Dao注释。现在,我们将使用暂停功能创建一个函数,该函数是协程函数。在这里,我们创建了三个函数,第一个是用于在数据库中插入项目并用@Insert注释的插入函数,第二个是用于从数据库中用@Delete注释的项删除项目,第三个是使用@Query注释的所有项。转到应用> Java > com.example.application-name 。右键单击com.example.application-name,然后转到new并创建Kotlin文件/类,并将该文件命名为GroceryDao 。请参见下面的代码以实现。

科特林

package com.example.grocerylist.Database
  
import androidx.lifecycle.LiveData
import androidx.room.*
import com.example.grocerylist.Database.Entity.GroceryItems
  
// This class is used to create
// function for database.
@Dao
interface GroceryDao {
  
    // Insert function is used to 
    // insert data in database.
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(item: GroceryItems)
  
    // Delete function is used to
    // delete data in database.
    @Delete
    suspend fun delete(item: GroceryItems)
  
    // getAllGroceryItems function is used to get 
    // all the data of database.
    @Query("SELECT * FROM grocery_items")
    fun getAllGroceryItems(): LiveData>
}

c)数据库类

用@Database注释的数据库类(实体= [Entity class.class的名称],版本= 1)这些实体是实体数组列表,列出了与数据库相关联的所有数据实体,并且版本显示了数据库的当前版本。该数据库类继承自Room Database类。在GroceryDatabase类中,我们将提供一个抽象方法来获取DAO的实例,并进一步使用DAO实例中的此方法与数据库进行交互。请参见下面的代码来实现。去 应用> Java > com.example.application-name 。右键单击com.example.application-name,然后转到new并将Kotlin文件/类创建为GroceryDatabase 。请参见下面的代码以实现。

科特林

package com.example.grocerylist.Database
  
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import com.example.grocerylist.Database.Entity.GroceryItems
  
@Database(entities = [GroceryItems::class], version = 1)
abstract class GroceryDatabase : RoomDatabase() {
  
    abstract fun getGroceryDao(): GroceryDao
  
    companion object {
        @Volatile
        private var instance: GroceryDatabase? = null
        private val LOCK = Any()
  
        operator fun invoke(context: Context) = instance ?: synchronized(LOCK) {
            instance ?: createDatabase(context).also {
                instance = it
            }
        }
  
        private fun createDatabase(context: Context) =
            Room.databaseBuilder(context.applicationContext, GroceryDatabase::class.java, "GroceryDatabase.db").build()
    }
}

步骤4:现在,我们将在应用程序中实现架构结构

a)储存库类

知识库是设计结构之一。存储库类将数据提供给ViewModel类,然后ViewModel类将该数据用于View。存储库将在本地或网络上选择适当的数据。在这里,在我们的Grocery Repository类中,数据是从Room数据库本地获取的。我们将通过创建数据库实例并将其存储在Grocery Repository类的db变量中来添加构造函数值。去 应用> Java > com.example.application-name 。右键单击com.example.application-name,然后转到new并将Kotlin文件/类创建为GroceryRepository 。请参见下面的代码以实现。

科特林

package com.example.grocerylist.Database
  
import com.example.grocerylist.Database.Entity.GroceryItems
  
class GroceryRepository(private val db: GroceryDatabase) {
  
    suspend fun insert(item: GroceryItems) = db.getGroceryDao().insert(item)
    suspend fun delete(item: GroceryItems) = db.getGroceryDao().delete(item)
  
    fun allGroceryItems() = db.getGroceryDao().getAllGroceryItems()
}

转到应用程序> Java > com.example.application-name 。右键单击com.example.application-name,转到new并创建一个名为UI的新程序包,然后右键单击UI程序包并创建Kotlin文件/类。请参见下面的代码以实现。

b)ViewModel类

ViewModel类用作View和Data之间的接口。杂货店View模型类继承自View模型类,我们将通过创建Repository类的实例变量并将其存储在存储库变量中来传递构造函数值。当我们在View Model中传递构造函数时,我们必须创建另一个类,即Factory View Model类。转到应用程序> Java > com.example.application-name> UI 。右键单击UI包,然后创建Kotlin文件/类,然后将该文件命名为GroceryViewModel 。请参见下面的代码。

科特林

package com.example.grocerylist.UI
  
import androidx.lifecycle.ViewModel
import com.example.grocerylist.Database.Entity.GroceryItems
import com.example.grocerylist.Database.GroceryRepository
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
  
class GroceryViewModel(private val repository: GroceryRepository) : ViewModel() {
  
    // In coroutines thread insert item in insert function.
    fun insert(item: GroceryItems) = GlobalScope.launch {
        repository.insert(item)
    }
  
    // In coroutines thread delete item in delete function.
    fun delete(item: GroceryItems) = GlobalScope.launch {
        repository.delete(item)
    }
  
    //Here we initialized allGroceryItems function with repository
    fun allGroceryItems() = repository.allGroceryItems()
  
}

c)工厂ViewModel类

我们将从ViewModelProvider.NewInstanceFactory继承Grocery ViewModel Factory类,并通过创建Grocery Repository的实例变量来再次传递构造函数值,并返回GroceryViewModel(respository)。转到应用> Java > com.example.application-name> UI 。右键点击 UI包,并创建一个名为GroceryViewModelFactory的Kotlin文件/类。请参阅下面的代码以了解。

科特林

package com.example.grocerylist.UI
  
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.example.grocerylist.Database.GroceryRepository
  
class GroceryViewModelFactory(private val repository: GroceryRepository):ViewModelProvider.NewInstanceFactory() {
  
    override fun  create(modelClass: Class): T {
        return GroceryViewModel(repository) as T
    }
}

第5步:现在,让我们进入UI部分

activity_main.xml中的文件,我们会点击这个按钮对话框打开后添加两个ImageView的,RecyclerView和按钮,在对话框中用户可以输入项目名称,项目数量和项目价格。请参考以下代码。

XML格式



  
    
    
  
    
    
  
    
    
          
    
  
    
    

XML代码的输出:

第6步:让我们实现RecyclerView 。现在,我们将对列表中行的UI部分进行编码。转到应用程序> res>布局。右键单击布局,转到“新建”,然后添加一个布局资源文件并将其命名为食品杂货店。请参阅groceradaptapt.xml文件的XML代码。

XML格式



  
    
    
  
    
    
  
    
    
  
    
  
    
    
  
    
    
  
    
    
      

XML代码的输出:

我们将为回收者视图编码适配器类。在Grocery Adapter类中,我们将通过将实体类作为列表存储在list变量中来添加构造函数值,并创建视图模型的实例。在Grocery Adapter中,我们将覆盖三个函数:onCreateViewHolder,getItemCount和onbindViewHolder,我们还将创建一个称为杂货店视图持有人的内部类。转到应用> Java > com.example.application-name 。右键单击com.example.application-name转到new并创建一个名为Adapter的新程序包,然后右键单击Adapter程序包并创建一个名为GroceryAdapter的Kotlin文件/类。请参见下面的代码。

科特林

package com.example.grocerylist.Adapter
  
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.grocerylist.Database.Entity.GroceryItems
import com.example.grocerylist.R
import com.example.grocerylist.UI.GroceryViewModel
import kotlinx.android.synthetic.main.groceryadapter.view.*
  
class GroceryAdapter(var list: List, val viewModel: GroceryViewModel) :
    RecyclerView.Adapter() {
  
    // In this function we will add our groceryadapter.xml to kotlin class
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GroceryViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.groceryadapter, parent, false)
        return GroceryViewHolder(view)
    }
  
    // This function is used to return total number of size of list.
    override fun getItemCount(): Int {
        return list.size
    }
  
    // In onBindViewHolder we will bind our itemViews with adapter
    override fun onBindViewHolder(holder: GroceryViewHolder, position: Int) {
        var currentPosition = list[position]
        holder.itemView.txtItemName.text = currentPosition.itemName
        holder.itemView.txtItemPrice.text = "${currentPosition.itemPrice}"
        holder.itemView.txtItemQuantity.text = "${currentPosition.itemQuantity}"
        holder.itemView.ibDelete.setOnClickListener {
            viewModel.delete(currentPosition)
        }
  
        // To get total cost 
        if (position == list.size - 1) {
            var totalCost = 0
            for (i in 0 until list.size) {
                totalCost += list[i].itemPrice
            }
            holder.itemView.txtItemTotalCost.visibility = View.VISIBLE
            holder.itemView.txtTotalCostTitle.visibility = View.VISIBLE
            holder.itemView.txtItemTotalCost.text = "$totalCost"
        }
    }
    // Inner class for viewHolder
    inner class GroceryViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
}

步骤7:要从用户输入杂货项目,数量和价格,我们必须创建一个界面。为了实现此接口,我们将使用DialogBox。首先创建对话框的UI。在此对话框中,我们将添加三个编辑文本和两个文本视图。三个编辑文本可输入食品杂货的名称,数量和价格。两种文本视图,一种用于保存,另一种用于取消。单击保存文本后,所有保存到数据库的数据都将被保存,并通过单击“取消文本”对话框关闭。转到应用程序> res>布局。右键单击布局,转到“新建”,然后添加一个“布局资源文件”,并将其命名为“杂货店对话框” 。请参阅杂货店dialog.xml文件的XML代码。

XML格式



  
    
    
  
    
    
  
        
        
  
        
        
  
        
        
  
    
  
    
    
  
    
    
  

XML代码的输出:

要在保存文本上添加clicklistener,我们必须首先创建一个接口,然后在其中创建一个函数。去 应用> Java > com.example.application-name> UI。右键点击 UI包并创建Kotlin文件/类,并创建一个名为DialogListener接口。请参阅DialogListener.kt文件的代码。

科特林

package com.example.grocerylist.UI
  
import com.example.grocerylist.Database.Entity.GroceryItems
  
interface DialogListener {
    
    // Create a function to add items
      // in GroceryItems on clicking
    fun onAddButtonClicked(item:GroceryItems)
}

现在,我们将创建食品杂货对话框类,在其中将所有输入保存在不同的变量中,然后插入数据库中。转到应用> Java > com.example.application-name> UI。右键单击UI包,创建一个Kotlin文件/类,并创建一个名为GroceryItemDialog的类。请参见下面的代码。

科特林

package com.example.grocerylist.UI
  
import android.content.Context
import android.os.Bundle
import android.view.Window
import android.widget.Toast
import androidx.appcompat.app.AppCompatDialog
import com.example.grocerylist.Database.Entity.GroceryItems
import com.example.grocerylist.R
import kotlinx.android.synthetic.main.grocerydialog.*
  
class GroceryItemDialog(context: Context, var dialogListener: DialogListener) : AppCompatDialog(context) {
  
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE)
        setContentView(R.layout.grocerydialog)
  
        // Click listener on Save button
        // to save all data.
        tvSave.setOnClickListener {
  
            // Take all three inputs in different variables from user
            // and add it in Grocery Items database
            val name = etItemName.text.toString()
            val quantity = etItemQuantity.text.toString().toInt()
            val price = etItemPrice.text.toString().toInt()
  
            // Toast to display enter items in edit text
            if (name.isEmpty()) {
                Toast.makeText(context, "Please Enter Item Name", Toast.LENGTH_SHORT).show()
            }
  
            val item = GroceryItems(name, quantity, price)
            dialogListener.onAddButtonClicked(item)
            dismiss()
        }
  
        // On click listener on cancel text to close dialog box
        tvCancel.setOnClickListener {
            cancel()
        }
    }
}

步骤8:最后,在这一步中,我们将在MainActivity中进行编码。在我们的主要活动中,我们必须设置回收站视图,并在添加按钮上添加单击侦听器以打开对话框。转到MainActivity.kt文件,并参考以下代码。下面是MainActivity.kt文件的代码。在代码内部添加了注释,以更详细地了解代码。

科特林

package com.example.grocerylist.UI
  
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.grocerylist.Adapter.GroceryAdapter
import com.example.grocerylist.Database.Entity.GroceryItems
import com.example.grocerylist.Database.GroceryDatabase
import com.example.grocerylist.Database.GroceryRepository
import com.example.grocerylist.R
import kotlinx.android.synthetic.main.activity_main.*
  
class MainActivity : AppCompatActivity() {
      
    lateinit var ViewModel: GroceryViewModel
    lateinit var list: List
  
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
          
        val groceryRepository = GroceryRepository(GroceryDatabase(this))
        val factory = GroceryViewModelFactory(groceryRepository)
  
        // Initialised View Model
        ViewModel = ViewModelProvider(this, factory).get(GroceryViewModel::class.java)
        val groceryAdapter = GroceryAdapter(listOf(), ViewModel)
        rvList.layoutManager = LinearLayoutManager(this)
        rvList.adapter = groceryAdapter
          
        // To display all items in recycler view
        ViewModel.allGroceryItems().observe(this, Observer {
            groceryAdapter.list = it
            groceryAdapter.notifyDataSetChanged()
        })
          
        // on ClickListener on button to open dialog box
        btnAdd.setOnClickListener {
            GroceryItemDialog(this, object : DialogListener {
                override fun onAddButtonClicked(item: GroceryItems) {
                    ViewModel.insert(item)
                }
            }).show()
        }
    }
}

这就是完整的项目结构。

输出:

Github链接: https : //github.com/arpit-288/Fresh_Basket

想要一个节奏更快,更具竞争性的环境来学习Android的基础知识吗?
单击此处,前往由我们的专家精心策划的指南,以使您立即做好行业准备!