お首が長いのよお首が長いのよ

チラシの裏よりお届けするソフトウェアエンジニアとして成長したい人のためのブログ

2020-06-11

by viewModels() | ActivityViewModelsでClassCastException

結論

fragment-ktx 1.1.0-alpha04を使っている場合はアップデートする

経緯

ActivityやFragmentでViewModelインスタンスを取得する際、ViewModelProviders.ofを使って生成していたが、非推奨になっていた為、推奨方法に乗り換えようとした。

直接ViewModelProviderを使って生成する

FragmentのAndroid-KTXがAACViewModelの取得に便利だ

こちらの解説が大変丁寧に記述されており、かつわかりやすい内容だったのでbuild.gradleにバージョン情報も含めて記載した。

bash: title=app/build.gradle
1dependencies {
2    implementation 'androidx.fragment:fragment-ktx:1.1.0-alpha04'
3}
4
5
java: title=SomethingDetailFragment.kt
1class SomethingDetailFragment : Fragment() {
2
3    private lateinit var binding: SomethingDetailFragmentBinding
4
5     private val sharedViewModel: SomethingViewModel by activityViewModels()
6
7    override fun onCreateView(
8        inflater: LayoutInflater, container: ViewGroup?,
9        savedInstanceState: Bundle?
10    ): View? {
11        binding = SomethingDetailFragmentBinding.inflate(inflater, container, false)
12        binding.viewmodel = sharedViewModel
13
14        binding.viewmodel!!.sometnig.observe(viewLifecycleOwner, Observer {
15            val adapter = binding.SomethingDetailRv.adapter as SomethingDetailAdapter?
16            adapter?.setItem(it!!)
17            Log.v("SomethingDetail","Observe event!")
18        })
19        this.binding = binding
20
21        setHasOptionsMenu(true)
22        return binding.root
23
24    }
25

エラーの内容

ただし、バージョンが古い事と利用している何らかのライブラリと合わずエラーが発生してしまった。

java.lang.ClassCastException: com.example.android.app.screen.detail.SomethingDetailFragment cannot be cast to androidx.lifecycle.ViewModelStore
        at androidx.lifecycle.ViewModelLazy.getValue(ViewModelProvider.kt:53)
        at androidx.lifecycle.ViewModelLazy.getValue(ViewModelProvider.kt:41)
        at com.example.android.app.screen.detail.SomethingDetailFragment.getSharedViewModel(Unknown Source:2)
        at com.example.android.app.screen.detail.SomethingDetailFragment.onCreateView(SomethingDetailFragment.kt:30)
        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2698)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:310)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1185)
        at androidx.fragment.app.FragmentManager.addAddedFragments(FragmentManager.java:2222)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1995)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1951)
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1847)
        at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

試行錯誤

試行錯誤の末、バージョン情報を確認したところ、だいぶ古いものを使ってしまっていたことが判明した。

更新前

gradle: title=app/build.gradle(before)
1dependencies {
2    implementation 'androidx.fragment:fragment-ktx:1.1.0-alpha04'
3}
4

更新後

gradle: title=app/build.gradle(after)
1dependencies {
2    implementation 'androidx.fragment:fragment-ktx:1.2.4'
3}
4

反省

提供されている記事自体は大変参考になったし、一次情報と照らし合わせながら実装まで試みたは良いものの、バージョンの確認が甘かったなと反省。

参考

ありがとうございました

/以上

よかったらシェアしてください!