1 /* 2 * Copyright 2018 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 17 package androidx.loader.app; 18 19 import android.os.Bundle; 20 21 import androidx.annotation.MainThread; 22 import androidx.annotation.NonNull; 23 import androidx.annotation.Nullable; 24 import androidx.lifecycle.LifecycleOwner; 25 import androidx.lifecycle.ViewModelStoreOwner; 26 import androidx.loader.content.Loader; 27 28 import java.io.FileDescriptor; 29 import java.io.PrintWriter; 30 31 /** 32 * Static library support version of the framework's {@link android.app.LoaderManager}. 33 * Used to write apps that run on platforms prior to Android 3.0. When running 34 * on Android 3.0 or above, this implementation is still used; it does not try 35 * to switch to the framework's implementation. See the framework SDK 36 * documentation for a class overview. 37 * 38 * <p>Your activity must derive from {@link androidx.fragment.app.FragmentActivity} to use this. 39 */ 40 public abstract class LoaderManager { 41 /** 42 * Callback interface for a client to interact with the manager. 43 */ 44 public interface LoaderCallbacks<D> { 45 /** 46 * Instantiate and return a new Loader for the given ID. 47 * 48 * <p>This will always be called from the process's main thread. 49 * 50 * @param id The ID whose loader is to be created. 51 * @param args Any arguments supplied by the caller. 52 * @return Return a new Loader instance that is ready to start loading. 53 */ 54 @MainThread 55 @NonNull onCreateLoader(int id, @Nullable Bundle args)56 Loader<D> onCreateLoader(int id, @Nullable Bundle args); 57 58 /** 59 * Called when a previously created loader has finished its load. Note 60 * that normally an application is <em>not</em> allowed to commit fragment 61 * transactions while in this call, since it can happen after an 62 * activity's state is saved. See {@link androidx.fragment.app.FragmentManager#beginTransaction() 63 * FragmentManager.openTransaction()} for further discussion on this. 64 * 65 * <p>This function is guaranteed to be called prior to the release of 66 * the last data that was supplied for this Loader. At this point 67 * you should remove all use of the old data (since it will be released 68 * soon), but should not do your own release of the data since its Loader 69 * owns it and will take care of that. The Loader will take care of 70 * management of its data so you don't have to. In particular: 71 * 72 * <ul> 73 * <li> <p>The Loader will monitor for changes to the data, and report 74 * them to you through new calls here. You should not monitor the 75 * data yourself. For example, if the data is a {@link android.database.Cursor} 76 * and you place it in a {@link android.widget.CursorAdapter}, use 77 * the {@link android.widget.CursorAdapter#CursorAdapter(android.content.Context, 78 * android.database.Cursor, int)} constructor <em>without</em> passing 79 * in either {@link android.widget.CursorAdapter#FLAG_AUTO_REQUERY} 80 * or {@link android.widget.CursorAdapter#FLAG_REGISTER_CONTENT_OBSERVER} 81 * (that is, use 0 for the flags argument). This prevents the CursorAdapter 82 * from doing its own observing of the Cursor, which is not needed since 83 * when a change happens you will get a new Cursor throw another call 84 * here. 85 * <li> The Loader will release the data once it knows the application 86 * is no longer using it. For example, if the data is 87 * a {@link android.database.Cursor} from a {@link android.content.CursorLoader}, 88 * you should not call close() on it yourself. If the Cursor is being placed in a 89 * {@link android.widget.CursorAdapter}, you should use the 90 * {@link android.widget.CursorAdapter#swapCursor(android.database.Cursor)} 91 * method so that the old Cursor is not closed. 92 * </ul> 93 * 94 * <p>This will always be called from the process's main thread. 95 * 96 * @param loader The Loader that has finished. 97 * @param data The data generated by the Loader. 98 */ 99 @MainThread onLoadFinished(@onNull Loader<D> loader, D data)100 void onLoadFinished(@NonNull Loader<D> loader, D data); 101 102 /** 103 * Called when a previously created loader is being reset, and thus 104 * making its data unavailable. The application should at this point 105 * remove any references it has to the Loader's data. 106 * 107 * <p>This will always be called from the process's main thread. 108 * 109 * @param loader The Loader that is being reset. 110 */ 111 @MainThread onLoaderReset(@onNull Loader<D> loader)112 void onLoaderReset(@NonNull Loader<D> loader); 113 } 114 115 /** 116 * Gets a LoaderManager associated with the given owner, such as a {@link androidx.fragment.app.FragmentActivity} or 117 * {@link androidx.fragment.app.Fragment}. 118 * 119 * @param owner The owner that should be used to create the returned LoaderManager 120 * @param <T> A class that maintains its own {@link android.arch.lifecycle.Lifecycle} and 121 * {@link android.arch.lifecycle.ViewModelStore}. For instance, 122 * {@link androidx.fragment.app.FragmentActivity} or {@link androidx.fragment.app.Fragment}. 123 * @return A valid LoaderManager 124 */ 125 @NonNull getInstance( @onNull T owner)126 public static <T extends LifecycleOwner & ViewModelStoreOwner> LoaderManager getInstance( 127 @NonNull T owner) { 128 return new LoaderManagerImpl(owner, owner.getViewModelStore()); 129 } 130 131 /** 132 * Ensures a loader is initialized and active. If the loader doesn't 133 * already exist, one is created and (if the activity/fragment is currently 134 * started) starts the loader. Otherwise the last created 135 * loader is re-used. 136 * 137 * <p>In either case, the given callback is associated with the loader, and 138 * will be called as the loader state changes. If at the point of call 139 * the caller is in its started state, and the requested loader 140 * already exists and has generated its data, then 141 * callback {@link LoaderCallbacks#onLoadFinished} will 142 * be called immediately (inside of this function), so you must be prepared 143 * for this to happen. 144 * 145 * <p>Must be called from the process's main thread. 146 * 147 * @param id A unique identifier for this loader. Can be whatever you want. 148 * Identifiers are scoped to a particular LoaderManager instance. 149 * @param args Optional arguments to supply to the loader at construction. 150 * If a loader already exists (a new one does not need to be created), this 151 * parameter will be ignored and the last arguments continue to be used. 152 * @param callback Interface the LoaderManager will call to report about 153 * changes in the state of the loader. Required. 154 */ 155 @MainThread 156 @NonNull initLoader(int id, @Nullable Bundle args, @NonNull LoaderManager.LoaderCallbacks<D> callback)157 public abstract <D> Loader<D> initLoader(int id, @Nullable Bundle args, 158 @NonNull LoaderManager.LoaderCallbacks<D> callback); 159 160 /** 161 * Starts a new or restarts an existing {@link android.content.Loader} in 162 * this manager, registers the callbacks to it, 163 * and (if the activity/fragment is currently started) starts loading it. 164 * If a loader with the same id has previously been 165 * started it will automatically be destroyed when the new loader completes 166 * its work. The callback will be delivered before the old loader 167 * is destroyed. 168 * 169 * <p>Must be called from the process's main thread. 170 * 171 * @param id A unique identifier for this loader. Can be whatever you want. 172 * Identifiers are scoped to a particular LoaderManager instance. 173 * @param args Optional arguments to supply to the loader at construction. 174 * @param callback Interface the LoaderManager will call to report about 175 * changes in the state of the loader. Required. 176 */ 177 @MainThread 178 @NonNull restartLoader(int id, @Nullable Bundle args, @NonNull LoaderManager.LoaderCallbacks<D> callback)179 public abstract <D> Loader<D> restartLoader(int id, @Nullable Bundle args, 180 @NonNull LoaderManager.LoaderCallbacks<D> callback); 181 182 /** 183 * Stops and removes the loader with the given ID. If this loader 184 * had previously reported data to the client through 185 * {@link LoaderCallbacks#onLoadFinished(Loader, Object)}, a call 186 * will be made to {@link LoaderCallbacks#onLoaderReset(Loader)}. 187 * 188 * <p>Must be called from the process's main thread. 189 */ 190 @MainThread destroyLoader(int id)191 public abstract void destroyLoader(int id); 192 193 /** 194 * Return the Loader with the given id or null if no matching Loader 195 * is found. 196 */ 197 @Nullable getLoader(int id)198 public abstract <D> Loader<D> getLoader(int id); 199 200 /** 201 * Mark all Loaders associated with this LoaderManager for redelivery of their current 202 * data (if any), waiting for the next time the Loader is started if it is currently stopped. 203 * In cases where no data has yet been delivered, this is effectively a no-op. In cases where 204 * data has already been delivered via {@link LoaderCallbacks#onLoadFinished(Loader, Object)}, 205 * this will ensure that {@link LoaderCallbacks#onLoadFinished(Loader, Object)} is called again 206 * with the same data. 207 * <p> 208 * Call this only if you are implementing a {@link LifecycleOwner} where the views/elements that 209 * developers are likely to use in {@link LoaderCallbacks#onLoadFinished(Loader, Object)} can be 210 * created and destroyed multiple times without the {@link LifecycleOwner} itself being 211 * destroyed. Call this when the views/elements are being destroyed to ensure that the data 212 * is redelivered upon recreation. 213 */ markForRedelivery()214 public abstract void markForRedelivery(); 215 216 /** 217 * Print the LoaderManager's state into the given stream. 218 * 219 * @param prefix Text to print at the front of each line. 220 * @param fd The raw file descriptor that the dump is being sent to. 221 * @param writer A PrintWriter to which the dump is to be set. 222 * @param args Additional arguments to the dump request. 223 * @deprecated Use {@link #enableDebugLogging(boolean)} to understand the series of operations 224 * performed by LoaderManager. 225 */ 226 @Deprecated dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args)227 public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args); 228 229 /** 230 * Control whether the framework's internal loader manager debugging 231 * logs are turned on. If enabled, you will see output in logcat as 232 * the framework performs loader operations. 233 */ enableDebugLogging(boolean enabled)234 public static void enableDebugLogging(boolean enabled) { 235 LoaderManagerImpl.DEBUG = enabled; 236 } 237 238 /** 239 * Returns true if any loaders managed are currently running and have not 240 * returned data to the application yet. 241 */ hasRunningLoaders()242 public boolean hasRunningLoaders() { return false; } 243 } 244