138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake/*
238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake * Copyright 2018 The Android Open Source Project
338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake *
438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake * Licensed under the Apache License, Version 2.0 (the "License");
538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake * you may not use this file except in compliance with the License.
638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake * You may obtain a copy of the License at
738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake *
838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake *      http://www.apache.org/licenses/LICENSE-2.0
938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake *
1038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake * Unless required by applicable law or agreed to in writing, software
1138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake * distributed under the License is distributed on an "AS IS" BASIS,
1238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake * See the License for the specific language governing permissions and
1438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake * limitations under the License.
1538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake */
1638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.loader.app;
1838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
1938f4f4174d9cd53c553f14c19746500cb861b089Ian Lakeimport android.os.Bundle;
2038f4f4174d9cd53c553f14c19746500cb861b089Ian Lakeimport android.os.Looper;
2138f4f4174d9cd53c553f14c19746500cb861b089Ian Lakeimport android.util.Log;
2238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
2301b544c7352c805d3c18f023b2eaeecb924ee1b3Ian Lakeimport androidx.annotation.MainThread;
2401b544c7352c805d3c18f023b2eaeecb924ee1b3Ian Lakeimport androidx.annotation.NonNull;
2501b544c7352c805d3c18f023b2eaeecb924ee1b3Ian Lakeimport androidx.annotation.Nullable;
2601b544c7352c805d3c18f023b2eaeecb924ee1b3Ian Lakeimport androidx.collection.SparseArrayCompat;
2701b544c7352c805d3c18f023b2eaeecb924ee1b3Ian Lakeimport androidx.core.util.DebugUtils;
28ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.lifecycle.LifecycleOwner;
29ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.lifecycle.MutableLiveData;
30ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.lifecycle.Observer;
31ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.lifecycle.ViewModel;
32ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.lifecycle.ViewModelProvider;
33ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.lifecycle.ViewModelStore;
3401b544c7352c805d3c18f023b2eaeecb924ee1b3Ian Lakeimport androidx.loader.content.Loader;
3501b544c7352c805d3c18f023b2eaeecb924ee1b3Ian Lake
366160d5a551afe96c4180acf0454b5b4dbae89b9eAurimas Liutikasimport java.io.FileDescriptor;
376160d5a551afe96c4180acf0454b5b4dbae89b9eAurimas Liutikasimport java.io.PrintWriter;
386160d5a551afe96c4180acf0454b5b4dbae89b9eAurimas Liutikasimport java.lang.reflect.Modifier;
396160d5a551afe96c4180acf0454b5b4dbae89b9eAurimas Liutikas
4038f4f4174d9cd53c553f14c19746500cb861b089Ian Lakeclass LoaderManagerImpl extends LoaderManager {
4138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    static final String TAG = "LoaderManager";
4238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    static boolean DEBUG = false;
4338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
4438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    /**
4538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake     * Class which manages the state of a {@link Loader} and its associated
4638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake     * {@link LoaderCallbacks}
4738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake     *
4838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake     * @param <D> Type of data the Loader handles
4938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake     */
5038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    public static class LoaderInfo<D> extends MutableLiveData<D>
5138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            implements Loader.OnLoadCompleteListener<D> {
5238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
5338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        private final int mId;
5438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        private final @Nullable Bundle mArgs;
5538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        private final @NonNull Loader<D> mLoader;
5638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        private LifecycleOwner mLifecycleOwner;
5738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        private LoaderObserver<D> mObserver;
585404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake        private Loader<D> mPriorLoader;
5938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
605404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake        LoaderInfo(int id, @Nullable Bundle args, @NonNull Loader<D> loader,
615404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake                @Nullable Loader<D> priorLoader) {
6238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mId = id;
6338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mArgs = args;
6438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mLoader = loader;
655404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake            mPriorLoader = priorLoader;
6638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mLoader.registerListener(id, this);
6738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
6838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
6938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        @NonNull
7038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        Loader<D> getLoader() {
7138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            return mLoader;
7238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
7338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
7438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        @Override
7538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        protected void onActive() {
7638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            if (DEBUG) Log.v(TAG, "  Starting: " + LoaderInfo.this);
7738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mLoader.startLoading();
7838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
7938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
8038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        @Override
8138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        protected void onInactive() {
8238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            if (DEBUG) Log.v(TAG, "  Stopping: " + LoaderInfo.this);
8338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mLoader.stopLoading();
8438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
8538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
8638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        /**
8738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake         * Set the {@link LoaderCallbacks} to associate with this {@link Loader}. This
8838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake         * removes any existing {@link LoaderCallbacks}.
8938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake         *
9038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake         * @param owner The lifecycle that should be used to start and stop the {@link Loader}
9138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake         * @param callback The new {@link LoaderCallbacks} to use
9238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake         * @return The {@link Loader} associated with this LoaderInfo
9338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake         */
9438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        @MainThread
9538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        @NonNull
9638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        Loader<D> setCallback(@NonNull LifecycleOwner owner,
9738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                @NonNull LoaderCallbacks<D> callback) {
9838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            LoaderObserver<D> observer = new LoaderObserver<>(mLoader, callback);
9938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            // Add the new observer
10038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            observe(owner, observer);
10138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            // Loaders only support one observer at a time, so remove the current observer, if any
10238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            if (mObserver != null) {
10338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                removeObserver(mObserver);
10438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            }
10538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mLifecycleOwner = owner;
10638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mObserver = observer;
10738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            return mLoader;
10838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
10938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
11038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        void markForRedelivery() {
11138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            LifecycleOwner lifecycleOwner = mLifecycleOwner;
11238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            LoaderObserver<D> observer = mObserver;
11338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            if (lifecycleOwner != null && observer != null) {
11438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                // Removing and re-adding the observer ensures that the
11538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                // observer is called again, even if they had already
11638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                // received the current data
11750575bfebd6938a9914afc8cf05e2a5f9b1f57edIan Lake                // Use super.removeObserver to avoid nulling out mLifecycleOwner & mObserver
11850575bfebd6938a9914afc8cf05e2a5f9b1f57edIan Lake                super.removeObserver(observer);
11938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                observe(lifecycleOwner, observer);
12038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            }
12138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
12238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
12338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        boolean isCallbackWaitingForData() {
12438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            //noinspection SimplifiableIfStatement
12538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            if (!hasActiveObservers()) {
12638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                // No active observers means no one is waiting for data
12738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                return false;
12838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            }
12938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            return mObserver != null && !mObserver.hasDeliveredData();
13038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
13138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
13238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        @Override
133ba069d50913c3fb250bb60ec310439db36895337Alan Viverette        public void removeObserver(@NonNull Observer<? super D> observer) {
13438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            super.removeObserver(observer);
13538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            // Clear out our references when the observer is removed to avoid leaking
13638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mLifecycleOwner = null;
13738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mObserver = null;
13838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
13938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
1405404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake        /**
1415404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake         * Destroys this LoaderInfo, its underlying {@link #getLoader() Loader}, and removes any
14201b544c7352c805d3c18f023b2eaeecb924ee1b3Ian Lake         * existing {@link androidx.loader.app.LoaderManager.LoaderCallbacks}.
1435404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake         *
1445404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake         * @param reset Whether the LoaderCallbacks and Loader should be reset.
1455404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake         * @return When reset is false, returns any Loader that still needs to be reset
1465404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake         */
14738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        @MainThread
1485404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake        Loader<D> destroy(boolean reset) {
14938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            if (DEBUG) Log.v(TAG, "  Destroying: " + this);
15038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            // First tell the Loader that we don't need it anymore
15138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mLoader.cancelLoad();
15238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mLoader.abandon();
15338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            // Then clean up the LoaderObserver
15438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            LoaderObserver<D> observer = mObserver;
15538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            if (observer != null) {
15638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                removeObserver(observer);
1575404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake                if (reset) {
1585404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake                    observer.reset();
1595404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake                }
16038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            }
1615404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake            // Finally, clean up the Loader
16238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mLoader.unregisterListener(this);
1635404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake            if ((observer != null && !observer.hasDeliveredData()) || reset) {
1645404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake                mLoader.reset();
1655404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake                return mPriorLoader;
1665404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake            }
1675404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake            return mLoader;
16838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
16938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
17038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        @Override
17138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        public void onLoadComplete(@NonNull Loader<D> loader, @Nullable D data) {
17238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);
17302b80098dcec67b9f0b92b1c87ec127b4a4844f1Ian Lake            if (Looper.myLooper() == Looper.getMainLooper()) {
17402b80098dcec67b9f0b92b1c87ec127b4a4844f1Ian Lake                setValue(data);
17502b80098dcec67b9f0b92b1c87ec127b4a4844f1Ian Lake            } else {
17602b80098dcec67b9f0b92b1c87ec127b4a4844f1Ian Lake                // The Loader#deliverResult method that calls this should
17702b80098dcec67b9f0b92b1c87ec127b4a4844f1Ian Lake                // only be called on the main thread, so this should never
17802b80098dcec67b9f0b92b1c87ec127b4a4844f1Ian Lake                // happen, but we don't want to lose the data
17902b80098dcec67b9f0b92b1c87ec127b4a4844f1Ian Lake                if (DEBUG) {
18002b80098dcec67b9f0b92b1c87ec127b4a4844f1Ian Lake                    Log.w(TAG, "onLoadComplete was incorrectly called on a "
18102b80098dcec67b9f0b92b1c87ec127b4a4844f1Ian Lake                            + "background thread");
18202b80098dcec67b9f0b92b1c87ec127b4a4844f1Ian Lake                }
18302b80098dcec67b9f0b92b1c87ec127b4a4844f1Ian Lake                postValue(data);
18402b80098dcec67b9f0b92b1c87ec127b4a4844f1Ian Lake            }
18538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
18638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
18738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        @Override
1885404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake        public void setValue(D value) {
1895404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake            super.setValue(value);
1905404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake            // Now that the new data has arrived, we can reset any prior Loader
1915404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake            if (mPriorLoader != null) {
1925404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake                mPriorLoader.reset();
1935404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake                mPriorLoader = null;
1945404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake            }
1955404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake        }
1965404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake
1975404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake        @Override
19838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        public String toString() {
19938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            StringBuilder sb = new StringBuilder(64);
20038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            sb.append("LoaderInfo{");
20138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            sb.append(Integer.toHexString(System.identityHashCode(this)));
20238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            sb.append(" #");
20338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            sb.append(mId);
20438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            sb.append(" : ");
20538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            DebugUtils.buildShortClassTag(mLoader, sb);
20638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            sb.append("}}");
20738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            return sb.toString();
20838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
20938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
210946ba810ddc84c105a657c671b2630bed6d15942Ian Lake        @SuppressWarnings("deprecation")
21138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
21238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            writer.print(prefix); writer.print("mId="); writer.print(mId);
21338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            writer.print(" mArgs="); writer.println(mArgs);
21438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            writer.print(prefix); writer.print("mLoader="); writer.println(mLoader);
21538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mLoader.dump(prefix + "  ", fd, writer, args);
21638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            if (mObserver != null) {
21738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                writer.print(prefix); writer.print("mCallbacks="); writer.println(mObserver);
21838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                mObserver.dump(prefix + "  ", writer);
21938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            }
22038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            writer.print(prefix); writer.print("mData="); writer.println(
22138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                    getLoader().dataToString(getValue()));
22238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            writer.print(prefix); writer.print("mStarted="); writer.println(
22338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                    hasActiveObservers());
22438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
22538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    }
22638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
22738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    /**
22838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake     * Encapsulates the {@link LoaderCallbacks} as a {@link Observer}.
22938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake     *
23038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake     * @param <D> Type of data the LoaderCallbacks handles
23138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake     */
23238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    static class LoaderObserver<D> implements Observer<D> {
23338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
23438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        private final @NonNull Loader<D> mLoader;
23538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        private final @NonNull LoaderCallbacks<D> mCallback;
23638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
23738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        private boolean mDeliveredData = false;
23838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
23938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        LoaderObserver(@NonNull Loader<D> loader, @NonNull LoaderCallbacks<D> callback) {
24038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mLoader = loader;
24138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mCallback = callback;
24238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
24338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
24438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        @Override
24538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        public void onChanged(@Nullable D data) {
24638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            if (DEBUG) {
24738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                Log.v(TAG, "  onLoadFinished in " + mLoader + ": "
24838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                        + mLoader.dataToString(data));
24938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            }
25038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mCallback.onLoadFinished(mLoader, data);
25138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mDeliveredData = true;
25238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
25338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
25438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        boolean hasDeliveredData() {
25538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            return mDeliveredData;
25638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
25738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
25838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        @MainThread
25938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        void reset() {
26038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            if (mDeliveredData) {
26138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                if (DEBUG) Log.v(TAG, "  Resetting: " + mLoader);
26238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                mCallback.onLoaderReset(mLoader);
26338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            }
26438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
26538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
26638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        @Override
26738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        public String toString() {
26838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            return mCallback.toString();
26938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
27038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
27138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        public void dump(String prefix, PrintWriter writer) {
27238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            writer.print(prefix); writer.print("mDeliveredData="); writer.println(
27338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                    mDeliveredData);
27438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
27538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    }
27638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
27738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    /**
27838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake     * ViewModel responsible for retaining {@link LoaderInfo} instances across configuration changes
27938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake     */
28038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    static class LoaderViewModel extends ViewModel {
28138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        private static final ViewModelProvider.Factory FACTORY = new ViewModelProvider.Factory() {
28238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            @NonNull
28338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            @Override
28438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            @SuppressWarnings("unchecked")
28538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
28638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                return (T) new LoaderViewModel();
28738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            }
28838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        };
28938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
29038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        @NonNull
29138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        static LoaderViewModel getInstance(ViewModelStore viewModelStore) {
29238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            return new ViewModelProvider(viewModelStore, FACTORY).get(LoaderViewModel.class);
29338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
29438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
29538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        private SparseArrayCompat<LoaderInfo> mLoaders = new SparseArrayCompat<>();
296afe28d91550483f9b7a82076a507151b4defd9baIan Lake        private boolean mCreatingLoader = false;
297afe28d91550483f9b7a82076a507151b4defd9baIan Lake
298afe28d91550483f9b7a82076a507151b4defd9baIan Lake        void startCreatingLoader() {
299afe28d91550483f9b7a82076a507151b4defd9baIan Lake            mCreatingLoader = true;
300afe28d91550483f9b7a82076a507151b4defd9baIan Lake        }
301afe28d91550483f9b7a82076a507151b4defd9baIan Lake
302afe28d91550483f9b7a82076a507151b4defd9baIan Lake        boolean isCreatingLoader() {
303afe28d91550483f9b7a82076a507151b4defd9baIan Lake            return mCreatingLoader;
304afe28d91550483f9b7a82076a507151b4defd9baIan Lake        }
305afe28d91550483f9b7a82076a507151b4defd9baIan Lake
306afe28d91550483f9b7a82076a507151b4defd9baIan Lake        void finishCreatingLoader() {
307afe28d91550483f9b7a82076a507151b4defd9baIan Lake            mCreatingLoader = false;
308afe28d91550483f9b7a82076a507151b4defd9baIan Lake        }
30938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
31038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        void putLoader(int id, @NonNull LoaderInfo info) {
31138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mLoaders.put(id, info);
31238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
31338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
31438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        @SuppressWarnings("unchecked")
31538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        <D> LoaderInfo<D> getLoader(int id) {
31638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            return mLoaders.get(id);
31738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
31838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
31938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        void removeLoader(int id) {
32038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mLoaders.remove(id);
32138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
32238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
32338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        boolean hasRunningLoaders() {
32438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            int size = mLoaders.size();
32538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            for (int index = 0; index < size; index++) {
32638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                LoaderInfo info = mLoaders.valueAt(index);
32738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                if (info.isCallbackWaitingForData()) {
32838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                    return true;
32938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                }
33038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            }
33138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            return false;
33238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
33338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
33438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        void markForRedelivery() {
33538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            int size = mLoaders.size();
33638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            for (int index = 0; index < size; index++) {
33738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                LoaderInfo info = mLoaders.valueAt(index);
33838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                info.markForRedelivery();
33938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            }
34038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
34138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
34238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        @Override
34338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        protected void onCleared() {
34438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            super.onCleared();
34538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            int size = mLoaders.size();
34638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            for (int index = 0; index < size; index++) {
34738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                LoaderInfo info = mLoaders.valueAt(index);
3485404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake                info.destroy(true);
34938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            }
3500f4d973e9bb5a00727068f6a76338908c21902fdIan Lake            mLoaders.clear();
35138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
35238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
35338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
35438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            if (mLoaders.size() > 0) {
35538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                writer.print(prefix); writer.println("Loaders:");
35638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                String innerPrefix = prefix + "    ";
35738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                for (int i = 0; i < mLoaders.size(); i++) {
35838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                    LoaderInfo info = mLoaders.valueAt(i);
35938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                    writer.print(prefix); writer.print("  #"); writer.print(mLoaders.keyAt(i));
36038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                    writer.print(": "); writer.println(info.toString());
36138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                    info.dump(innerPrefix, fd, writer, args);
36238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                }
36338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            }
36438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
36538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    }
36638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
36738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    private final @NonNull LifecycleOwner mLifecycleOwner;
36838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    private final @NonNull LoaderViewModel mLoaderViewModel;
36938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
37038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    LoaderManagerImpl(@NonNull LifecycleOwner lifecycleOwner,
37138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            @NonNull ViewModelStore viewModelStore) {
37238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        mLifecycleOwner = lifecycleOwner;
37338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        mLoaderViewModel = LoaderViewModel.getInstance(viewModelStore);
37438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    }
37538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
37638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    @MainThread
37738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    @NonNull
37838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    private <D> Loader<D> createAndInstallLoader(int id, @Nullable Bundle args,
3795404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake            @NonNull LoaderCallbacks<D> callback, @Nullable Loader<D> priorLoader) {
380732fb271c18d4bed045f5d8284b46d428e7ad210Ian Lake        LoaderInfo<D> info;
38138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        try {
382afe28d91550483f9b7a82076a507151b4defd9baIan Lake            mLoaderViewModel.startCreatingLoader();
38338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            Loader<D> loader = callback.onCreateLoader(id, args);
384f2b50d9efc9f0a438d6b1d85c463591398a2d306Ian Lake            if (loader == null) {
385f2b50d9efc9f0a438d6b1d85c463591398a2d306Ian Lake                throw new IllegalArgumentException("Object returned from onCreateLoader "
386f2b50d9efc9f0a438d6b1d85c463591398a2d306Ian Lake                        + "must not be null");
387f2b50d9efc9f0a438d6b1d85c463591398a2d306Ian Lake            }
38838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            if (loader.getClass().isMemberClass()
38938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                    && !Modifier.isStatic(loader.getClass().getModifiers())) {
39038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                throw new IllegalArgumentException("Object returned from onCreateLoader "
39138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                        + "must not be a non-static inner member class: "
39238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake                        + loader);
39338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            }
3945404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake            info = new LoaderInfo<>(id, args, loader, priorLoader);
39538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            if (DEBUG) Log.v(TAG, "  Created new loader " + info);
39638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mLoaderViewModel.putLoader(id, info);
39738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        } finally {
398afe28d91550483f9b7a82076a507151b4defd9baIan Lake            mLoaderViewModel.finishCreatingLoader();
39938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
400732fb271c18d4bed045f5d8284b46d428e7ad210Ian Lake        return info.setCallback(mLifecycleOwner, callback);
40138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    }
40238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
40338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    @MainThread
40438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    @NonNull
40538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    @Override
40638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    public <D> Loader<D> initLoader(int id, @Nullable Bundle args,
40738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            @NonNull LoaderCallbacks<D> callback) {
408afe28d91550483f9b7a82076a507151b4defd9baIan Lake        if (mLoaderViewModel.isCreatingLoader()) {
40938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            throw new IllegalStateException("Called while creating a loader");
41038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
41138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        if (Looper.getMainLooper() != Looper.myLooper()) {
41238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            throw new IllegalStateException("initLoader must be called on the main thread");
41338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
41438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
41538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        LoaderInfo<D> info = mLoaderViewModel.getLoader(id);
41638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
41738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);
41838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
41938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        if (info == null) {
42038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            // Loader doesn't already exist; create.
4215404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake            return createAndInstallLoader(id, args, callback, null);
42238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        } else {
42338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            if (DEBUG) Log.v(TAG, "  Re-using existing loader " + info);
42438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            return info.setCallback(mLifecycleOwner, callback);
42538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
42638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    }
42738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
42838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    @MainThread
42938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    @NonNull
43038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    @Override
43138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    public <D> Loader<D> restartLoader(int id, @Nullable Bundle args,
43238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            @NonNull LoaderCallbacks<D> callback) {
433afe28d91550483f9b7a82076a507151b4defd9baIan Lake        if (mLoaderViewModel.isCreatingLoader()) {
43438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            throw new IllegalStateException("Called while creating a loader");
43538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
43638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        if (Looper.getMainLooper() != Looper.myLooper()) {
43738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            throw new IllegalStateException("restartLoader must be called on the main thread");
43838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
43938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
44038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        if (DEBUG) Log.v(TAG, "restartLoader in " + this + ": args=" + args);
4415404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake        LoaderInfo<D> info = mLoaderViewModel.getLoader(id);
4425404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake        Loader<D> priorLoader = null;
4435404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake        if (info != null) {
4445404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake            priorLoader = info.destroy(false);
4455404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake        }
44638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        // And create a new Loader
4475404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake        return createAndInstallLoader(id, args, callback, priorLoader);
44838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    }
44938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
45038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    @MainThread
45138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    @Override
45238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    public void destroyLoader(int id) {
453afe28d91550483f9b7a82076a507151b4defd9baIan Lake        if (mLoaderViewModel.isCreatingLoader()) {
45438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            throw new IllegalStateException("Called while creating a loader");
45538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
45638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        if (Looper.getMainLooper() != Looper.myLooper()) {
45738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            throw new IllegalStateException("destroyLoader must be called on the main thread");
45838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
45938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
46038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        if (DEBUG) Log.v(TAG, "destroyLoader in " + this + " of " + id);
46138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        LoaderInfo info = mLoaderViewModel.getLoader(id);
46238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        if (info != null) {
4635404d815b5a1cc57d7b1dc6c1f89627f627e76eeIan Lake            info.destroy(true);
46438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            mLoaderViewModel.removeLoader(id);
46538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
46638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    }
46738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
46838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    @Nullable
46938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    @Override
47038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    public <D> Loader<D> getLoader(int id) {
471afe28d91550483f9b7a82076a507151b4defd9baIan Lake        if (mLoaderViewModel.isCreatingLoader()) {
47238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake            throw new IllegalStateException("Called while creating a loader");
47338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        }
47438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
47538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        LoaderInfo<D> info = mLoaderViewModel.getLoader(id);
47638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        return info != null ? info.getLoader() : null;
47738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    }
47838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
479afe28d91550483f9b7a82076a507151b4defd9baIan Lake    @Override
480afe28d91550483f9b7a82076a507151b4defd9baIan Lake    public void markForRedelivery() {
48138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        mLoaderViewModel.markForRedelivery();
48238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    }
48338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
48438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    @Override
48538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    public String toString() {
48638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        StringBuilder sb = new StringBuilder(128);
48738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        sb.append("LoaderManager{");
48838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        sb.append(Integer.toHexString(System.identityHashCode(this)));
48938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        sb.append(" in ");
49038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        DebugUtils.buildShortClassTag(mLifecycleOwner, sb);
49138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        sb.append("}}");
49238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        return sb.toString();
49338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    }
49438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
495946ba810ddc84c105a657c671b2630bed6d15942Ian Lake    @Deprecated
49638f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    @Override
49738f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
49838f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        mLoaderViewModel.dump(prefix, fd, writer, args);
49938f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    }
50038f4f4174d9cd53c553f14c19746500cb861b089Ian Lake
50138f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    @Override
50238f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    public boolean hasRunningLoaders() {
50338f4f4174d9cd53c553f14c19746500cb861b089Ian Lake        return mLoaderViewModel.hasRunningLoaders();
50438f4f4174d9cd53c553f14c19746500cb861b089Ian Lake    }
50538f4f4174d9cd53c553f14c19746500cb861b089Ian Lake}
506