Fragment.java revision b4bc78b16a05554c57508b488e21dd8eca4e13e6
1/* 2 * Copyright (C) 2010 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.app; 18 19import android.content.ComponentCallbacks; 20import android.content.res.Configuration; 21import android.os.Bundle; 22import android.os.Parcel; 23import android.os.Parcelable; 24import android.util.AttributeSet; 25import android.util.SparseArray; 26import android.view.LayoutInflater; 27import android.view.View; 28import android.view.ViewGroup; 29import android.view.animation.Animation; 30 31import java.lang.reflect.Constructor; 32import java.lang.reflect.InvocationTargetException; 33import java.util.HashMap; 34 35final class FragmentState implements Parcelable { 36 static final String VIEW_STATE_TAG = "android:view_state"; 37 38 final String mClassName; 39 final boolean mFromLayout; 40 final int mSavedStateId; 41 final int mFragmentId; 42 final int mContainerId; 43 final String mTag; 44 final boolean mRetainInstance; 45 46 Bundle mSavedFragmentState; 47 48 Fragment mInstance; 49 50 public FragmentState(Fragment frag) { 51 mClassName = frag.getClass().getName(); 52 mFromLayout = frag.mFromLayout; 53 mSavedStateId = frag.mSavedStateId; 54 mFragmentId = frag.mFragmentId; 55 mContainerId = frag.mContainerId; 56 mTag = frag.mTag; 57 mRetainInstance = frag.mRetainInstance; 58 } 59 60 public FragmentState(Parcel in) { 61 mClassName = in.readString(); 62 mFromLayout = in.readInt() != 0; 63 mSavedStateId = in.readInt(); 64 mFragmentId = in.readInt(); 65 mContainerId = in.readInt(); 66 mTag = in.readString(); 67 mRetainInstance = in.readInt() != 0; 68 mSavedFragmentState = in.readBundle(); 69 } 70 71 public Fragment instantiate(Activity activity) { 72 if (mFromLayout) { 73 return null; 74 } 75 76 if (mInstance != null) { 77 return mInstance; 78 } 79 80 try { 81 mInstance = Fragment.instantiate(activity, mClassName); 82 } catch (Exception e) { 83 throw new RuntimeException("Unable to restore fragment " + mClassName, e); 84 } 85 86 if (mSavedFragmentState != null) { 87 mSavedFragmentState.setClassLoader(activity.getClassLoader()); 88 mInstance.mSavedFragmentState = mSavedFragmentState; 89 mInstance.mSavedViewState 90 = mSavedFragmentState.getSparseParcelableArray(VIEW_STATE_TAG); 91 } 92 mInstance.mSavedStateId = mSavedStateId; 93 mInstance.mFragmentId = mFragmentId; 94 mInstance.mContainerId = mContainerId; 95 mInstance.mTag = mTag; 96 mInstance.mRetainInstance = mRetainInstance; 97 98 return mInstance; 99 } 100 101 public int describeContents() { 102 return 0; 103 } 104 105 public void writeToParcel(Parcel dest, int flags) { 106 dest.writeString(mClassName); 107 dest.writeInt(mFromLayout ? 1 : 0); 108 dest.writeInt(mSavedStateId); 109 dest.writeInt(mFragmentId); 110 dest.writeInt(mContainerId); 111 dest.writeString(mTag); 112 dest.writeInt(mRetainInstance ? 1 : 0); 113 dest.writeBundle(mSavedFragmentState); 114 } 115 116 public static final Parcelable.Creator<FragmentState> CREATOR 117 = new Parcelable.Creator<FragmentState>() { 118 public FragmentState createFromParcel(Parcel in) { 119 return new FragmentState(in); 120 } 121 122 public FragmentState[] newArray(int size) { 123 return new FragmentState[size]; 124 } 125 }; 126} 127 128/** 129 * A Fragment is a piece of an application's user interface or behavior 130 * that can be placed in an {@link Activity}. 131 */ 132public class Fragment implements ComponentCallbacks { 133 private static final Object[] sConstructorArgs = new Object[0]; 134 135 private static final Class[] sConstructorSignature = new Class[] { }; 136 137 private static final HashMap<String, Constructor> sConstructorMap = 138 new HashMap<String, Constructor>(); 139 140 static final int INITIALIZING = 0; // Not yet created. 141 static final int CREATED = 1; // Created. 142 static final int CONTENT = 2; // View hierarchy content available. 143 static final int STARTED = 3; // Created and started, not resumed. 144 static final int RESUMED = 4; // Created started and resumed. 145 146 int mState = INITIALIZING; 147 148 // When instantiated from saved state, this is the saved state. 149 Bundle mSavedFragmentState; 150 SparseArray<Parcelable> mSavedViewState; 151 152 // Set to true if this fragment was instantiated from a layout file. 153 boolean mFromLayout; 154 155 // Number of active back stack entries this fragment is in. 156 int mBackStackNesting; 157 158 // Activity this fragment is attached to. 159 Activity mActivity; 160 161 // The optional identifier for this fragment -- either the container ID if it 162 // was dynamically added to the view hierarchy, or the ID supplied in 163 // layout. 164 int mFragmentId; 165 166 // When a fragment is being dynamically added to the view hierarchy, this 167 // is the identifier of the parent container it is being added to. 168 int mContainerId; 169 170 // The optional named tag for this fragment -- usually used to find 171 // fragments that are not part of the layout. 172 String mTag; 173 174 // If set this fragment would like its instance retained across 175 // configuration changes. 176 boolean mRetainInstance; 177 178 // If set this fragment is being retained across the current config change. 179 boolean mRetaining; 180 181 // Used to verify that subclasses call through to super class. 182 boolean mCalled; 183 184 // The parent container of the fragment after dynamically added to UI. 185 ViewGroup mContainer; 186 187 // The View generated for this fragment. 188 View mView; 189 190 // Used for performing save state of fragments. 191 int mSavedStateSeq = 0; 192 int mSavedStateId; 193 194 public Fragment() { 195 } 196 197 static Fragment instantiate(Activity activity, String fname) 198 throws NoSuchMethodException, ClassNotFoundException, 199 IllegalArgumentException, InstantiationException, 200 IllegalAccessException, InvocationTargetException { 201 Constructor constructor = sConstructorMap.get(fname); 202 Class clazz = null; 203 204 if (constructor == null) { 205 // Class not found in the cache, see if it's real, and try to add it 206 clazz = activity.getClassLoader().loadClass(fname); 207 constructor = clazz.getConstructor(sConstructorSignature); 208 sConstructorMap.put(fname, constructor); 209 } 210 return (Fragment)constructor.newInstance(sConstructorArgs); 211 } 212 213 void restoreViewState() { 214 if (mSavedViewState != null) { 215 mView.restoreHierarchyState(mSavedViewState); 216 mSavedViewState = null; 217 } 218 } 219 220 /** 221 * Subclasses can not override equals(). 222 */ 223 @Override final public boolean equals(Object o) { 224 return super.equals(o); 225 } 226 227 /** 228 * Subclasses can not override hashCode(). 229 */ 230 @Override final public int hashCode() { 231 return super.hashCode(); 232 } 233 234 /** 235 * Return the identifier this fragment is known by. This is either 236 * the android:id value supplied in a layout or the container view ID 237 * supplied when adding the fragment. 238 */ 239 public int getId() { 240 return mFragmentId; 241 } 242 243 /** 244 * Get the tag name of the fragment, if specified. 245 */ 246 public String getTag() { 247 return mTag; 248 } 249 250 /** 251 * Return the Activity this fragment is currently associated with. 252 */ 253 public Activity getActivity() { 254 return mActivity; 255 } 256 257 /** 258 * Control whether a fragment instance is retained across Activity 259 * re-creation (such as from a configuration change). This can only 260 * be used with fragments not in the back stack. If set, the fragment 261 * lifecycle will be slightly different when an activity is recreated: 262 * <ul> 263 * <li> {@link #onDestroy()} will not be called (but {@link #onDetach()} still 264 * will be, because the fragment is being detached from its current activity). 265 * <li> {@link #onCreate(Bundle)} will not be called since the fragment 266 * is not being re-created. 267 * <li> {@link #onAttach(Activity)} and {@link #onReady(Bundle)} <b>will</b> 268 * still be called. 269 * </ul> 270 */ 271 public void setRetainInstance(boolean retain) { 272 mRetainInstance = retain; 273 } 274 275 public boolean getRetainInstance() { 276 return mRetainInstance; 277 } 278 279 /** 280 * Called when a fragment is being created as part of a view layout 281 * inflation, typically from setting the content view of an activity. 282 * 283 * @param activity The Activity that is inflating the fragment. 284 * @param attrs The attributes at the tag where the fragment is 285 * being created. 286 */ 287 public void onInflate(Activity activity, AttributeSet attrs) { 288 mCalled = true; 289 } 290 291 /** 292 * Called when a fragment is first attached to its activity. 293 * {@link #onCreate(Bundle)} will be called after this. 294 */ 295 public void onAttach(Activity activity) { 296 mCalled = true; 297 } 298 299 public Animation onCreateAnimation(int transit, boolean enter) { 300 return null; 301 } 302 303 /** 304 * Called to do initial creation of a fragment. This is called after 305 * {@link #onAttach(Activity)} and before {@link #onReady(Bundle)}. 306 * @param savedInstanceState If the fragment is being re-created from 307 * a previous saved state, this is the state. 308 */ 309 public void onCreate(Bundle savedInstanceState) { 310 mCalled = true; 311 } 312 313 /** 314 * Called to have the fragment instantiate its user interface view. 315 * This is optional, and non-graphical fragments can return null (which 316 * is the default implementation). This will be called between 317 * {@link #onCreate(Bundle)} and {@link #onReady(Bundle)}. 318 * 319 * @param inflater The LayoutInflater object that can be used to inflate 320 * any views in the fragment, 321 * @param container If non-null, this is the parent view that the fragment's 322 * UI should be attached to. The fragment should not add the view itself, 323 * but this can be used to generate the LayoutParams of the view. 324 * @param savedInstanceState If non-null, this fragment is being re-constructed 325 * from a previous saved state as given here. 326 * 327 * @return Return the View for the fragment's UI, or null. 328 */ 329 public View onCreateView(LayoutInflater inflater, ViewGroup container, 330 Bundle savedInstanceState) { 331 return null; 332 } 333 334 public View getView() { 335 return mView; 336 } 337 338 /** 339 * Called when the activity is ready for the fragment to run. This is 340 * most useful for fragments that use {@link #setRetainInstance(boolean)} 341 * instance, as this tells the fragment when it is fully associated with 342 * the new activity instance. This is called after {@link #onCreate(Bundle)} 343 * and before {@link #onStart()}. 344 * 345 * @param savedInstanceState If the fragment is being re-created from 346 * a previous saved state, this is the state. 347 */ 348 public void onReady(Bundle savedInstanceState) { 349 mCalled = true; 350 } 351 352 /** 353 * Called when the Fragment is visible to the user. This is generally 354 * tied to {@link Activity#onStart() Activity.onStart} of the containing 355 * Activity's lifecycle. 356 */ 357 public void onStart() { 358 mCalled = true; 359 } 360 361 /** 362 * Called when the fragment is visible to the user and actively running. 363 * This is generally 364 * tied to {@link Activity#onResume() Activity.onResume} of the containing 365 * Activity's lifecycle. 366 */ 367 public void onResume() { 368 mCalled = true; 369 } 370 371 public void onSaveInstanceState(Bundle outState) { 372 } 373 374 public void onConfigurationChanged(Configuration newConfig) { 375 mCalled = true; 376 } 377 378 /** 379 * Called when the Fragment is no longer resumed. This is generally 380 * tied to {@link Activity#onPause() Activity.onPause} of the containing 381 * Activity's lifecycle. 382 */ 383 public void onPause() { 384 mCalled = true; 385 } 386 387 /** 388 * Called when the Fragment is no longer started. This is generally 389 * tied to {@link Activity#onStop() Activity.onStop} of the containing 390 * Activity's lifecycle. 391 */ 392 public void onStop() { 393 mCalled = true; 394 } 395 396 public void onLowMemory() { 397 mCalled = true; 398 } 399 400 /** 401 * Called when the fragment is no longer in use. This is called 402 * after {@link #onStop()} and before {@link #onDetach()}. 403 */ 404 public void onDestroy() { 405 mCalled = true; 406 } 407 408 /** 409 * Called when the fragment is no longer attached to its activity. This 410 * is called after {@link #onDestroy()}. 411 */ 412 public void onDetach() { 413 mCalled = true; 414 } 415} 416