一発ネタです。ViewModelをkey指定で取得するとき、同じkeyで異なるViewModelのインスタンスを取得しようとするとはまります。必ずモデルクラスごとにkeyが異なるように名前空間に注意が必要というお話。
要約
通常ViewModelを取得するときは、以下のようにViewModelProviderから取得します。拡張関数のviewModels()なども最終的には同じことをやっています。
val hogeViewModel = ViewModelProvider(this).get(HogeViewModel::class.java)
val fugaViewModel = ViewModelProvider(this).get(FugaViewModel::class.java)
通常、各ViewModelはインスタンスが複数必要なことはないのでこれで良いですが、例えば、ViewPagerの各Fragment用のViewModel等は、FragmentスコープではなくActivityスコープにする必要があり、ページごとに異なるインスタンスをActivityのViewModelStoreに保持してもらう必要があります。そのような場合、getにkeyを指定して、
val pageKey = requireArguments().getInt(ARG_SECTION_NUMBER).toString()
val hogeViewModel = ViewModelProvider(this).get(key, HogeViewModel::class.java)
のように使います。
さて、このFragmentでViewModelがもう一つ必要になった場合、
val pageKey = requireArguments().getInt(ARG_SECTION_NUMBER).toString()
val hogeViewModel = ViewModelProvider(requireActivity()).get(key, HogeViewModel::class.java)
val fugaViewModel = ViewModelProvider(requireActivity()).get(key, FugaViewModel::class.java)
としてはいけません。
例えば以下のように、keyがモデルクラスごとに異なる値となるような工夫が必要です。
val pageKey = requireArguments().getInt(ARG_SECTION_NUMBER).toString()
val hogeViewModel = ViewModelProvider(requireActivity())
    .get(HogeViewModel::class.qualifiedName + ":" + key, HogeViewModel::class.java)
val fugaViewModel = ViewModelProvider(requireActivity())
    .get(HogeViewModel::class.qualifiedName + ":" + key, FugaViewModel::class.java)
なぜか
ソースコードを追ってみましょう。
private static final String DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey";
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
    String canonicalName = modelClass.getCanonicalName();
    if (canonicalName == null) {
        throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
    }
    return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
    ViewModel viewModel = mViewModelStore.get(key);
    if (modelClass.isInstance(viewModel)) {
        if (mFactory instanceof OnRequeryFactory) {
            ((OnRequeryFactory) mFactory).onRequery(viewModel);
        }
        return (T) viewModel;
    } else {
        //noinspection StatementWithEmptyBody
        if (viewModel != null) {
            // TODO: log a warning.
        }
    }
    if (mFactory instanceof KeyedFactory) {
        viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
    } else {
        viewModel = mFactory.create(modelClass);
    }
    mViewModelStore.put(key, viewModel);
    return (T) viewModel;
}
このように、keyを指定しない場合DEFAULT_KEY + ":" + canonicalNameをkeyとしてgetがコールされています。
keyを指定したgetの中身を見てみると、mViewModelStoreからkeyを使って、ViewModelを取り出し、モデルクラスとクラスが一致しているかを確認しています。ViewModelStoreはHashMapのラッパーの用なもので、一つのkeyに一つのインスタンスしか保持できません。
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
    ...
    return (T) viewModel;
クラスが異なる場合、その後の処理に流れ、新規でViewModelのインスタンスが作られ、ViewModelStoreにkeyを使って格納されます。当然、そのkeyで格納されていた別のViewModelは上書きされ保持されなくなります。
elseの分岐で// TODO: log a warning.とあるように、エラーログを出す予定らしいですね。
つまり、冒頭で書いたように
val pageKey = requireArguments().getInt(ARG_SECTION_NUMBER).toString()
val hogeViewModel = ViewModelProvider(requireActivity()).get(key, HogeViewModel::class.java)
val fugaViewModel = ViewModelProvider(requireActivity()).get(key, FugaViewModel::class.java)
ということをすると、最初にHogeViewModelが作られ、FugaViewModelで上書きされ、次回も同様にと、毎回ViewModelのインスタンスが作り直されることになるため、意図と異なる挙動になってしまいます。
keyを指定しない場合は、内部でクラス名がkeyに使われているので、モデルクラスが異なれば別のkeyで格納され、問題無く動作するだけに、挙動をよく理解しないで使ってしまうとはまってしまいます。
ViewModelは複数使わないということであれば単純なkeyでもかまわないかもしれませんが、少なくとも複数つかう必要がある場合は、keyにモデルクラス名を追加するなどして、名前空間が分かれるように工夫する必要があります。
val pageKey = requireArguments().getInt(ARG_SECTION_NUMBER).toString()
val hogeViewModel = ViewModelProvider(requireActivity())
    .get(HogeViewModel::class.qualifiedName + ":" + key, HogeViewModel::class.java)
val fugaViewModel = ViewModelProvider(requireActivity())
    .get(HogeViewModel::class.qualifiedName + ":" + key, FugaViewModel::class.java)
さすがにこれは冗長なので、拡張関数などをつくってシンプルにするのが良いでしょう。
以上です。