package vandy.mooc.common; import java.lang.ref.WeakReference; import java.util.HashMap; import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; import android.os.Bundle; import android.util.Log; /** * Retains and manages state information between runtime configuration * changes to an Activity. Plays the role of the "Originator" in the * Memento pattern. */ public class RetainedFragmentManager { /** * Debugging tag used by the Android logger. */ protected final String TAG = getClass().getSimpleName(); /** * Name used to identify the RetainedFragment. */ private final String mRetainedFragmentTag; /** * WeakReference to the FragmentManager. */ private final WeakReference<FragmentManager> mFragmentManager; /** * Reference to the RetainedFragment. */ private RetainedFragment mRetainedFragment; /** * Constructor initializes fields. */ public RetainedFragmentManager(FragmentManager fragmentManager, String retainedFragmentTag) { // Store a WeakReference to the Activity. mFragmentManager = new WeakReference<FragmentManager>(fragmentManager); // Store the tag used to identify the RetainedFragment. mRetainedFragmentTag = retainedFragmentTag; } /** * Initializes the RetainedFragment the first time it's called. * * @returns true if it's first time the method's been called, else * false. */ public boolean firstTimeIn() { try { // Find the RetainedFragment on Activity restarts. The // RetainedFragment has no UI so it must be referenced via // a tag. mRetainedFragment = (RetainedFragment) mFragmentManager.get().findFragmentByTag(mRetainedFragmentTag); // A value of null means it's the first time in, so there's // extra work to do. if (mRetainedFragment == null) { Log.d(TAG, "Creating new RetainedFragment " + mRetainedFragmentTag); // Create a new RetainedFragment. mRetainedFragment = new RetainedFragment(); // Commit this RetainedFragment to the FragmentManager. mFragmentManager.get().beginTransaction(). add(mRetainedFragment, mRetainedFragmentTag).commit(); return true; } // A value of non-null means it's not first time in. else { Log.d(TAG, "Returning existing RetainedFragment " + mRetainedFragmentTag); return false; } } catch (NullPointerException e) { Log.d(TAG, "NPE in firstTimeIn()"); return false; } } /** * Add the @a object with the @a key. */ public void put(String key, Object object) { mRetainedFragment.put(key, object); } /** * Add the @a object with its class name. */ public void put(Object object) { put(object.getClass().getName(), object); } /** * Get the object with @a key. */ @SuppressWarnings("unchecked") public <T> T get(String key) { return (T) mRetainedFragment.get(key); } /** * Return the Activity the RetainedFragment is attached to or null * if it's not currently attached. */ public Activity getActivity() { return mRetainedFragment.getActivity(); } /** * "Headless" Fragment that retains state information between * configuration changes. Plays the role of the "Memento" in the * Memento pattern. */ public static class RetainedFragment extends Fragment { /** * Maps keys to objects. */ private HashMap<String, Object> mData = new HashMap<String, Object>(); /** * Hook method called when a new instance of Fragment is * created. * * @param savedInstanceState * object that contains saved state information. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Ensure the data survives runtime configuration changes. setRetainInstance(true); } /** * Add the @a object with the @a key. */ public void put(String key, Object object) { mData.put(key, object); } /** * Add the @a object with its class name. */ public void put(Object object) { put(object.getClass().getName(), object); } /** * Get the object with @a key. */ @SuppressWarnings("unchecked") public <T> T get(String key) { return (T) mData.get(key); } } }