使用 Factory 将 ViewModel 注入 Fragment 时找不到 RoomDatabase 的实现

发布于 2025-01-11 02:45:46 字数 4492 浏览 0 评论 0原文

我正在努力解决视图模型注入问题。我一直在遵循教程并稍微更改了代码以适应我的需要,但应用程序崩溃了。
我有 App 类保存我的 DaggerComponent 及其模块。在它的 onCreate 里面我有:

component = DaggerAppComponent.builder().daoModule(DaoModule(this)).build()

My AppModule:

@Singleton
@Component(modules = [DaoModule::class, ViewModelModule::class])

interface AppComponent {

    val factory: ViewModelFactory
}

ViewModelModule :

@Module
abstract class ViewModelModule {

    @Binds
    @Singleton
    abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory

    @Binds
    @Singleton
    @IntoMap
    @ViewModelKey(TaskViewModel::class)
    abstract fun splashViewModel(viewModel: TaskViewModel): ViewModel

}

MyFactory:

@Singleton
class ViewModelFactory @Inject constructor(
    private val viewModels: MutableMap<Class<out ViewModel>,
            @JvmSuppressWildcards Provider<ViewModel>>
) : ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T =
        viewModels[modelClass]?.get() as T
}

我这里使用了 ViewModelKey、ViewModelModule 和 Factory,以及 Fragment 扩展函数来执行 Fragment viewmodel注射。我在网上找到了它,并在之前的项目中成功使用了它。这是我的 util 函数:

@MainThread
inline fun <reified VM : ViewModel> Fragment.daggerViewModels(
    noinline ownerProducer: () -> ViewModelStoreOwner = { this }
) = createViewModelLazy(
    VM::class,
    { ownerProducer().viewModelStore },
    { App.component.factory }
    )

和我的 DaoModule。

@Module
class DaoModule(private val app: Application) {

    @Provides
    @Singleton
    fun getDB(): TaskDatabase = TaskDatabase.getAppDatabase(context())

    @Provides
    @Singleton
    fun context(): Context = app.applicationContext

    @Provides
    fun  gettaskDao(taskDatabase: TaskDatabase) : TaskDao = taskDatabase.TaskDao()

}

我的实体:

@Entity(tableName = "userinfo")
data class Task(
    @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "id") val id: Int = 0,
    @ColumnInfo(name = "name") val name: String,
    @ColumnInfo(name = "email") val email: String,
    @ColumnInfo(name = "phone") val phone: String?
)

My TaskDatabase 如下:

@Database(entities = [Task::class], version = 1)
abstract class TaskDatabase : RoomDatabase() {

    abstract fun TaskDao(): TaskDao

    companion object {
        private var INSTANCE: TaskDatabase? = null

        fun getAppDatabase(context: Context): TaskDatabase {

            if (INSTANCE == null) {
                INSTANCE = Room.databaseBuilder(
                    context.applicationContext, TaskDatabase::class.java, "AppDBB"
                )
                    .allowMainThreadQueries()
                    .build()
            }
            return INSTANCE!!
        }
    }
}

My Dao 接口。

@Dao
interface TaskDao {


    @Query("SELECT * FROM userinfo")
    fun getAllTaskInfo(): List<Task>?

    @Insert
    fun insertTask(user: Task?)

    @Delete
    fun deleteTask(user: Task?)

    @Update
    fun updateTask(user: Task?)

}

现在我有一个逻辑可以在我的片段中初始化我的 TaskViewModel 并将观察者附加到我的任务列表。然而应用程序崩溃了。

在我的片段中,我有:

val viewModel: TaskViewModel by daggerViewModels { requireActivity() } 另外:

        DaggerFragmentComponent
            .builder()
            .appComponent((requireActivity().application as App).getAppComponent())
            .build()
            .inject(this)

        viewModel.allTaskList.observe(viewLifecycleOwner) {
         //   textView.text = it.toString()
        }


我的 TaskViewModel 类如下:

class TaskViewModel @Inject constructor(var taskDao: TaskDao) : ViewModel() {

    private var _allTaskList = MutableLiveData<List<Task>>()
    val allTaskList = _allTaskList as LiveData<List<Task>>

    init {
      
        getAllRecords()
    }
    
    private fun getAllRecords() = _allTaskList.postValue(taskDao.getAllTaskInfo())

    fun insertTask(task: Task) {
        taskDao.insertTask(task)
        getAllRecords()
    }
}

现在我知道这是很多代码,但是有人可以帮我解决这个问题吗?匕首看到它的图形,因为我可以构建项目,因此提供了所有依赖项。我在这里做错了什么?我的 logcat:

“在此处输入图像描述"

I am struggling with viewmodel injection. I have been following tutorials and changed the code a little bit in order to adjust it to my needs, but the app crashes.
I have App class holding my DaggerComponent with it's modules. Inside it's onCreate I have:

component = DaggerAppComponent.builder().daoModule(DaoModule(this)).build()

My AppModule:

@Singleton
@Component(modules = [DaoModule::class, ViewModelModule::class])

interface AppComponent {

    val factory: ViewModelFactory
}

ViewModelModule :

@Module
abstract class ViewModelModule {

    @Binds
    @Singleton
    abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory

    @Binds
    @Singleton
    @IntoMap
    @ViewModelKey(TaskViewModel::class)
    abstract fun splashViewModel(viewModel: TaskViewModel): ViewModel

}

MyFactory:

@Singleton
class ViewModelFactory @Inject constructor(
    private val viewModels: MutableMap<Class<out ViewModel>,
            @JvmSuppressWildcards Provider<ViewModel>>
) : ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T =
        viewModels[modelClass]?.get() as T
}

I used here ViewModelKey, ViewModelModule and Factory, and Fragment extension function to perform Fragment viewmodel injection. I found it online and used it succesfuly on previous projects. This is my util function:

@MainThread
inline fun <reified VM : ViewModel> Fragment.daggerViewModels(
    noinline ownerProducer: () -> ViewModelStoreOwner = { this }
) = createViewModelLazy(
    VM::class,
    { ownerProducer().viewModelStore },
    { App.component.factory }
    )

And my DaoModule.

@Module
class DaoModule(private val app: Application) {

    @Provides
    @Singleton
    fun getDB(): TaskDatabase = TaskDatabase.getAppDatabase(context())

    @Provides
    @Singleton
    fun context(): Context = app.applicationContext

    @Provides
    fun  gettaskDao(taskDatabase: TaskDatabase) : TaskDao = taskDatabase.TaskDao()

}

My entity:

@Entity(tableName = "userinfo")
data class Task(
    @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "id") val id: Int = 0,
    @ColumnInfo(name = "name") val name: String,
    @ColumnInfo(name = "email") val email: String,
    @ColumnInfo(name = "phone") val phone: String?
)

My TaskDatabase as follows:

@Database(entities = [Task::class], version = 1)
abstract class TaskDatabase : RoomDatabase() {

    abstract fun TaskDao(): TaskDao

    companion object {
        private var INSTANCE: TaskDatabase? = null

        fun getAppDatabase(context: Context): TaskDatabase {

            if (INSTANCE == null) {
                INSTANCE = Room.databaseBuilder(
                    context.applicationContext, TaskDatabase::class.java, "AppDBB"
                )
                    .allowMainThreadQueries()
                    .build()
            }
            return INSTANCE!!
        }
    }
}

My Dao interface.

@Dao
interface TaskDao {


    @Query("SELECT * FROM userinfo")
    fun getAllTaskInfo(): List<Task>?

    @Insert
    fun insertTask(user: Task?)

    @Delete
    fun deleteTask(user: Task?)

    @Update
    fun updateTask(user: Task?)

}

And now I have a logic to init my TaskViewModel inside my Fragment and attach observer to my Task List. However the app crashes.

Inside my fragment I have:

val viewModel: TaskViewModel by daggerViewModels { requireActivity() }
and also:

        DaggerFragmentComponent
            .builder()
            .appComponent((requireActivity().application as App).getAppComponent())
            .build()
            .inject(this)

        viewModel.allTaskList.observe(viewLifecycleOwner) {
         //   textView.text = it.toString()
        }


and my TaskViewModel class is as follows:

class TaskViewModel @Inject constructor(var taskDao: TaskDao) : ViewModel() {

    private var _allTaskList = MutableLiveData<List<Task>>()
    val allTaskList = _allTaskList as LiveData<List<Task>>

    init {
      
        getAllRecords()
    }
    
    private fun getAllRecords() = _allTaskList.postValue(taskDao.getAllTaskInfo())

    fun insertTask(task: Task) {
        taskDao.insertTask(task)
        getAllRecords()
    }
}

Now I understand that this is A LOT of code, but can somebody help me figure this out? The dagger sees it's graph as I can build the project, so all the dependencies are provided. What I did wrong here? My logcat:

enter image description here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

你曾走过我的故事 2025-01-18 02:45:46

我自己找到了解决方案。这个缺失了。

    implementation 'androidx.room:room-runtime:2.5.0-alpha01'

I found the solution myself. This was missing.

    implementation 'androidx.room:room-runtime:2.5.0-alpha01'
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文