| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.arch.lifecycle; |
| |
| import android.app.Activity; |
| import android.app.Application.ActivityLifecycleCallbacks; |
| import android.os.Bundle; |
| import android.support.annotation.NonNull; |
| import android.support.annotation.Nullable; |
| import android.support.annotation.RestrictTo; |
| import android.support.v4.app.Fragment; |
| import android.support.v4.app.FragmentActivity; |
| import android.support.v4.app.FragmentManager; |
| import android.support.v4.app.FragmentManager.FragmentLifecycleCallbacks; |
| import android.util.Log; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| /** |
| * @hide |
| */ |
| @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) |
| public class HolderFragment extends Fragment implements ViewModelStoreOwner { |
| private static final String LOG_TAG = "ViewModelStores"; |
| |
| private static final HolderFragmentManager sHolderFragmentManager = new HolderFragmentManager(); |
| |
| /** |
| * @hide |
| */ |
| @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) |
| public static final String HOLDER_TAG = |
| "android.arch.lifecycle.state.StateProviderHolderFragment"; |
| |
| private ViewModelStore mViewModelStore = new ViewModelStore(); |
| |
| public HolderFragment() { |
| setRetainInstance(true); |
| } |
| |
| @Override |
| public void onCreate(@Nullable Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| sHolderFragmentManager.holderFragmentCreated(this); |
| } |
| |
| @Override |
| public void onSaveInstanceState(Bundle outState) { |
| super.onSaveInstanceState(outState); |
| } |
| |
| @Override |
| public void onDestroy() { |
| super.onDestroy(); |
| mViewModelStore.clear(); |
| } |
| |
| @NonNull |
| @Override |
| public ViewModelStore getViewModelStore() { |
| return mViewModelStore; |
| } |
| |
| /** |
| * @hide |
| */ |
| @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) |
| public static HolderFragment holderFragmentFor(FragmentActivity activity) { |
| return sHolderFragmentManager.holderFragmentFor(activity); |
| } |
| |
| /** |
| * @hide |
| */ |
| @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) |
| public static HolderFragment holderFragmentFor(Fragment fragment) { |
| return sHolderFragmentManager.holderFragmentFor(fragment); |
| } |
| |
| @SuppressWarnings("WeakerAccess") |
| static class HolderFragmentManager { |
| private Map<Activity, HolderFragment> mNotCommittedActivityHolders = new HashMap<>(); |
| private Map<Fragment, HolderFragment> mNotCommittedFragmentHolders = new HashMap<>(); |
| |
| private ActivityLifecycleCallbacks mActivityCallbacks = |
| new EmptyActivityLifecycleCallbacks() { |
| @Override |
| public void onActivityDestroyed(Activity activity) { |
| HolderFragment fragment = mNotCommittedActivityHolders.remove(activity); |
| if (fragment != null) { |
| Log.e(LOG_TAG, "Failed to save a ViewModel for " + activity); |
| } |
| } |
| }; |
| |
| private boolean mActivityCallbacksIsAdded = false; |
| |
| private FragmentLifecycleCallbacks mParentDestroyedCallback = |
| new FragmentLifecycleCallbacks() { |
| @Override |
| public void onFragmentDestroyed(FragmentManager fm, Fragment parentFragment) { |
| super.onFragmentDestroyed(fm, parentFragment); |
| HolderFragment fragment = mNotCommittedFragmentHolders.remove( |
| parentFragment); |
| if (fragment != null) { |
| Log.e(LOG_TAG, "Failed to save a ViewModel for " + parentFragment); |
| } |
| } |
| }; |
| |
| void holderFragmentCreated(Fragment holderFragment) { |
| Fragment parentFragment = holderFragment.getParentFragment(); |
| if (parentFragment != null) { |
| mNotCommittedFragmentHolders.remove(parentFragment); |
| parentFragment.getFragmentManager().unregisterFragmentLifecycleCallbacks( |
| mParentDestroyedCallback); |
| } else { |
| mNotCommittedActivityHolders.remove(holderFragment.getActivity()); |
| } |
| } |
| |
| private static HolderFragment findHolderFragment(FragmentManager manager) { |
| if (manager.isDestroyed()) { |
| throw new IllegalStateException("Can't access ViewModels from onDestroy"); |
| } |
| |
| Fragment fragmentByTag = manager.findFragmentByTag(HOLDER_TAG); |
| if (fragmentByTag != null && !(fragmentByTag instanceof HolderFragment)) { |
| throw new IllegalStateException("Unexpected " |
| + "fragment instance was returned by HOLDER_TAG"); |
| } |
| return (HolderFragment) fragmentByTag; |
| } |
| |
| private static HolderFragment createHolderFragment(FragmentManager fragmentManager) { |
| HolderFragment holder = new HolderFragment(); |
| fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss(); |
| return holder; |
| } |
| |
| HolderFragment holderFragmentFor(FragmentActivity activity) { |
| FragmentManager fm = activity.getSupportFragmentManager(); |
| HolderFragment holder = findHolderFragment(fm); |
| if (holder != null) { |
| return holder; |
| } |
| holder = mNotCommittedActivityHolders.get(activity); |
| if (holder != null) { |
| return holder; |
| } |
| |
| if (!mActivityCallbacksIsAdded) { |
| mActivityCallbacksIsAdded = true; |
| activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks); |
| } |
| holder = createHolderFragment(fm); |
| mNotCommittedActivityHolders.put(activity, holder); |
| return holder; |
| } |
| |
| HolderFragment holderFragmentFor(Fragment parentFragment) { |
| FragmentManager fm = parentFragment.getChildFragmentManager(); |
| HolderFragment holder = findHolderFragment(fm); |
| if (holder != null) { |
| return holder; |
| } |
| holder = mNotCommittedFragmentHolders.get(parentFragment); |
| if (holder != null) { |
| return holder; |
| } |
| |
| parentFragment.getFragmentManager() |
| .registerFragmentLifecycleCallbacks(mParentDestroyedCallback, false); |
| holder = createHolderFragment(fm); |
| mNotCommittedFragmentHolders.put(parentFragment, holder); |
| return holder; |
| } |
| } |
| } |