FragmentStatePagerAdapter.java revision 7a01f352fa0fe92cfd786ced85129dcc5531c087
1/*
2 * Copyright (C) 2011 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 java.util.ArrayList;
20
21import android.os.Bundle;
22import android.os.Parcelable;
23import android.support.v4.view.PagerAdapter;
24import android.util.Log;
25import android.view.View;
26import android.view.ViewGroup;
27
28/**
29 * Implementation of {@link android.support.v4.view.PagerAdapter} that
30 * uses a {@link Fragment} to manage each page. This class also handles
31 * saving and restoring of fragment's state.
32 */
33public abstract class FragmentStatePagerAdapter extends PagerAdapter {
34    private static final String TAG = "FragmentStatePagerAdapter";
35    private static final boolean DEBUG = false;
36
37    private final FragmentManager mFragmentManager;
38    private FragmentTransaction mCurTransaction = null;
39
40    private ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();
41    private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
42    private Fragment mCurrentPrimaryItem = null;
43
44    public FragmentStatePagerAdapter(FragmentManager fm) {
45        mFragmentManager = fm;
46    }
47
48    /**
49     * Return the Fragment associated with a specified position.
50     */
51    public abstract Fragment getItem(int position);
52
53    @Override
54    public void startUpdate(ViewGroup container) {
55    }
56
57    @Override
58    public Object instantiateItem(ViewGroup container, int position) {
59        // If we already have this item instantiated, there is nothing
60        // to do.  This can happen when we are restoring the entire pager
61        // from its saved state, where the fragment manager has already
62        // taken care of restoring the fragments we previously had instantiated.
63        if (mFragments.size() > position) {
64            Fragment f = mFragments.get(position);
65            if (f != null) {
66                return f;
67            }
68        }
69
70        if (mCurTransaction == null) {
71            mCurTransaction = mFragmentManager.beginTransaction();
72        }
73
74        Fragment fragment = getItem(position);
75        if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
76        if (mSavedState.size() > position) {
77            Fragment.SavedState fss = mSavedState.get(position);
78            if (fss != null) {
79                fragment.setInitialSavedState(fss);
80            }
81        }
82        while (mFragments.size() <= position) {
83            mFragments.add(null);
84        }
85        fragment.setMenuVisibility(false);
86        mFragments.set(position, fragment);
87        mCurTransaction.add(container.getId(), fragment);
88
89        return fragment;
90    }
91
92    @Override
93    public void destroyItem(ViewGroup container, int position, Object object) {
94        Fragment fragment = (Fragment)object;
95
96        if (mCurTransaction == null) {
97            mCurTransaction = mFragmentManager.beginTransaction();
98        }
99        if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object
100                + " v=" + ((Fragment)object).getView());
101        while (mSavedState.size() <= position) {
102            mSavedState.add(null);
103        }
104        mSavedState.set(position, mFragmentManager.saveFragmentInstanceState(fragment));
105        mFragments.set(position, null);
106
107        mCurTransaction.remove(fragment);
108    }
109
110    @Override
111    public void setPrimaryItem(ViewGroup container, int position, Object object) {
112        Fragment fragment = (Fragment)object;
113        if (fragment != mCurrentPrimaryItem) {
114            if (mCurrentPrimaryItem != null) {
115                mCurrentPrimaryItem.setMenuVisibility(false);
116            }
117            if (fragment != null) {
118                fragment.setMenuVisibility(true);
119            }
120            mCurrentPrimaryItem = fragment;
121        }
122    }
123
124    @Override
125    public void finishUpdate(ViewGroup container) {
126        if (mCurTransaction != null) {
127            mCurTransaction.commitAllowingStateLoss();
128            mCurTransaction = null;
129            mFragmentManager.executePendingTransactions();
130        }
131    }
132
133    @Override
134    public boolean isViewFromObject(View view, Object object) {
135        return ((Fragment)object).getView() == view;
136    }
137
138    @Override
139    public Parcelable saveState() {
140        Bundle state = null;
141        if (mSavedState.size() > 0) {
142            state = new Bundle();
143            Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
144            mSavedState.toArray(fss);
145            state.putParcelableArray("states", fss);
146        }
147        for (int i=0; i<mFragments.size(); i++) {
148            Fragment f = mFragments.get(i);
149            if (f != null) {
150                if (state == null) {
151                    state = new Bundle();
152                }
153                String key = "f" + i;
154                mFragmentManager.putFragment(state, key, f);
155            }
156        }
157        return state;
158    }
159
160    @Override
161    public void restoreState(Parcelable state, ClassLoader loader) {
162        if (state != null) {
163            Bundle bundle = (Bundle)state;
164            bundle.setClassLoader(loader);
165            Parcelable[] fss = bundle.getParcelableArray("states");
166            mSavedState.clear();
167            mFragments.clear();
168            if (fss != null) {
169                for (int i=0; i<fss.length; i++) {
170                    mSavedState.add((Fragment.SavedState)fss[i]);
171                }
172            }
173            Iterable<String> keys = bundle.keySet();
174            for (String key: keys) {
175                if (key.startsWith("f")) {
176                    int index = Integer.parseInt(key.substring(1));
177                    Fragment f = mFragmentManager.getFragment(bundle, key);
178                    if (f != null) {
179                        while (mFragments.size() <= index) {
180                            mFragments.add(null);
181                        }
182                        f.setMenuVisibility(false);
183                        mFragments.set(index, f);
184                    } else {
185                        Log.w(TAG, "Bad fragment at key " + key);
186                    }
187                }
188            }
189        }
190    }
191}
192