blob: 32e3bf309ec62fd288ee4c28ca7ce995eceaca25 [file] [log] [blame]
Dmitri Plotnikov86053952010-04-29 10:22:01 -07001/*
2 * Copyright (C) 2010 Google Inc.
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.patterns;
18
19import android.app.Fragment;
20import android.os.Bundle;
21
22import java.util.HashMap;
23
24public abstract class LoaderManagingFragment<D> extends Fragment
25 implements Loader.OnLoadCompleteListener<D> {
26 private boolean mStarted = false;
27
28 static final class LoaderInfo<D> {
29 public Bundle args;
30 public Loader<D> loader;
31 }
32 private HashMap<Integer, LoaderInfo<D>> mLoaders;
33 private HashMap<Integer, LoaderInfo<D>> mInactiveLoaders;
34
35 /**
36 * Registers a loader with this activity, registers the callbacks on it, and starts it loading.
37 * If a loader with the same id has previously been started it will automatically be destroyed
38 * when the new loader completes it's work. The callback will be delivered before the old loader
39 * is destroyed.
40 */
41 protected void startLoading(int id, Bundle args) {
42 LoaderInfo<D> info = mLoaders.get(id);
43 if (info != null) {
44 // Keep track of the previous instance of this loader so we can destroy
45 // it when the new one completes.
46 mInactiveLoaders.put(id, info);
47 }
48 info = new LoaderInfo<D>();
49 info.args = args;
50 mLoaders.put(id, info);
51 Loader<D> loader = onCreateLoader(id, args);
52 info.loader = loader;
53 if (mStarted) {
54 // The activity will start all existing loaders in it's onStart(), so only start them
55 // here if we're past that point of the activitiy's life cycle
56 loader.registerListener(id, this);
57 loader.startLoading();
58 }
59 }
60
61 protected abstract Loader<D> onCreateLoader(int id, Bundle args);
62 protected abstract void onInitializeLoaders();
63 protected abstract void onLoadFinished(Loader<D> loader, D data);
64
65 public final void onLoadComplete(Loader<D> loader, D data) {
66 // Notify of the new data so the app can switch out the old data before
67 // we try to destroy it.
68 onLoadFinished(loader, data);
69
70 // Look for an inactive loader and destroy it if found
71 int id = loader.getId();
72 LoaderInfo<D> info = mInactiveLoaders.get(id);
73 if (info != null) {
74 Loader<D> oldLoader = info.loader;
75 if (oldLoader != null) {
76 oldLoader.destroy();
77 }
78 mInactiveLoaders.remove(id);
79 }
80 }
81
82 @Override
83 public void onCreate(Bundle savedState) {
84 super.onCreate(savedState);
85
86 if (mLoaders == null) {
87 // Look for a passed along loader and create a new one if it's not there
88// TODO: uncomment once getLastNonConfigurationInstance method is available
89// mLoaders = (HashMap<Integer, LoaderInfo>) getLastNonConfigurationInstance();
90 if (mLoaders == null) {
91 mLoaders = new HashMap<Integer, LoaderInfo<D>>();
92 onInitializeLoaders();
93 }
94 }
95 if (mInactiveLoaders == null) {
96 mInactiveLoaders = new HashMap<Integer, LoaderInfo<D>>();
97 }
98 }
99
100 @Override
101 public void onStart() {
102 super.onStart();
103
104 // Call out to sub classes so they can start their loaders
105 // Let the existing loaders know that we want to be notified when a load is complete
106 for (HashMap.Entry<Integer, LoaderInfo<D>> entry : mLoaders.entrySet()) {
107 LoaderInfo<D> info = entry.getValue();
108 Loader<D> loader = info.loader;
109 int id = entry.getKey();
110 if (loader == null) {
111 loader = onCreateLoader(id, info.args);
112 info.loader = loader;
113 }
114 loader.registerListener(id, this);
115 loader.startLoading();
116 }
117
118 mStarted = true;
119 }
120
121 @Override
122 public void onStop() {
123 super.onStop();
124
125 for (HashMap.Entry<Integer, LoaderInfo<D>> entry : mLoaders.entrySet()) {
126 LoaderInfo<D> info = entry.getValue();
127 Loader<D> loader = info.loader;
128 if (loader == null) {
129 continue;
130 }
131
132 // Let the loader know we're done with it
133 loader.unregisterListener(this);
134
135 // The loader isn't getting passed along to the next instance so ask it to stop loading
136// TODO: uncomment once isChangingConfig method is available
137// if (!getActivity().isChangingConfigurations()) {
138// loader.stopLoading();
139// }
140 }
141
142 mStarted = false;
143 }
144
145 @Override
146 public Object onRetainNonConfigurationInstance() {
147 // Pass the loader along to the next guy
148 Object result = mLoaders;
149 mLoaders = null;
150 return result;
151 }
152
153 @Override
154 public void onDestroy() {
155 super.onDestroy();
156
157 if (mLoaders != null) {
158 for (HashMap.Entry<Integer, LoaderInfo<D>> entry : mLoaders.entrySet()) {
159 LoaderInfo<D> info = entry.getValue();
160 Loader<D> loader = info.loader;
161 if (loader == null) {
162 continue;
163 }
164 loader.destroy();
165 }
166 }
167 }
168}