【发布时间】:2021-02-11 18:43:24
【问题描述】:
我正在使用 Kotlin。我对 Java、Kotlin 和 Android 了解不多。我有两个表,Item 和 ItemOrderDetails。
我项目中的主要文件有:ItemDatabase、ItemDao、ItemOrderDetailsDao、Item、ItemOrderDetails、ItemRepository和ItemViewModel。
- 实体(Item & ItemOrderDetails)。
- DAO (ItemDao & ItemOrderDetailsDao)。
- 数据库(ItemDatabase)。
- 存储库 (ItemRepository)。
- ViewModel (ItemViewModel)。
首先需要检查数据是否存在。它应该像这样工作:
如果不存在数据,则预加载两个表中的所有数据。
如果表中已经存在数据,则更新数据,即将要预加载的数据和已经存在的数据合并。如果在这种情况下存在相同数据的副本,则覆盖数据。
请告诉我如何更改 ItemDatabase.kt,以实现这一点。
日志
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.itemapp, PID: 24878
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.itemapp/com.example.itemapp.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class com.example.itemapp.viewmodel.ItemViewModel
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2817)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2895)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1616)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:6651)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:824)
Caused by: java.lang.RuntimeException: Cannot create an instance of class com.example.itemapp.viewmodel.ItemViewModel
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:275)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:106)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
at com.example.itemapp.fragments.list.ListFragment.onCreateView(ListFragment.kt:43)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2699)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:320)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1199)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1368)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1446)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1509)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2637)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:2589)
at androidx.fragment.app.Fragment.performActivityCreated(Fragment.java:2723)
at androidx.fragment.app.FragmentStateManager.activityCreated(FragmentStateManager.java:346)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1200)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1368)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1446)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1509)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2637)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:2589)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:247)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:541)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:210)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1335)
at android.app.Activity.performStart(Activity.java:7108)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2780)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2895)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1616)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:6651)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:824)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:334)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:267)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:106)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
at com.example.itemapp.fragments.list.ListFragment.onCreateView(ListFragment.kt:43)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2699)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:320)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1199)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1368)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1446)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1509)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2637)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:2589)
at androidx.fragment.app.Fragment.performActivityCreated(Fragment.java:2723)
at androidx.fragment.app.FragmentStateManager.activityCreated(FragmentStateManager.java:346)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1200)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1368)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1446)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1509)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2637)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:2589)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:247)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:541)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:210)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1335)
at android.app.Activity.performStart(Activity.java:7108)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2780)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2895)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1616)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:6651)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:824)
Caused by: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
at androidx.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:267)
at androidx.room.RoomDatabase.query(RoomDatabase.java:323)
at androidx.room.util.DBUtil.query(DBUtil.java:83)
at com.example.itemapp.data.ItemOrderDetailsDao_Impl.getAllItems(ItemOrderDetailsDao_Impl.java:109)
at com.example.itemapp.repository.ItemRepository.<init>(ItemRepository.kt:15)
at com.example.itemapp.viewmodel.ItemViewModel.<init>(ItemViewModel.kt:24)
... 38 more
ListFragment.kt
class ListFragment : Fragment(), RecyclerView_1_Adapter.OnItemClickListener1 {
private lateinit var mItemViewModel: ItemViewModel
private lateinit var nItemViewModel: ItemViewModel
var itemList = mutableListOf<Item>()
mItemViewModel.addItems(DataFragment.item_data) // Error: Expecting member declaration.
private lateinit var recyclerView1_adapter: RecyclerView_1_Adapter
lateinit var recyclerView1 : RecyclerView
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_list, container, false)
recyclerView1_adapter = RecyclerView_1_Adapter(itemList, this)
recyclerView1 = view.recyclerview1
recyclerView1.layoutManager = LinearLayoutManager(requireContext())
recyclerView1.adapter = recyclerView1_adapter
// ItemViewModel
mItemViewModel = ViewModelProvider(this).get(ItemViewModel::class.java)
nItemViewModel.addItems(DataFragment.item_data)
nItemViewModel.insertItems(DataFragment.item_order_details_data)
mItemViewModel.readAllData.observe(viewLifecycleOwner, Observer { item ->
recyclerView1_adapter.setData(item)
})
return view
}
}
RecyclerView_1_Adapter.kt
class RecyclerView_1_Adapter (
var itemList: MutableList<Item>, // = mutableListOf<Item>()
val listener1: OnItemClickListener1
) : RecyclerView.Adapter<RecyclerView_1_Adapter.RecyclerView_1_DataViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView_1_DataViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.recyview1_row, parent, false)
return RecyclerView_1_DataViewHolder(view)
}
override fun getItemCount(): Int {
return itemList.size
}
override fun onBindViewHolder(holder: RecyclerView_1_DataViewHolder, position: Int) {
val currentItem = itemList[position]
holder.itemView.apply {
firstName_list.text = currentItem.firstName
lastName_list.text = currentItem.lastName
}
}
inner class RecyclerView_1_DataViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
View.OnClickListener {
init {
itemView.setOnClickListener(this)
}
override fun onClick(v: View?) {
val position = adapterPosition
val currentItem2 = itemList[position]
if (position != RecyclerView.NO_POSITION) {
listener1.onItemClick1(position, currentItem2)
}
}
}
interface OnItemClickListener1 {
fun onItemClick1(position: Int, currentItem1: Item)
}
fun setData(item: MutableList<Item>){
this.itemList = item
notifyDataSetChanged()
}
}
ItemDao.kt(更新)
@Dao
interface ItemDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun addItem(item: Item)
// suspend fun insertItems(item: Item)
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun addItems(items: List<Item>)
@Update
suspend fun updateItem(item: Item)
@Delete
suspend fun deleteItem(item: Item)
@Query("DELETE FROM item_table")
suspend fun deleteAllItems()
@Query("SELECT * FROM item_table ORDER BY id ASC")
fun readAllData(): LiveData<MutableList<Item>>
}
ItemOrderDetailsDao.kt(更新)
@Dao
interface ItemOrderDetailsDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertItem(items: ItemOrderDetails)
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertItems(item: List<ItemOrderDetails>)
@Query("SELECT * FROM item_order_details_table ORDER BY id ASC")
fun getAllItems(): MutableList<ItemOrderDetails>
}
ItemRepository.kt(更新)
class ItemRepository(
private val itemDao: ItemDao,
private val itemOrderDetailsDao: ItemOrderDetailsDao
) {
val readAllData: LiveData<MutableList<Item>> = itemDao.readAllData()
val getAllItems: MutableList<ItemOrderDetails> = itemOrderDetailsDao.getAllItems()
/*suspend fun readAllData(user: Item){
itemDao.readAllData(LiveData<List<Item>>)
}*/
suspend fun addItem(item: Item){
itemDao.addItem(item)
}
suspend fun insertItem(item: ItemOrderDetails) {
itemOrderDetailsDao.insertItem(item)
}
suspend fun addItems(items: List<Item>){
itemDao.addItems(items)
}
suspend fun insertItems(items: List<ItemOrderDetails>){
itemOrderDetailsDao.insertItems(items)
}
suspend fun updateItem(item: Item){
itemDao.updateItem(item)
}
suspend fun deleteItem(item: Item){
itemDao.deleteItem(item)
}
suspend fun deleteAllItems(){
itemDao.deleteAllItems()
}
}
ItemViewModel.kt(更新)
class ItemViewModel(application: Application): AndroidViewModel(application) {
val readAllData: LiveData<MutableList<Item>>
val getAllItems: MutableList<ItemOrderDetails>
private val repository: ItemRepository
init {
val itemDao = App.db.itemDao()
val itemOrderDetailsDao = App.db.itemOrderDetailsDao()
// val itemDao = ItemDatabase.getDatabase(application).userDao()
repository = ItemRepository(itemDao, itemOrderDetailsDao)
readAllData = repository.readAllData
getAllItems = repository.getAllItems
}
fun addItem(item: Item){
viewModelScope.launch(Dispatchers.IO) {
repository.addItem(item)
}
}
fun insertItem(item: ItemOrderDetails) {
viewModelScope.launch(Dispatchers.IO) {
repository.insertItem(item)
}
}
fun addItems(items: List<Item>){
viewModelScope.launch(Dispatchers.IO) {
repository.addItems(items)
}
}
fun insertItems(items: List<ItemOrderDetails>){
viewModelScope.launch(Dispatchers.IO) {
repository.insertItems(items)
}
}
fun updateItem(item: Item){
viewModelScope.launch(Dispatchers.IO) {
repository.updateItem(item)
}
}
fun deleteItem(item: Item){
viewModelScope.launch(Dispatchers.IO) {
repository.deleteItem(item)
}
}
fun deleteAllItems(){
viewModelScope.launch(Dispatchers.IO) {
repository.deleteAllItems()
}
}
App.db.itemDao().addItemsFromFragment(DataFragment.item_data) // Expecting member declaration
App.db.itemOrderDetailsDao().insertItemsFromFragment(DataFragment.item_order_details_data) // Expecting member declaration
}
DataFragment.kt(更新)
class DataFragment {
companion object Data{
var item_order : Int = 0
var item_order_alert : Int = 0
var selectedItems1 = arrayOf<Int>(0)
var item_details_list = mutableListOf<ItemDetails>()
val item_data = listOf(
Item(0, "first_name_1", "last_name_1", "item_value_a_1"),
Item(0, "first_name_2", "last_name_2", "item_value_a_2"),
Item(0, "first_name_3", "last_name_3", "item_value_a_3")
)
val item_order_details_data = listOf(
ItemOrderDetails(0, "item_group_1", "item_name_1", "item-value_b_1", "item_base_1", "item_up_1"),
ItemOrderDetails(0, "item_group_2", "item_name_2", "item-value_b_2", "item_base_2", "item_up_2"),
ItemOrderDetails(0, "item_group_3", "item_name_3", "item-value_b_3", "item_base_3", "item_up_3")
)
fun addItemsFromFragment(items: List<Item>){
viewModel.addItems(items)
}
fun insertItemsFromFragment(items: List<ItemOrderDetails>){
viewModel.insertItems(items)
}
}
}
MainActivity.kt(更新)
package com.example.itemapp
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.findNavController
import androidx.navigation.ui.setupActionBarWithNavController
import com.example.itemapp.data.App
import com.example.itemapp.fragments.add.DataFragment
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupActionBarWithNavController(findNavController(R.id.fragment))
App.db.itemDao().addItemsFromFragment(DataFragment.item_data)
App.db.itemOrderDetailsDao().insertItemsFromFragment(DataFragment.item_order_details_data)
// Error - Unresolved reference: addItemsFromFragment
// Error - Unresolved reference: insertItemsFromFragment
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.fragment)
return navController.navigateUp() || super.onSupportNavigateUp()
}
}
ItemDatabase.kt(更新)
package com.example.itemapp.data
import androidx.room.Database
import androidx.room.RoomDatabase
import com.example.itemapp.model.Item
import com.example.itemapp.model.ItemOrderDetails
@Database(
entities = [
Item::class,
ItemOrderDetails::class
], version = 1, exportSchema = false)
abstract class ItemDatabase : RoomDatabase() {
// abstract fun userDao(): ItemDao
abstract fun getItemDao(): ItemDao
abstract fun getItemDetailsDao(): ItemOrderDetailsDao
/*companion object {
@Volatile
private var INSTANCE: ItemDatabase? = null
fun getDatabase(context: Context): ItemDatabase {
val tempInstance = INSTANCE
if (tempInstance != null) {
return tempInstance
}
synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
ItemDatabase::class.java,
"item_database"
).build()
INSTANCE = instance
return instance
}
}
}*/
}
DbRepository.kt(更新)
package com.example.itemapp.data
import android.content.Context
import androidx.room.Room
// Adding a new class to access DB.
class DbRepository (private val database: ItemDatabase) {
companion object {
private var instance: DbRepository? = null
fun getInstance(context: Context): DbRepository {
return instance ?: synchronized(this) {
instance ?: DbRepository(initializeDb(context)).also { instance = it }
}
}
private fun initializeDb(context: Context): ItemDatabase {
return Room.databaseBuilder(
context,
ItemDatabase::class.java, "ItemDb"
).build()
}
}
fun itemDao():ItemDao = database. getItemDao()
fun itemDetailsDao():ItemOrderDetailsDao = database.getItemDetailsDao()
}
App.kt(更新)
package com.example.itemapp.data
import android.app.Application
// Creating a single instance of the DbRepository throughout the app. It is done in App class.
class App : Application() {
companion object {
lateinit var db: DbRepository
}
override fun onCreate() {
super.onCreate()
db = DbRepository.getInstance(applicationContext)
}
}
/*You can access the App class from any class of that module like this:
App.db.itemDao().insertItems(data)
Note: Remember to call these DB functions on a background thread.*/
AndroidManifest.xml(更新)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.itemapp">
<application
android:name=".App" // Error.
/* Class referenced in the manifest, com.example.itemapp.App, was not
found in the project or the libraries. Unresolved class 'App' */
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/AppTheme">
<activity android:name="com.example.itemapp.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
项目.kt
package com.example.itemapp.model
import android.os.Parcelable
import androidx.room.Entity
import androidx.room.PrimaryKey
import kotlinx.android.parcel.Parcelize
@Parcelize
@Entity(tableName = "item_table")
data class Item(
@PrimaryKey(autoGenerate = true)
val id: Int,
val firstName: String,
val lastName: String,
val item_value_a: String = "0"
): Parcelable
ItemOrderDetails.kt
package com.example.itemapp.model
import android.os.Parcelable
import androidx.room.Entity
import androidx.room.PrimaryKey
import kotlinx.android.parcel.Parcelize
@Parcelize
@Entity(tableName = "item_order_details_table")
data class ItemOrderDetails(
@PrimaryKey(autoGenerate = true)
val id: Int,
val item_group: String,
val item_name: String,
val item_value_b: String = "0",
val item_base: String,
val item_up: String
): Parcelable
表格的数据是...
Item.kt 数据
val item_data = listOf(
Item("first_name_1", "last_name_1", "item_value_a_1"),
Item("first_name_2", "last_name_2", "item_value_a_2"),
Item("first_name_3", "last_name_3", "item_value_a_3")
)
ItemOrderDetails.kt 数据
val item_order_details_data = listOf(
ItemOrderDetails("item_group_1", "item_name_1", "item-value_b_1", "item_base_1", "item_up_1"),
ItemOrderDetails("item_group_2", "item_name_2", "item-value_b_2", "item_base_2", "item_up_2"),
ItemOrderDetails("item_group_3", "item_name_3", "item-value_b_3", "item_base_3", "item_up_3")
)
【问题讨论】:
-
您要ROOM操作吗?
-
我只想有人给我我的 ItemDatabase.kt 文件的代码,即根据我的问题的代码。我读了很多关于这个的东西。我需要正确的代码来实现我的问题中描述的那些功能。
-
为了预加载数据,ItemDatabase.kt 文件需要一些额外的代码。我有两张桌子。我不知道该怎么做。
标签: android kotlin android-room