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