/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.app; import android.content.Loader; import android.os.Bundle; import java.util.HashMap; /** * A Fragment that has utility methods for managing {@link Loader}s. * * @param The type of data returned by the Loader. If you're using multiple Loaders with * different return types use Object and case the results. * * @deprecated This was an old design, it will be removed before Honeycomb ships. */ @Deprecated public abstract class LoaderManagingFragment extends Fragment implements Loader.OnLoadCompleteListener { private boolean mStarted = false; static final class LoaderInfo { public Bundle args; public Loader loader; } private HashMap> mLoaders; private HashMap> mInactiveLoaders; /** * Registers a loader with this activity, registers the callbacks on it, and starts it loading. * If a loader with the same id has previously been started it will automatically be destroyed * when the new loader completes it's work. The callback will be delivered before the old loader * is destroyed. */ public Loader startLoading(int id, Bundle args) { LoaderInfo info = mLoaders.get(id); if (info != null) { // Keep track of the previous instance of this loader so we can destroy // it when the new one completes. mInactiveLoaders.put(id, info); } info = new LoaderInfo(); info.args = args; mLoaders.put(id, info); Loader loader = onCreateLoader(id, args); info.loader = loader; if (mStarted) { // The activity will start all existing loaders in it's onStart(), so only start them // here if we're past that point of the activitiy's life cycle loader.registerListener(id, this); loader.startLoading(); } return loader; } protected abstract Loader onCreateLoader(int id, Bundle args); protected abstract void onInitializeLoaders(); protected abstract void onLoadFinished(Loader loader, D data); public final void onLoadComplete(Loader loader, D data) { // Notify of the new data so the app can switch out the old data before // we try to destroy it. onLoadFinished(loader, data); // Look for an inactive loader and destroy it if found int id = loader.getId(); LoaderInfo info = mInactiveLoaders.get(id); if (info != null) { Loader oldLoader = info.loader; if (oldLoader != null) { oldLoader.destroy(); } mInactiveLoaders.remove(id); } } @Override public void onCreate(Bundle savedState) { super.onCreate(savedState); if (mLoaders == null) { // Look for a passed along loader and create a new one if it's not there // TODO: uncomment once getLastNonConfigurationInstance method is available // mLoaders = (HashMap) getLastNonConfigurationInstance(); if (mLoaders == null) { mLoaders = new HashMap>(); onInitializeLoaders(); } } if (mInactiveLoaders == null) { mInactiveLoaders = new HashMap>(); } } @Override public void onStart() { super.onStart(); // Call out to sub classes so they can start their loaders // Let the existing loaders know that we want to be notified when a load is complete for (HashMap.Entry> entry : mLoaders.entrySet()) { LoaderInfo info = entry.getValue(); Loader loader = info.loader; int id = entry.getKey(); if (loader == null) { loader = onCreateLoader(id, info.args); info.loader = loader; } loader.registerListener(id, this); loader.startLoading(); } mStarted = true; } @Override public void onStop() { super.onStop(); for (HashMap.Entry> entry : mLoaders.entrySet()) { LoaderInfo info = entry.getValue(); Loader loader = info.loader; if (loader == null) { continue; } // Let the loader know we're done with it loader.unregisterListener(this); // The loader isn't getting passed along to the next instance so ask it to stop loading if (!getActivity().isChangingConfigurations()) { loader.stopLoading(); } } mStarted = false; } /* TO DO: This needs to be turned into a retained fragment. @Override public Object onRetainNonConfigurationInstance() { // Pass the loader along to the next guy Object result = mLoaders; mLoaders = null; return result; } **/ @Override public void onDestroy() { super.onDestroy(); if (mLoaders != null) { for (HashMap.Entry> entry : mLoaders.entrySet()) { LoaderInfo info = entry.getValue(); Loader loader = info.loader; if (loader == null) { continue; } loader.destroy(); } } } /** * Stops and removes the loader with the given ID. */ public void stopLoading(int id) { if (mLoaders != null) { LoaderInfo info = mLoaders.remove(id); if (info != null) { Loader loader = info.loader; if (loader != null) { loader.unregisterListener(this); loader.destroy(); } } } } /** * @return the Loader with the given id or null if no matching Loader * is found. */ public Loader getLoader(int id) { LoaderInfo loaderInfo = mLoaders.get(id); if (loaderInfo != null) { return mLoaders.get(id).loader; } return null; } }