概要:複数のLiveDataObserversは、新しいフラグメントにナビゲートした後、フラグメントでトリガーされ、ポップします新しいフラグメント、および元のフラグメントに戻ります。
詳細:アーキテクチャは、HomeFragmentをホストするMainActivityで構成されます開始先 MainActivityのナビゲーショングラフ。 HomeFragment内には、プログラムで膨らんだPriceGraphFragmentがあります。 HomeFragmentは、ナビゲーションコンポーネントを使用して、新しい子FragmentProfileFragmentを起動しています。バックプレスでProfileFragmentがポップされ、アプリはPriceGraphFragmentをホストしているHomeFragmentに戻ります。 PriceGraphFragmentは、オブザーバーが複数回呼び出される場所です。
オブザーバーによって発行されているHashMapのハッシュコードを記録しており、プロファイルFragmentに移動してプロファイルFragmentをポップし、価格Fragmentに戻ると、2つの一意のハッシュコードを表示しています。これは、プロファイルフラグメントを起動せずに画面を回転させたときにHashMapから表示される1つのハッシュコードとは対照的です。
HomeFragment内で新しいProfileFragmentを起動するナビゲーションコンポーネント。
view.setOnClickListener(Navigation.createNavigateOnClickListener( R.id.action_homeFragment_to_profileFragment, null))
ViewModelFragment(PriceGraphFragment)での作成。 ViewModelがログに記録されており、複数のオブザーバーを持つデータのデータは、ViewModelで1回だけ初期化されています。
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) priceViewModel = ViewModelProviders.of(this).get(PriceDataViewModel::class.Java) }
元のフラグメント(PriceGraphFragment)のViewModelからのデータをリッスンします。これは複数回呼び出されていますが、フラグメントがロードされるときに1つのオブザーバーのみが存在することが予想されます。
priceViewModel.graphLiveData.observe( this, Observer { priceGraphDataMap: HashMap<Exchange, PriceGraphLiveData>? -> // This is being called multiple times. })
priceViewModel = ViewModelProviders.of(this).get(PriceDataViewModel::class.Java)
Fragmentのアクティビティと子Fragmentの親Fragmentを使用してViewModelを作成します。priceViewModel = ViewModelProviders.of(activity!!).get(PriceDataViewModel::class.Java)
priceViewModel = ViewModelProviders.of(parentFragment!!).get(PriceDataViewModel::class.Java)
observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)
のLifecycleOwnerにviewLifecycleOwner
の代わりにthis
を使用します。ChildFragmentManager
およびSupportFragmentManager
(アクティビティレベル)を使用して子フラグメントを起動します。onViewCreated()
?ParentFragment
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
user = viewModel.getCurrentUser()
if (savedInstanceState == null) {
fragmentManager
?.beginTransaction()
?.replace(binding.priceDataContainer.id,
PriceGraphFragment.newInstance())
?.commit()
}
まず、ここに投稿したすべての人に感謝します。複数の問題が関係していたため、過去5日間でこのバグを解決するのに役立ったのは、あなたのアドバイスとポインターの組み合わせでした。
前:
_override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
if (savedInstanceState == null) {
fragmentManager
?.beginTransaction()
?.add(binding.priceDataContainer.id, PriceGraphFragment.newInstance())
?.commit()
fragmentManager
?.beginTransaction()
?.add(binding.contentFeedContainer.id, ContentFeedFragment.newInstance())
?.commit()
}
...
}
_
後:
_override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
if (savedInstanceState == null
&& childFragmentManager.findFragmentByTag(PRICEGRAPH_FRAGMENT_TAG) == null
&& childFragmentManager.findFragmentByTag(CONTENTFEED_FRAGMENT_TAG) == null) {
childFragmentManager.beginTransaction()
.replace(priceDataContainer.id, PriceGraphFragment.newInstance(),
PRICEGRAPH_FRAGMENT_TAG)
.commit()
childFragmentManager.beginTransaction()
.replace(contentFeedContainer.id, ContentFeedFragment.newInstance(),
CONTENTFEED_FRAGMENT_TAG)
.commit()
}
...
}
_
親と子の両方のフラグメントに対してonCreate()
ではなくonCreateView()
でViewModel sを作成します。
onCreate()
ではなくonViewCreated()
の子Fragment(PriceFragment)のデータ(Firebase Firestoreクエリ)データのリクエストを初期化していますが、saveInstanceStateが-の場合のみnull。
いくつかの項目が提案されましたが、このバグの解決には影響がないことが判明しました。
onActivityCreated()
でObserversを作成しています。私は、子Fragment(PriceFragment)のonViewCreated()
に私のものを保持しています。
Observer作成でviewLifecycleOwner
を使用します。以前は、子フラグメント(PriceFragment)のthis
を使用していました。 viewLifecycleOwner
はこのバグに影響を与えませんが、全体としてはベストプラクティスであると思われるため、この新しい実装を維持しています。
これは基本的にアーキテクチャのバグです。詳しくは こちら をご覧ください。 getViewLifecycleOwner
でこれの代わりにobserver
を使用することで解決できます。
このような:
_mViewModel.methodToObserve().observe(getViewLifecycleOwner(), new Observer<Type>() {
@Override
public void onChanged(@Nullable Type variable) {
_
getViewLifecycleOwner
を使用するにはビューが必要なので、このコードをonActivityCreated()
に配置します。