我无法将 ViewModel 绑定(bind)到我的 Fragment(使用 lateinit
),因为我在 Activity 中创建 ViewModel 的方式出错了。我做错了什么?
Caused by: java.lang.RuntimeException: Cannot create an instance of class com.example.foo.FooViewModel
这是 Activity :
class FooActivity : AppCompatActivity() {
private lateinit var viewModel: FooViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_foo)
val id = intent.getLongExtra(FOO_ID, 1L)
val viewModelFactory = FooViewModelFactory(
id,
FooDatabase.getInstance(application).fooDao,
application)
viewModel = ViewModelProviders.of(
this, viewModelFactory).get(FooViewModel::class.java)
}
}
当 Fragment 尝试绑定(bind) viewModel 时实例化它时,会发生异常,请参阅下面注释的代码行:
class BlankFragment : Fragment() {
private val viewModel: FooViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
super.onCreateView(inflater, container, savedInstanceState)
val binding = FragmentBlankBinding.inflate(inflater)
binding.setLifecycleOwner(this)
// EXCEPTION OCCURS HERE
binding.viewModel = viewModel
return binding.root
}
}
这是 ViewModel 和 ViewModelFactory 类的代码:
class FooViewModelFactory (
private val id: Long,
private val fooDao: FooDao,
private val application: Application) : ViewModelProvider.Factory {
@Suppress("unchecked_cast")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(FooViewModel::class.java)) {
return FooViewModel(
id,
fooDao,
application
) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
class FooViewModel(id: Long, fooDao : FooDao, app: Application ): AndroidViewModel(app) {
private val _foo = MutableLiveData<Foo>()
val foo: LiveData<Foo>
get() = _foo
// infrastructure needed to get the Foo from the database
private val _database = fooDao
private val _fooid = id
private var viewModelJob = Job()
// database queries in the IO thread to avoid locking up the UI
private val ioScope = CoroutineScope(viewModelJob + Dispatchers.IO)
init {
// commenting this out and doing nothing doesn't affect exception in question.
GlobalScope.launch{ getFoo()}
}
private fun getFoo() = ... // code to fetch Foo from database
}
编辑:堆栈跟踪。
2020-05-22 22:10:05.018 8599-8599/com.example.foo E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.foo, PID: 8599
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.foo/com.example.foo.FooActivity}: android.view.InflateException: Binary XML file line #19: Binary XML file line #19: Error inflating class fragment
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3037)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3172)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1906)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6863)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: android.view.InflateException: Binary XML file line #19: Binary XML file line #19: Error inflating class fragment
Caused by: android.view.InflateException: Binary XML file line #19: Error inflating class fragment
Caused by: java.lang.RuntimeException: Cannot create an instance of class com.example.foo.FooViewModel
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:269)
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 androidx.lifecycle.ViewModelLazy.getValue(ViewModelProvider.kt:54)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelProvider.kt:41)
at com.example.foo.BlankFragment.getViewModel(Unknown Source:2)
at com.example.foo.BlankFragment.onCreateView(BlankFragment.kt:27)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2698)
at androidx.fragment.app.FragmentStateManager.ensureInflatedView(FragmentStateManager.java:218)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1183)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1356)
at androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:109)
at androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:135)
at androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:356)
at androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:335)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:780)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
at android.view.LayoutInflater.inflate(LayoutInflater.java:374)
at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:469)
at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:140)
at com.example.foo.FooActivity.onCreate(FooActivity.kt:29)
at android.app.Activity.performCreate(Activity.java:7149)
at android.app.Activity.performCreate(Activity.java:7140)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1288)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3017)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3172)
2020-05-22 22:10:05.019 8599-8599/com.example.foo E/AndroidRuntime: at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1906)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6863)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.NoSuchMethodException: <init> [class android.app.Application]
at java.lang.Class.getConstructor0(Class.java:2327)
at java.lang.Class.getConstructor(Class.java:1725)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:267)
... 40 more
最佳答案
问题是 by ActivityViewModels()
没有获得能够创建 View 模型的同一工厂。
应该是这样的:
class BlankFragment : Fragment() {
private val viewModel: FooViewModel by activityViewModels {
val application = requireActivity().application
FooViewModelFactory(
id,
FooDatabase.getInstance(application).fooDao,
application)
}
编辑:或者只提供 Activity 中的工厂实例。无论哪种方式,您都需要它来可靠地获取 FooViewModel
实例。
class FooActivity : AppCompatActivity() {
val viewModelFactory by lazy {
FooViewModelFactory(
intent.getLongExtra(FOO_ID, 1L),
FooDatabase.getInstance(application).fooDao,
application)
}
private val viewModel: FooViewModel by viewModels { viewModelFactory }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_foo)
}
}
还有
class BlankFragment : Fragment() {
private val viewModel: FooViewModel by activityViewModels {
(requireActivity() as FooActivity).viewModelFactory
}
关于android - 无法使用 ViewModelFactory 实例化我的 ViewModel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61963285/