android Loader
一、看看loader包目录结构:
1、LoaderManager
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* * Copyright 2018 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 androidx.loader.app; import android.os.Bundle; import androidx.annotation.MainThread; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.ViewModelStoreOwner; import androidx.loader.content.Loader; import java.io.FileDescriptor; import java.io.PrintWriter; /** * Static library support version of the framework's {@link android.app.LoaderManager}. * Used to write apps that run on platforms prior to Android 3.0. When running * on Android 3.0 or above, this implementation is still used; it does not try * to switch to the framework's implementation. See the framework SDK * documentation for a class overview. * * <p>Your activity must derive from {@link androidx.fragment.app.FragmentActivity} to use this. */ public abstract class LoaderManager { /** * Callback interface for a client to interact with the manager. */ public interface LoaderCallbacks<D> { /** * Instantiate and return a new Loader for the given ID. * * <p>This will always be called from the process's main thread. * * @param id The ID whose loader is to be created. * @param args Any arguments supplied by the caller. * @return Return a new Loader instance that is ready to start loading. */ @MainThread @NonNull Loader<D> onCreateLoader(int id, @Nullable Bundle args); /** * Called when a previously created loader has finished its load. Note * that normally an application is <em>not</em> allowed to commit fragment * transactions while in this call, since it can happen after an * activity's state is saved. See {@link androidx.fragment.app.FragmentManager#beginTransaction() * FragmentManager.openTransaction()} for further discussion on this. * * <p>This function is guaranteed to be called prior to the release of * the last data that was supplied for this Loader. At this point * you should remove all use of the old data (since it will be released * soon), but should not do your own release of the data since its Loader * owns it and will take care of that. The Loader will take care of * management of its data so you don't have to. In particular: * * <ul> * <li> <p>The Loader will monitor for changes to the data, and report * them to you through new calls here. You should not monitor the * data yourself. For example, if the data is a {@link android.database.Cursor} * and you place it in a {@link android.widget.CursorAdapter}, use * the {@link android.widget.CursorAdapter#CursorAdapter(android.content.Context, * android.database.Cursor, int)} constructor <em>without</em> passing * in either {@link android.widget.CursorAdapter#FLAG_AUTO_REQUERY} * or {@link android.widget.CursorAdapter#FLAG_REGISTER_CONTENT_OBSERVER} * (that is, use 0 for the flags argument). This prevents the CursorAdapter * from doing its own observing of the Cursor, which is not needed since * when a change happens you will get a new Cursor throw another call * here. * <li> The Loader will release the data once it knows the application * is no longer using it. For example, if the data is * a {@link android.database.Cursor} from a {@link android.content.CursorLoader}, * you should not call close() on it yourself. If the Cursor is being placed in a * {@link android.widget.CursorAdapter}, you should use the * {@link android.widget.CursorAdapter#swapCursor(android.database.Cursor)} * method so that the old Cursor is not closed. * </ul> * * <p>This will always be called from the process's main thread. * * @param loader The Loader that has finished. * @param data The data generated by the Loader. */ @MainThread void onLoadFinished(@NonNull Loader<D> loader, D data); /** * Called when a previously created loader is being reset, and thus * making its data unavailable. The application should at this point * remove any references it has to the Loader's data. * * <p>This will always be called from the process's main thread. * * @param loader The Loader that is being reset. */ @MainThread void onLoaderReset(@NonNull Loader<D> loader); } /** * Gets a LoaderManager associated with the given owner, such as a {@link androidx.fragment.app.FragmentActivity} or * {@link androidx.fragment.app.Fragment}. * * @param owner The owner that should be used to create the returned LoaderManager * @param <T> A class that maintains its own {@link android.arch.lifecycle.Lifecycle} and * {@link android.arch.lifecycle.ViewModelStore}. For instance, * {@link androidx.fragment.app.FragmentActivity} or {@link androidx.fragment.app.Fragment}. * @return A valid LoaderManager */ @NonNull public static <T extends LifecycleOwner & ViewModelStoreOwner> LoaderManager getInstance( @NonNull T owner) { return new LoaderManagerImpl(owner, owner.getViewModelStore()); } /** * Ensures a loader is initialized and active. If the loader doesn't * already exist, one is created and (if the activity/fragment is currently * started) starts the loader. Otherwise the last created * loader is re-used. * * <p>In either case, the given callback is associated with the loader, and * will be called as the loader state changes. If at the point of call * the caller is in its started state, and the requested loader * already exists and has generated its data, then * callback {@link LoaderCallbacks#onLoadFinished} will * be called immediately (inside of this function), so you must be prepared * for this to happen. * * <p>Must be called from the process's main thread. * * @param id A unique identifier for this loader. Can be whatever you want. * Identifiers are scoped to a particular LoaderManager instance. * @param args Optional arguments to supply to the loader at construction. * If a loader already exists (a new one does not need to be created), this * parameter will be ignored and the last arguments continue to be used. * @param callback Interface the LoaderManager will call to report about * changes in the state of the loader. Required. */ @MainThread @NonNull public abstract <D> Loader<D> initLoader(int id, @Nullable Bundle args, @NonNull LoaderManager.LoaderCallbacks<D> callback); /** * Starts a new or restarts an existing {@link android.content.Loader} in * this manager, registers the callbacks to it, * and (if the activity/fragment is currently started) starts loading it. * If a loader with the same id has previously been * started it will automatically be destroyed when the new loader completes * its work. The callback will be delivered before the old loader * is destroyed. * * <p>Must be called from the process's main thread. * * @param id A unique identifier for this loader. Can be whatever you want. * Identifiers are scoped to a particular LoaderManager instance. * @param args Optional arguments to supply to the loader at construction. * @param callback Interface the LoaderManager will call to report about * changes in the state of the loader. Required. */ @MainThread @NonNull public abstract <D> Loader<D> restartLoader(int id, @Nullable Bundle args, @NonNull LoaderManager.LoaderCallbacks<D> callback); /** * Stops and removes the loader with the given ID. If this loader * had previously reported data to the client through * {@link LoaderCallbacks#onLoadFinished(Loader, Object)}, a call * will be made to {@link LoaderCallbacks#onLoaderReset(Loader)}. * * <p>Must be called from the process's main thread. */ @MainThread public abstract void destroyLoader(int id); /** * Return the Loader with the given id or null if no matching Loader * is found. */ @Nullable public abstract <D> Loader<D> getLoader(int id); /** * Mark all Loaders associated with this LoaderManager for redelivery of their current * data (if any), waiting for the next time the Loader is started if it is currently stopped. * In cases where no data has yet been delivered, this is effectively a no-op. In cases where * data has already been delivered via {@link LoaderCallbacks#onLoadFinished(Loader, Object)}, * this will ensure that {@link LoaderCallbacks#onLoadFinished(Loader, Object)} is called again * with the same data. * <p> * Call this only if you are implementing a {@link LifecycleOwner} where the views/elements that * developers are likely to use in {@link LoaderCallbacks#onLoadFinished(Loader, Object)} can be * created and destroyed multiple times without the {@link LifecycleOwner} itself being * destroyed. Call this when the views/elements are being destroyed to ensure that the data * is redelivered upon recreation. */ public abstract void markForRedelivery(); /** * Print the LoaderManager's state into the given stream. * * @param prefix Text to print at the front of each line. * @param fd The raw file descriptor that the dump is being sent to. * @param writer A PrintWriter to which the dump is to be set. * @param args Additional arguments to the dump request. * @deprecated Use {@link #enableDebugLogging(boolean)} to understand the series of operations * performed by LoaderManager. */ @Deprecated public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args); /** * Control whether the framework's internal loader manager debugging * logs are turned on. If enabled, you will see output in logcat as * the framework performs loader operations. */ public static void enableDebugLogging(boolean enabled) { LoaderManagerImpl.DEBUG = enabled; } /** * Returns true if any loaders managed are currently running and have not * returned data to the application yet. */ public boolean hasRunningLoaders() { return false; } }
LoadManager.LoaderCallbacks
LoadManager.LoaderCallbacks::onCreateLoader
LoadManager.LoaderCallbacks::onLoadFinished
LoadManager.LoaderCallbacks::onLoaderReset
LoaderManager::getInstance
LoaderManager::initLoader
LoaderManager::restartLoader
LoaderManager::destroytLoader
LoaderManager::markForRedelivery
2、LoaderManagerImpl
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 import android.os.Looper; 21 import android.util.Log; 22 23 import androidx.annotation.MainThread; 24 import androidx.annotation.NonNull; 25 import androidx.annotation.Nullable; 26 import androidx.collection.SparseArrayCompat; 27 import androidx.core.util.DebugUtils; 28 import androidx.lifecycle.LifecycleOwner; 29 import androidx.lifecycle.MutableLiveData; 30 import androidx.lifecycle.Observer; 31 import androidx.lifecycle.ViewModel; 32 import androidx.lifecycle.ViewModelProvider; 33 import androidx.lifecycle.ViewModelStore; 34 import androidx.loader.content.Loader; 35 36 import java.io.FileDescriptor; 37 import java.io.PrintWriter; 38 import java.lang.reflect.Modifier; 39 40 class LoaderManagerImpl extends LoaderManager { 41 static final String TAG = "LoaderManager"; 42 static boolean DEBUG = false; 43 44 /** 45 * Class which manages the state of a {@link Loader} and its associated 46 * {@link LoaderCallbacks} 47 * 48 * @param <D> Type of data the Loader handles 49 */ 50 public static class LoaderInfo<D> extends MutableLiveData<D> 51 implements Loader.OnLoadCompleteListener<D> { 52 53 private final int mId; 54 private final @Nullable Bundle mArgs; 55 private final @NonNull Loader<D> mLoader; 56 private LifecycleOwner mLifecycleOwner; 57 private LoaderObserver<D> mObserver; 58 private Loader<D> mPriorLoader; 59 60 LoaderInfo(int id, @Nullable Bundle args, @NonNull Loader<D> loader, 61 @Nullable Loader<D> priorLoader) { 62 mId = id; 63 mArgs = args; 64 mLoader = loader; 65 mPriorLoader = priorLoader; 66 mLoader.registerListener(id, this); 67 } 68 69 @NonNull 70 Loader<D> getLoader() { 71 return mLoader; 72 } 73 74 @Override 75 protected void onActive() { 76 if (DEBUG) Log.v(TAG, " Starting: " + LoaderInfo.this); 77 mLoader.startLoading(); 78 } 79 80 @Override 81 protected void onInactive() { 82 if (DEBUG) Log.v(TAG, " Stopping: " + LoaderInfo.this); 83 mLoader.stopLoading(); 84 } 85 86 /** 87 * Set the {@link LoaderCallbacks} to associate with this {@link Loader}. This 88 * removes any existing {@link LoaderCallbacks}. 89 * 90 * @param owner The lifecycle that should be used to start and stop the {@link Loader} 91 * @param callback The new {@link LoaderCallbacks} to use 92 * @return The {@link Loader} associated with this LoaderInfo 93 */ 94 @MainThread 95 @NonNull 96 Loader<D> setCallback(@NonNull LifecycleOwner owner, 97 @NonNull LoaderCallbacks<D> callback) { 98 LoaderObserver<D> observer = new LoaderObserver<>(mLoader, callback); 99 // Add the new observer 100 observe(owner, observer); 101 // Loaders only support one observer at a time, so remove the current observer, if any 102 if (mObserver != null) { 103 removeObserver(mObserver); 104 } 105 mLifecycleOwner = owner; 106 mObserver = observer; 107 return mLoader; 108 } 109 110 void markForRedelivery() { 111 LifecycleOwner lifecycleOwner = mLifecycleOwner; 112 LoaderObserver<D> observer = mObserver; 113 if (lifecycleOwner != null && observer != null) { 114 // Removing and re-adding the observer ensures that the 115 // observer is called again, even if they had already 116 // received the current data 117 // Use super.removeObserver to avoid nulling out mLifecycleOwner & mObserver 118 super.removeObserver(observer); 119 observe(lifecycleOwner, observer); 120 } 121 } 122 123 boolean isCallbackWaitingForData() { 124 //noinspection SimplifiableIfStatement 125 if (!hasActiveObservers()) { 126 // No active observers means no one is waiting for data 127 return false; 128 } 129 return mObserver != null && !mObserver.hasDeliveredData(); 130 } 131 132 @Override 133 public void removeObserver(@NonNull Observer<? super D> observer) { 134 super.removeObserver(observer); 135 // Clear out our references when the observer is removed to avoid leaking 136 mLifecycleOwner = null; 137 mObserver = null; 138 } 139 140 /** 141 * Destroys this LoaderInfo, its underlying {@link #getLoader() Loader}, and removes any 142 * existing {@link androidx.loader.app.LoaderManager.LoaderCallbacks}. 143 * 144 * @param reset Whether the LoaderCallbacks and Loader should be reset. 145 * @return When reset is false, returns any Loader that still needs to be reset 146 */ 147 @MainThread 148 Loader<D> destroy(boolean reset) { 149 if (DEBUG) Log.v(TAG, " Destroying: " + this); 150 // First tell the Loader that we don't need it anymore 151 mLoader.cancelLoad(); 152 mLoader.abandon(); 153 // Then clean up the LoaderObserver 154 LoaderObserver<D> observer = mObserver; 155 if (observer != null) { 156 removeObserver(observer); 157 if (reset) { 158 observer.reset(); 159 } 160 } 161 // Finally, clean up the Loader 162 mLoader.unregisterListener(this); 163 if ((observer != null && !observer.hasDeliveredData()) || reset) { 164 mLoader.reset(); 165 return mPriorLoader; 166 } 167 return mLoader; 168 } 169 170 @Override 171 public void onLoadComplete(@NonNull Loader<D> loader, @Nullable D data) { 172 if (DEBUG) Log.v(TAG, "onLoadComplete: " + this); 173 if (Looper.myLooper() == Looper.getMainLooper()) { 174 setValue(data); 175 } else { 176 // The Loader#deliverResult method that calls this should 177 // only be called on the main thread, so this should never 178 // happen, but we don't want to lose the data 179 if (DEBUG) { 180 Log.w(TAG, "onLoadComplete was incorrectly called on a " 181 + "background thread"); 182 } 183 postValue(data); 184 } 185 } 186 187 @Override 188 public void setValue(D value) { 189 super.setValue(value); 190 // Now that the new data has arrived, we can reset any prior Loader 191 if (mPriorLoader != null) { 192 mPriorLoader.reset(); 193 mPriorLoader = null; 194 } 195 } 196 197 @Override 198 public String toString() { 199 StringBuilder sb = new StringBuilder(64); 200 sb.append("LoaderInfo{"); 201 sb.append(Integer.toHexString(System.identityHashCode(this))); 202 sb.append(" #"); 203 sb.append(mId); 204 sb.append(" : "); 205 DebugUtils.buildShortClassTag(mLoader, sb); 206 sb.append("}}"); 207 return sb.toString(); 208 } 209 210 @SuppressWarnings("deprecation") 211 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 212 writer.print(prefix); writer.print("mId="); writer.print(mId); 213 writer.print(" mArgs="); writer.println(mArgs); 214 writer.print(prefix); writer.print("mLoader="); writer.println(mLoader); 215 mLoader.dump(prefix + " ", fd, writer, args); 216 if (mObserver != null) { 217 writer.print(prefix); writer.print("mCallbacks="); writer.println(mObserver); 218 mObserver.dump(prefix + " ", writer); 219 } 220 writer.print(prefix); writer.print("mData="); writer.println( 221 getLoader().dataToString(getValue())); 222 writer.print(prefix); writer.print("mStarted="); writer.println( 223 hasActiveObservers()); 224 } 225 } 226 227 /** 228 * Encapsulates the {@link LoaderCallbacks} as a {@link Observer}. 229 * 230 * @param <D> Type of data the LoaderCallbacks handles 231 */ 232 static class LoaderObserver<D> implements Observer<D> { 233 234 private final @NonNull Loader<D> mLoader; 235 private final @NonNull LoaderCallbacks<D> mCallback; 236 237 private boolean mDeliveredData = false; 238 239 LoaderObserver(@NonNull Loader<D> loader, @NonNull LoaderCallbacks<D> callback) { 240 mLoader = loader; 241 mCallback = callback; 242 } 243 244 @Override 245 public void onChanged(@Nullable D data) { 246 if (DEBUG) { 247 Log.v(TAG, " onLoadFinished in " + mLoader + ": " 248 + mLoader.dataToString(data)); 249 } 250 mCallback.onLoadFinished(mLoader, data); 251 mDeliveredData = true; 252 } 253 254 boolean hasDeliveredData() { 255 return mDeliveredData; 256 } 257 258 @MainThread 259 void reset() { 260 if (mDeliveredData) { 261 if (DEBUG) Log.v(TAG, " Resetting: " + mLoader); 262 mCallback.onLoaderReset(mLoader); 263 } 264 } 265 266 @Override 267 public String toString() { 268 return mCallback.toString(); 269 } 270 271 public void dump(String prefix, PrintWriter writer) { 272 writer.print(prefix); writer.print("mDeliveredData="); writer.println( 273 mDeliveredData); 274 } 275 } 276 277 /** 278 * ViewModel responsible for retaining {@link LoaderInfo} instances across configuration changes 279 */ 280 static class LoaderViewModel extends ViewModel { 281 private static final ViewModelProvider.Factory FACTORY = new ViewModelProvider.Factory() { 282 @NonNull 283 @Override 284 @SuppressWarnings("unchecked") 285 public <T extends ViewModel> T create(@NonNull Class<T> modelClass) { 286 return (T) new LoaderViewModel(); 287 } 288 }; 289 290 @NonNull 291 static LoaderViewModel getInstance(ViewModelStore viewModelStore) { 292 return new ViewModelProvider(viewModelStore, FACTORY).get(LoaderViewModel.class); 293 } 294 295 private SparseArrayCompat<LoaderInfo> mLoaders = new SparseArrayCompat<>(); 296 private boolean mCreatingLoader = false; 297 298 void startCreatingLoader() { 299 mCreatingLoader = true; 300 } 301 302 boolean isCreatingLoader() { 303 return mCreatingLoader; 304 } 305 306 void finishCreatingLoader() { 307 mCreatingLoader = false; 308 } 309 310 void putLoader(int id, @NonNull LoaderInfo info) { 311 mLoaders.put(id, info); 312 } 313 314 @SuppressWarnings("unchecked") 315 <D> LoaderInfo<D> getLoader(int id) { 316 return mLoaders.get(id); 317 } 318 319 void removeLoader(int id) { 320 mLoaders.remove(id); 321 } 322 323 boolean hasRunningLoaders() { 324 int size = mLoaders.size(); 325 for (int index = 0; index < size; index++) { 326 LoaderInfo info = mLoaders.valueAt(index); 327 if (info.isCallbackWaitingForData()) { 328 return true; 329 } 330 } 331 return false; 332 } 333 334 void markForRedelivery() { 335 int size = mLoaders.size(); 336 for (int index = 0; index < size; index++) { 337 LoaderInfo info = mLoaders.valueAt(index); 338 info.markForRedelivery(); 339 } 340 } 341 342 @Override 343 protected void onCleared() { 344 super.onCleared(); 345 int size = mLoaders.size(); 346 for (int index = 0; index < size; index++) { 347 LoaderInfo info = mLoaders.valueAt(index); 348 info.destroy(true); 349 } 350 mLoaders.clear(); 351 } 352 353 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 354 if (mLoaders.size() > 0) { 355 writer.print(prefix); writer.println("Loaders:"); 356 String innerPrefix = prefix + " "; 357 for (int i = 0; i < mLoaders.size(); i++) { 358 LoaderInfo info = mLoaders.valueAt(i); 359 writer.print(prefix); writer.print(" #"); writer.print(mLoaders.keyAt(i)); 360 writer.print(": "); writer.println(info.toString()); 361 info.dump(innerPrefix, fd, writer, args); 362 } 363 } 364 } 365 } 366 367 private final @NonNull LifecycleOwner mLifecycleOwner; 368 private final @NonNull LoaderViewModel mLoaderViewModel; 369 370 LoaderManagerImpl(@NonNull LifecycleOwner lifecycleOwner, 371 @NonNull ViewModelStore viewModelStore) { 372 mLifecycleOwner = lifecycleOwner; 373 mLoaderViewModel = LoaderViewModel.getInstance(viewModelStore); 374 } 375 376 @MainThread 377 @NonNull 378 private <D> Loader<D> createAndInstallLoader(int id, @Nullable Bundle args, 379 @NonNull LoaderCallbacks<D> callback, @Nullable Loader<D> priorLoader) { 380 LoaderInfo<D> info; 381 try { 382 mLoaderViewModel.startCreatingLoader(); 383 Loader<D> loader = callback.onCreateLoader(id, args); 384 if (loader == null) { 385 throw new IllegalArgumentException("Object returned from onCreateLoader " 386 + "must not be null"); 387 } 388 if (loader.getClass().isMemberClass() 389 && !Modifier.isStatic(loader.getClass().getModifiers())) { 390 throw new IllegalArgumentException("Object returned from onCreateLoader " 391 + "must not be a non-static inner member class: " 392 + loader); 393 } 394 info = new LoaderInfo<>(id, args, loader, priorLoader); 395 if (DEBUG) Log.v(TAG, " Created new loader " + info); 396 mLoaderViewModel.putLoader(id, info); 397 } finally { 398 mLoaderViewModel.finishCreatingLoader(); 399 } 400 return info.setCallback(mLifecycleOwner, callback); 401 } 402 403 @MainThread 404 @NonNull 405 @Override 406 public <D> Loader<D> initLoader(int id, @Nullable Bundle args, 407 @NonNull LoaderCallbacks<D> callback) { 408 if (mLoaderViewModel.isCreatingLoader()) { 409 throw new IllegalStateException("Called while creating a loader"); 410 } 411 if (Looper.getMainLooper() != Looper.myLooper()) { 412 throw new IllegalStateException("initLoader must be called on the main thread"); 413 } 414 415 LoaderInfo<D> info = mLoaderViewModel.getLoader(id); 416 417 if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args); 418 419 if (info == null) { 420 // Loader doesn't already exist; create. 421 return createAndInstallLoader(id, args, callback, null); 422 } else { 423 if (DEBUG) Log.v(TAG, " Re-using existing loader " + info); 424 return info.setCallback(mLifecycleOwner, callback); 425 } 426 } 427 428 @MainThread 429 @NonNull 430 @Override 431 public <D> Loader<D> restartLoader(int id, @Nullable Bundle args, 432 @NonNull LoaderCallbacks<D> callback) { 433 if (mLoaderViewModel.isCreatingLoader()) { 434 throw new IllegalStateException("Called while creating a loader"); 435 } 436 if (Looper.getMainLooper() != Looper.myLooper()) { 437 throw new IllegalStateException("restartLoader must be called on the main thread"); 438 } 439 440 if (DEBUG) Log.v(TAG, "restartLoader in " + this + ": args=" + args); 441 LoaderInfo<D> info = mLoaderViewModel.getLoader(id); 442 Loader<D> priorLoader = null; 443 if (info != null) { 444 priorLoader = info.destroy(false); 445 } 446 // And create a new Loader 447 return createAndInstallLoader(id, args, callback, priorLoader); 448 } 449 450 @MainThread 451 @Override 452 public void destroyLoader(int id) { 453 if (mLoaderViewModel.isCreatingLoader()) { 454 throw new IllegalStateException("Called while creating a loader"); 455 } 456 if (Looper.getMainLooper() != Looper.myLooper()) { 457 throw new IllegalStateException("destroyLoader must be called on the main thread"); 458 } 459 460 if (DEBUG) Log.v(TAG, "destroyLoader in " + this + " of " + id); 461 LoaderInfo info = mLoaderViewModel.getLoader(id); 462 if (info != null) { 463 info.destroy(true); 464 mLoaderViewModel.removeLoader(id); 465 } 466 } 467 468 @Nullable 469 @Override 470 public <D> Loader<D> getLoader(int id) { 471 if (mLoaderViewModel.isCreatingLoader()) { 472 throw new IllegalStateException("Called while creating a loader"); 473 } 474 475 LoaderInfo<D> info = mLoaderViewModel.getLoader(id); 476 return info != null ? info.getLoader() : null; 477 } 478 479 @Override 480 public void markForRedelivery() { 481 mLoaderViewModel.markForRedelivery(); 482 } 483 484 @Override 485 public String toString() { 486 StringBuilder sb = new StringBuilder(128); 487 sb.append("LoaderManager{"); 488 sb.append(Integer.toHexString(System.identityHashCode(this))); 489 sb.append(" in "); 490 DebugUtils.buildShortClassTag(mLifecycleOwner, sb); 491 sb.append("}}"); 492 return sb.toString(); 493 } 494 495 @Deprecated 496 @Override 497 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 498 mLoaderViewModel.dump(prefix, fd, writer, args); 499 } 500 501 @Override 502 public boolean hasRunningLoaders() { 503 return mLoaderViewModel.hasRunningLoaders(); 504 } 505 }
LoadInfo就是LiveData
LoaderViewModel就是ViewModel
LoaderObserver就是Observer