FragmentHostCallback.java revision 4f08e623f23cbb89881f35d3472b78d388b76dc9
1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.support.v4.app; 18 19import android.app.Activity; 20import android.content.Context; 21import android.content.Intent; 22import android.os.Bundle; 23import android.os.Handler; 24import android.support.annotation.Nullable; 25import android.support.v4.util.SimpleArrayMap; 26import android.util.AttributeSet; 27import android.view.LayoutInflater; 28import android.view.View; 29 30import java.io.FileDescriptor; 31import java.io.PrintWriter; 32 33/** 34 * Integration points with the Fragment host. 35 * <p> 36 * Fragments may be hosted by any object; such as an {@link Activity}. In order to 37 * host fragments, implement {@link FragmentHostCallback}, overriding the methods 38 * applicable to the host. 39 */ 40public abstract class FragmentHostCallback<E> extends FragmentContainer { 41 private final Activity mActivity; 42 final Context mContext; 43 private final Handler mHandler; 44 final int mWindowAnimations; 45 final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl(); 46 private SimpleArrayMap<String, LoaderManager> mAllLoaderManagers; 47 private LoaderManagerImpl mLoaderManager; 48 private boolean mCheckedForLoaderManager; 49 private boolean mLoadersStarted; 50 51 public FragmentHostCallback(Context context, Handler handler, int windowAnimations) { 52 this(null /*activity*/, context, handler, windowAnimations); 53 } 54 55 FragmentHostCallback(FragmentActivity activity) { 56 this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/); 57 } 58 59 FragmentHostCallback(Activity activity, Context context, Handler handler, 60 int windowAnimations) { 61 mActivity = activity; 62 mContext = context; 63 mHandler = handler; 64 mWindowAnimations = windowAnimations; 65 } 66 67 /** 68 * Print internal state into the given stream. 69 * 70 * @param prefix Desired prefix to prepend at each line of output. 71 * @param fd The raw file descriptor that the dump is being sent to. 72 * @param writer The PrintWriter to which you should dump your state. This will be closed 73 * for you after you return. 74 * @param args additional arguments to the dump request. 75 */ 76 public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 77 } 78 79 /** 80 * Return {@code true} if the fragment's state needs to be saved. 81 */ 82 public boolean onShouldSaveFragmentState(Fragment fragment) { 83 return true; 84 } 85 86 /** 87 * Return a {@link LayoutInflater}. 88 * See {@link Activity#getLayoutInflater()}. 89 */ 90 public LayoutInflater onGetLayoutInflater() { 91 return (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 92 } 93 94 /** 95 * Return the object that's currently hosting the fragment. If a {@link Fragment} 96 * is hosted by a {@link FragmentActivity}, the object returned here should be 97 * the same object returned from {@link Fragment#getActivity()}. 98 */ 99 @Nullable 100 public abstract E onGetHost(); 101 102 /** 103 * Invalidates the activity's options menu. 104 * See {@link FragmentActivity#supportInvalidateOptionsMenu()} 105 */ 106 public void onSupportInvalidateOptionsMenu() { 107 } 108 109 /** 110 * Starts a new {@link Activity} from the given fragment. 111 * See {@link FragmentActivity#startActivityForResult(Intent, int)}. 112 */ 113 public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode) { 114 if (requestCode != -1) { 115 throw new IllegalStateException( 116 "Starting activity with a requestCode requires a FragmentActivity host"); 117 } 118 mContext.startActivity(intent); 119 } 120 121 /** 122 * Return {@code true} if there are window animations. 123 */ 124 public boolean onHasWindowAnimations() { 125 return true; 126 } 127 128 /** 129 * Return the window animations. 130 */ 131 public int onGetWindowAnimations() { 132 return mWindowAnimations; 133 } 134 135 @Nullable 136 @Override 137 public View onFindViewById(int id) { 138 return null; 139 } 140 141 @Override 142 public boolean onHasView() { 143 return true; 144 } 145 146 Activity getActivity() { 147 return mActivity; 148 } 149 150 Context getContext() { 151 return mContext; 152 } 153 154 Handler getHandler() { 155 return mHandler; 156 } 157 158 FragmentManagerImpl getFragmentManagerImpl() { 159 return mFragmentManager; 160 } 161 162 LoaderManagerImpl getLoaderManagerImpl() { 163 if (mLoaderManager != null) { 164 return mLoaderManager; 165 } 166 mCheckedForLoaderManager = true; 167 mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true /*create*/); 168 return mLoaderManager; 169 } 170 171 void inactivateFragment(String who) { 172 //Log.v(TAG, "invalidateSupportFragment: who=" + who); 173 if (mAllLoaderManagers != null) { 174 LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who); 175 if (lm != null && !lm.mRetaining) { 176 lm.doDestroy(); 177 mAllLoaderManagers.remove(who); 178 } 179 } 180 } 181 182 void onAttachFragment(Fragment fragment) { 183 } 184 185 void doLoaderStart() { 186 if (mLoadersStarted) { 187 return; 188 } 189 mLoadersStarted = true; 190 191 if (mLoaderManager != null) { 192 mLoaderManager.doStart(); 193 } else if (!mCheckedForLoaderManager) { 194 mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false); 195 // the returned loader manager may be a new one, so we have to start it 196 if ((mLoaderManager != null) && (!mLoaderManager.mStarted)) { 197 mLoaderManager.doStart(); 198 } 199 } 200 mCheckedForLoaderManager = true; 201 } 202 203 // retain -- whether to stop the loader or retain it 204 void doLoaderStop(boolean retain) { 205 if (mLoaderManager == null) { 206 return; 207 } 208 209 if (!mLoadersStarted) { 210 return; 211 } 212 mLoadersStarted = false; 213 214 if (retain) { 215 mLoaderManager.doRetain(); 216 } else { 217 mLoaderManager.doStop(); 218 } 219 } 220 221 void doLoaderRetain() { 222 if (mLoaderManager == null) { 223 return; 224 } 225 mLoaderManager.doRetain(); 226 } 227 228 void doLoaderDestroy() { 229 if (mLoaderManager == null) { 230 return; 231 } 232 mLoaderManager.doDestroy(); 233 } 234 235 void reportLoaderStart() { 236 if (mAllLoaderManagers != null) { 237 final int N = mAllLoaderManagers.size(); 238 LoaderManagerImpl loaders[] = new LoaderManagerImpl[N]; 239 for (int i=N-1; i>=0; i--) { 240 loaders[i] = (LoaderManagerImpl) mAllLoaderManagers.valueAt(i); 241 } 242 for (int i=0; i<N; i++) { 243 LoaderManagerImpl lm = loaders[i]; 244 lm.finishRetain(); 245 lm.doReportStart(); 246 } 247 } 248 } 249 250 LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) { 251 if (mAllLoaderManagers == null) { 252 mAllLoaderManagers = new SimpleArrayMap<String, LoaderManager>(); 253 } 254 LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who); 255 if (lm == null) { 256 if (create) { 257 lm = new LoaderManagerImpl(who, this, started); 258 mAllLoaderManagers.put(who, lm); 259 } 260 } else { 261 lm.updateHostController(this); 262 } 263 return lm; 264 } 265 266 SimpleArrayMap<String, LoaderManager> retainLoaderNonConfig() { 267 boolean retainLoaders = false; 268 if (mAllLoaderManagers != null) { 269 // prune out any loader managers that were already stopped and so 270 // have nothing useful to retain. 271 final int N = mAllLoaderManagers.size(); 272 LoaderManagerImpl loaders[] = new LoaderManagerImpl[N]; 273 for (int i=N-1; i>=0; i--) { 274 loaders[i] = (LoaderManagerImpl) mAllLoaderManagers.valueAt(i); 275 } 276 for (int i=0; i<N; i++) { 277 LoaderManagerImpl lm = loaders[i]; 278 if (lm.mRetaining) { 279 retainLoaders = true; 280 } else { 281 lm.doDestroy(); 282 mAllLoaderManagers.remove(lm.mWho); 283 } 284 } 285 } 286 287 if (retainLoaders) { 288 return mAllLoaderManagers; 289 } 290 return null; 291 } 292 293 void restoreLoaderNonConfig(SimpleArrayMap<String, LoaderManager> loaderManagers) { 294 mAllLoaderManagers = loaderManagers; 295 } 296 297 void dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 298 writer.print(prefix); writer.print("mLoadersStarted="); 299 writer.println(mLoadersStarted); 300 if (mLoaderManager != null) { 301 writer.print(prefix); writer.print("Loader Manager "); 302 writer.print(Integer.toHexString(System.identityHashCode(mLoaderManager))); 303 writer.println(":"); 304 mLoaderManager.dump(prefix + " ", fd, writer, args); 305 } 306 } 307} 308