LoaderManagerImpl.java revision ac5fe7c617c66850fff75a9fce9979c6e5674b0f
1707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet/*
2707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet * Copyright 2018 The Android Open Source Project
3707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet *
4707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet * Licensed under the Apache License, Version 2.0 (the "License");
5707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet * you may not use this file except in compliance with the License.
6707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet * You may obtain a copy of the License at
7707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet *
8707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet *      http://www.apache.org/licenses/LICENSE-2.0
9707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet *
10707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet * Unless required by applicable law or agreed to in writing, software
11707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet * distributed under the License is distributed on an "AS IS" BASIS,
12707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet * See the License for the specific language governing permissions and
14707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet * limitations under the License.
15707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet */
16707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet
173ced3cfd5b8f22b632c35f24e585c4847383b195David Grosspackage androidx.loader.app;
18707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet
193ced3cfd5b8f22b632c35f24e585c4847383b195David Grossimport android.arch.lifecycle.LifecycleOwner;
20707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouilletimport android.arch.lifecycle.MutableLiveData;
2183e24dc4706a5b7089881a55daf05b3924fab3b7David Grossimport android.arch.lifecycle.Observer;
22707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouilletimport android.arch.lifecycle.ViewModel;
23707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouilletimport android.arch.lifecycle.ViewModelProvider;
24707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouilletimport android.arch.lifecycle.ViewModelStore;
25707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouilletimport android.os.Bundle;
26707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouilletimport android.os.Looper;
27689d892203c06c66c7bb2e374462a8434e40b75fMichael Butlerimport androidx.annotation.MainThread;
28389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouilletimport androidx.annotation.NonNull;
29689d892203c06c66c7bb2e374462a8434e40b75fMichael Butlerimport androidx.annotation.Nullable;
30689d892203c06c66c7bb2e374462a8434e40b75fMichael Butlerimport androidx.loader.content.Loader;
31707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouilletimport androidx.core.util.DebugUtils;
32707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouilletimport androidx.collection.SparseArrayCompat;
33707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouilletimport android.util.Log;
34389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet
35389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouilletimport java.io.FileDescriptor;
36389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouilletimport java.io.PrintWriter;
37389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouilletimport java.lang.reflect.Modifier;
38389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet
39389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouilletclass LoaderManagerImpl extends LoaderManager {
40389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet    static final String TAG = "LoaderManager";
41389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet    static boolean DEBUG = false;
42a4e2ee81d015b5e26897d18b18dd50044faba62fJean-Luc Brouillet
43389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet    /**
44389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet     * Class which manages the state of a {@link Loader} and its associated
45389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet     * {@link LoaderCallbacks}
46389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet     *
47389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet     * @param <D> Type of data the Loader handles
48389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet     */
49389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet    public static class LoaderInfo<D> extends MutableLiveData<D>
50389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet            implements Loader.OnLoadCompleteListener<D> {
51389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet
52389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet        private final int mId;
53389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet        private final @Nullable Bundle mArgs;
54389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet        private final @NonNull Loader<D> mLoader;
55389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet        private LifecycleOwner mLifecycleOwner;
56389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet        private LoaderObserver<D> mObserver;
57389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet
58389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet        LoaderInfo(int id, @Nullable Bundle args, @NonNull Loader<D> loader) {
5996811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross            mId = id;
6096811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross            mArgs = args;
6196811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross            mLoader = loader;
6296811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross            mLoader.registerListener(id, this);
6396811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross        }
6496811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross
6596811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross        @NonNull
6696811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross        Loader<D> getLoader() {
6796811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross            return mLoader;
68389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet        }
69389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet
70389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet        @Override
71389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet        protected void onActive() {
72389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet            if (DEBUG) Log.v(TAG, "  Starting: " + LoaderInfo.this);
73d2d0c031c43e8e5aafc75e8a652d79bcc2aaca99Jean-Luc Brouillet            mLoader.startLoading();
74389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet        }
75389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet
763ced3cfd5b8f22b632c35f24e585c4847383b195David Gross        @Override
77389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet        protected void onInactive() {
78389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet            if (DEBUG) Log.v(TAG, "  Stopping: " + LoaderInfo.this);
79389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet            mLoader.stopLoading();
80d2d0c031c43e8e5aafc75e8a652d79bcc2aaca99Jean-Luc Brouillet        }
81389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet
82389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet        /**
83389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet         * Set the {@link LoaderCallbacks} to associate with this {@link Loader}. This
84389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet         * removes any existing {@link LoaderCallbacks}.
85389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet         *
863ced3cfd5b8f22b632c35f24e585c4847383b195David Gross         * @param owner The lifecycle that should be used to start and stop the {@link Loader}
8783e24dc4706a5b7089881a55daf05b3924fab3b7David Gross         * @param callback The new {@link LoaderCallbacks} to use
881f4381539b7e89c42336ee7cd1addb9a4c317b34David Gross         * @return The {@link Loader} associated with this LoaderInfo
8983e24dc4706a5b7089881a55daf05b3924fab3b7David Gross         */
9083e24dc4706a5b7089881a55daf05b3924fab3b7David Gross        @MainThread
9183e24dc4706a5b7089881a55daf05b3924fab3b7David Gross        @NonNull
923ced3cfd5b8f22b632c35f24e585c4847383b195David Gross        Loader<D> setCallback(@NonNull LifecycleOwner owner,
93707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet                @NonNull LoaderCallbacks<D> callback) {
94707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            LoaderObserver<D> observer = new LoaderObserver<>(mLoader, callback);
953ced3cfd5b8f22b632c35f24e585c4847383b195David Gross            // Add the new observer
96e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet            observe(owner, observer);
97707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            // Loaders only support one observer at a time, so remove the current observer, if any
98707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            if (mObserver != null) {
993ced3cfd5b8f22b632c35f24e585c4847383b195David Gross                removeObserver(mObserver);
100707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            }
101707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            mLifecycleOwner = owner;
102e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet            mObserver = observer;
103e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet            return mLoader;
104e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet        }
105e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet
106e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet        void markForRedelivery() {
107e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet            LifecycleOwner lifecycleOwner = mLifecycleOwner;
108e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet            LoaderObserver<D> observer = mObserver;
109e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet            if (lifecycleOwner != null && observer != null) {
110e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet                // Removing and re-adding the observer ensures that the
111e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet                // observer is called again, even if they had already
112e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet                // received the current data
113389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet                // Use super.removeObserver to avoid nulling out mLifecycleOwner & mObserver
114e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet                super.removeObserver(observer);
115707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet                observe(lifecycleOwner, observer);
116707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            }
1173ced3cfd5b8f22b632c35f24e585c4847383b195David Gross        }
118e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet
11996811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross        boolean isCallbackWaitingForData() {
12096811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross            //noinspection SimplifiableIfStatement
1218b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet            if (!hasActiveObservers()) {
1228b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet                // No active observers means no one is waiting for data
1233ced3cfd5b8f22b632c35f24e585c4847383b195David Gross                return false;
1248b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet            }
1258b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet            return mObserver != null && !mObserver.hasDeliveredData();
1268b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet        }
127105807d963d969197fe78185ed588bfad3dc0ea5Miao Wang
128105807d963d969197fe78185ed588bfad3dc0ea5Miao Wang        @Override
129105807d963d969197fe78185ed588bfad3dc0ea5Miao Wang        public void removeObserver(@NonNull Observer<D> observer) {
130e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet            super.removeObserver(observer);
131389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet            // Clear out our references when the observer is removed to avoid leaking
132389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet            mLifecycleOwner = null;
133389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet            mObserver = null;
134707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet        }
135707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet
1363ced3cfd5b8f22b632c35f24e585c4847383b195David Gross        @MainThread
137e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet        void destroy() {
138707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            if (DEBUG) Log.v(TAG, "  Destroying: " + this);
139707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            // First tell the Loader that we don't need it anymore
1403ced3cfd5b8f22b632c35f24e585c4847383b195David Gross            mLoader.cancelLoad();
141707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            mLoader.abandon();
142707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            // Then clean up the LoaderObserver
143e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet            LoaderObserver<D> observer = mObserver;
144e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet            if (observer != null) {
145e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet                removeObserver(observer);
146e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet                observer.reset();
147e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet            }
148e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet            // Finally, send the reset to the Loader
149e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet            mLoader.unregisterListener(this);
150e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet            mLoader.reset();
151e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet        }
152e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet
153e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet        @Override
154e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet        public void onLoadComplete(@NonNull Loader<D> loader, @Nullable D data) {
155707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);
156707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            if (Looper.myLooper() == Looper.getMainLooper()) {
1573ced3cfd5b8f22b632c35f24e585c4847383b195David Gross                setValue(data);
158e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet            } else {
15996811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross                // The Loader#deliverResult method that calls this should
16096811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross                // only be called on the main thread, so this should never
1618b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet                // happen, but we don't want to lose the data
1628b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet                if (DEBUG) {
1633ced3cfd5b8f22b632c35f24e585c4847383b195David Gross                    Log.w(TAG, "onLoadComplete was incorrectly called on a "
1648b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet                            + "background thread");
1658b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet                }
1668b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet                postValue(data);
167105807d963d969197fe78185ed588bfad3dc0ea5Miao Wang            }
168105807d963d969197fe78185ed588bfad3dc0ea5Miao Wang        }
169105807d963d969197fe78185ed588bfad3dc0ea5Miao Wang
170e127e49e67b53c96eb79f6a9c58f956ad4761227Jean-Luc Brouillet        @Override
171389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet        public String toString() {
172389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet            StringBuilder sb = new StringBuilder(64);
173389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet            sb.append("LoaderInfo{");
174707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            sb.append(Integer.toHexString(System.identityHashCode(this)));
175707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            sb.append(" #");
176033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler            sb.append(mId);
177033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler            sb.append(" : ");
178425b2594c76e934dfdbc93209253e3c189571149David Gross            DebugUtils.buildShortClassTag(mLoader, sb);
179707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            sb.append("}}");
180707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            return sb.toString();
181f1817c663af4f22bc089ef82cd50df4186422c42Yang Ni        }
182f1817c663af4f22bc089ef82cd50df4186422c42Yang Ni
183f1817c663af4f22bc089ef82cd50df4186422c42Yang Ni        public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
1848b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet            writer.print(prefix); writer.print("mId="); writer.print(mId);
185389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet            writer.print(" mArgs="); writer.println(mArgs);
1863ced3cfd5b8f22b632c35f24e585c4847383b195David Gross            writer.print(prefix); writer.print("mLoader="); writer.println(mLoader);
187707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            mLoader.dump(prefix + "  ", fd, writer, args);
188707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            if (mObserver != null) {
189707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet                writer.print(prefix); writer.print("mCallbacks="); writer.println(mObserver);
190f1817c663af4f22bc089ef82cd50df4186422c42Yang Ni                mObserver.dump(prefix + "  ", writer);
1918b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet            }
192389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet            writer.print(prefix); writer.print("mData="); writer.println(
1933ced3cfd5b8f22b632c35f24e585c4847383b195David Gross                    getLoader().dataToString(getValue()));
194707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            writer.print(prefix); writer.print("mStarted="); writer.println(
195707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet                    hasActiveObservers());
196707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet        }
197707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet    }
1981f4381539b7e89c42336ee7cd1addb9a4c317b34David Gross
1991f4381539b7e89c42336ee7cd1addb9a4c317b34David Gross    /**
200b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross     * Encapsulates the {@link LoaderCallbacks} as a {@link Observer}.
201b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross     *
202b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross     * @param <D> Type of data the LoaderCallbacks handles
203b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross     */
2041f4381539b7e89c42336ee7cd1addb9a4c317b34David Gross    static class LoaderObserver<D> implements Observer<D> {
205891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross
206891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross        private final @NonNull Loader<D> mLoader;
207891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross        private final @NonNull LoaderCallbacks<D> mCallback;
208891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross
209891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross        private boolean mDeliveredData = false;
210891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross
211891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross        LoaderObserver(@NonNull Loader<D> loader, @NonNull LoaderCallbacks<D> callback) {
212891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross            mLoader = loader;
213891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross            mCallback = callback;
214891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross        }
215891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross
216891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross        @Override
217891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross        public void onChanged(@Nullable D data) {
218891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross            if (DEBUG) {
219891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross                Log.v(TAG, "  onLoadFinished in " + mLoader + ": "
220891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross                        + mLoader.dataToString(data));
221b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross            }
222891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross            mCallback.onLoadFinished(mLoader, data);
223891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross            mDeliveredData = true;
224891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross        }
225891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross
226891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross        boolean hasDeliveredData() {
227891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross            return mDeliveredData;
228891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross        }
229891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross
230891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross        @MainThread
231891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross        void reset() {
232891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross            if (mDeliveredData) {
233033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler                if (DEBUG) Log.v(TAG, "  Resetting: " + mLoader);
234891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross                mCallback.onLoaderReset(mLoader);
235891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross            }
236891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross        }
237033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler
238033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler        @Override
239891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross        public String toString() {
240891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross            return mCallback.toString();
241b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross        }
2421f4381539b7e89c42336ee7cd1addb9a4c317b34David Gross
2431f4381539b7e89c42336ee7cd1addb9a4c317b34David Gross        public void dump(String prefix, PrintWriter writer) {
2441f4381539b7e89c42336ee7cd1addb9a4c317b34David Gross            writer.print(prefix); writer.print("mDeliveredData="); writer.println(
245ef22aa5727b96e9a0863ef71cfbe3dbdac339408Jean-Luc Brouillet                    mDeliveredData);
246ef22aa5727b96e9a0863ef71cfbe3dbdac339408Jean-Luc Brouillet        }
2471f4381539b7e89c42336ee7cd1addb9a4c317b34David Gross    }
2481f4381539b7e89c42336ee7cd1addb9a4c317b34David Gross
249ef22aa5727b96e9a0863ef71cfbe3dbdac339408Jean-Luc Brouillet    /**
250ef22aa5727b96e9a0863ef71cfbe3dbdac339408Jean-Luc Brouillet     * ViewModel responsible for retaining {@link LoaderInfo} instances across configuration changes
251ef22aa5727b96e9a0863ef71cfbe3dbdac339408Jean-Luc Brouillet     */
2521f4381539b7e89c42336ee7cd1addb9a4c317b34David Gross    static class LoaderViewModel extends ViewModel {
253ef22aa5727b96e9a0863ef71cfbe3dbdac339408Jean-Luc Brouillet        private static final ViewModelProvider.Factory FACTORY = new ViewModelProvider.Factory() {
254ef22aa5727b96e9a0863ef71cfbe3dbdac339408Jean-Luc Brouillet            @NonNull
2551f4381539b7e89c42336ee7cd1addb9a4c317b34David Gross            @Override
256b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross            @SuppressWarnings("unchecked")
257b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross            public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
258b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross                return (T) new LoaderViewModel();
259033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler            }
260ef22aa5727b96e9a0863ef71cfbe3dbdac339408Jean-Luc Brouillet        };
261ef22aa5727b96e9a0863ef71cfbe3dbdac339408Jean-Luc Brouillet
262ef22aa5727b96e9a0863ef71cfbe3dbdac339408Jean-Luc Brouillet        @NonNull
2631f4381539b7e89c42336ee7cd1addb9a4c317b34David Gross        static LoaderViewModel getInstance(ViewModelStore viewModelStore) {
264b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross            return new ViewModelProvider(viewModelStore, FACTORY).get(LoaderViewModel.class);
265b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross        }
266b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross
267b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross        private SparseArrayCompat<LoaderInfo> mLoaders = new SparseArrayCompat<>();
268033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler        private boolean mCreatingLoader = false;
269707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet
270707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet        void startCreatingLoader() {
271707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            mCreatingLoader = true;
2728b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet        }
273b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross
274b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross        boolean isCreatingLoader() {
2758b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet            return mCreatingLoader;
276707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet        }
2778b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet
2788b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet        void finishCreatingLoader() {
2798b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet            mCreatingLoader = false;
2808b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet        }
2818b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet
2828b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet        void putLoader(int id, @NonNull LoaderInfo info) {
2838b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet            mLoaders.put(id, info);
2848b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet        }
2858b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet
2868b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet        @SuppressWarnings("unchecked")
287707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet        <D> LoaderInfo<D> getLoader(int id) {
2883ced3cfd5b8f22b632c35f24e585c4847383b195David Gross            return mLoaders.get(id);
289707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet        }
290707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet
291707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet        void removeLoader(int id) {
2928b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet            mLoaders.remove(id);
2938b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet        }
294389f26c7c442c37994db9f43d013fe3953c9353cJean-Luc Brouillet
2958b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet        boolean hasRunningLoaders() {
2968b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet            int size = mLoaders.size();
297707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            for (int index = 0; index < size; index++) {
298707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet                LoaderInfo info = mLoaders.valueAt(index);
299707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet                if (info.isCallbackWaitingForData()) {
3008b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet                    return true;
301a4e2ee81d015b5e26897d18b18dd50044faba62fJean-Luc Brouillet                }
3028b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet            }
3038b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet            return false;
3048b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet        }
3058b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet
3068b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet        void markForRedelivery() {
3078b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet            int size = mLoaders.size();
3088b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet            for (int index = 0; index < size; index++) {
309b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross                LoaderInfo info = mLoaders.valueAt(index);
310b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross                info.markForRedelivery();
311b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross            }
312b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross        }
313891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross
314891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross        @Override
315b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross        protected void onCleared() {
316b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross            super.onCleared();
317b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross            int size = mLoaders.size();
318b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross            for (int index = 0; index < size; index++) {
319b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross                LoaderInfo info = mLoaders.valueAt(index);
320b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross                info.destroy();
321b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross            }
322891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross            mLoaders.clear();
323891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross        }
324891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross
325891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross        public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
326891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross            if (mLoaders.size() > 0) {
327891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross                writer.print(prefix); writer.println("Loaders:");
328891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross                String innerPrefix = prefix + "    ";
329891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross                for (int i = 0; i < mLoaders.size(); i++) {
330891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross                    LoaderInfo info = mLoaders.valueAt(i);
331891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross                    writer.print(prefix); writer.print("  #"); writer.print(mLoaders.keyAt(i));
332891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross                    writer.print(": "); writer.println(info.toString());
333891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross                    info.dump(innerPrefix, fd, writer, args);
334891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross                }
335891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross            }
336891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross        }
337891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross    }
338891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross
339891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross    private final @NonNull LifecycleOwner mLifecycleOwner;
340891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross    private final @NonNull LoaderViewModel mLoaderViewModel;
341891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross
342891b10f7048c62a37a74c4b570be220089dfd55eDavid Gross    LoaderManagerImpl(@NonNull LifecycleOwner lifecycleOwner,
34396811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross            @NonNull ViewModelStore viewModelStore) {
34496811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross        mLifecycleOwner = lifecycleOwner;
34596811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross        mLoaderViewModel = LoaderViewModel.getInstance(viewModelStore);
34696811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross    }
34796811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross
34896811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross    @MainThread
34996811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross    @NonNull
35096811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross    private <D> Loader<D> createAndInstallLoader(int id, @Nullable Bundle args,
35196811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross            @NonNull LoaderCallbacks<D> callback) {
35296811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross        LoaderInfo<D> info;
35396811e2b1347889a25bd9686f47ca3cbf061fb1bDavid Gross        try {
354033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler            mLoaderViewModel.startCreatingLoader();
355b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross            Loader<D> loader = callback.onCreateLoader(id, args);
356033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler            if (loader.getClass().isMemberClass()
357b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross                    && !Modifier.isStatic(loader.getClass().getModifiers())) {
358033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler                throw new IllegalArgumentException("Object returned from onCreateLoader "
359b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross                        + "must not be a non-static inner member class: "
360b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross                        + loader);
361b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross            }
362033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler            info = new LoaderInfo<>(id, args, loader);
363b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross            if (DEBUG) Log.v(TAG, "  Created new loader " + info);
364b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross            mLoaderViewModel.putLoader(id, info);
365033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler        } finally {
366425b2594c76e934dfdbc93209253e3c189571149David Gross            mLoaderViewModel.finishCreatingLoader();
367b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross        }
3681f4381539b7e89c42336ee7cd1addb9a4c317b34David Gross        return info.setCallback(mLifecycleOwner, callback);
369b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross    }
3701f4381539b7e89c42336ee7cd1addb9a4c317b34David Gross
3711f4381539b7e89c42336ee7cd1addb9a4c317b34David Gross    @MainThread
3721f4381539b7e89c42336ee7cd1addb9a4c317b34David Gross    @NonNull
3731f4381539b7e89c42336ee7cd1addb9a4c317b34David Gross    @Override
374033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler    public <D> Loader<D> initLoader(int id, @Nullable Bundle args,
375033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler            @NonNull LoaderCallbacks<D> callback) {
376033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler        if (mLoaderViewModel.isCreatingLoader()) {
377033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler            throw new IllegalStateException("Called while creating a loader");
378033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler        }
379033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler        if (Looper.getMainLooper() != Looper.myLooper()) {
3805f916fc9a7ae95f172492bdfe5344c37beff3a6fMichael Butler            throw new IllegalStateException("initLoader must be called on the main thread");
381033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler        }
3821f4381539b7e89c42336ee7cd1addb9a4c317b34David Gross
383033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler        LoaderInfo<D> info = mLoaderViewModel.getLoader(id);
384033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler
385033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler        if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);
386033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler
3871f4381539b7e89c42336ee7cd1addb9a4c317b34David Gross        if (info == null) {
3881f4381539b7e89c42336ee7cd1addb9a4c317b34David Gross            // Loader doesn't already exist; create.
389707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            return createAndInstallLoader(id, args, callback);
390707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet        } else {
391e413eef7e5f790acdb8e5d07cacfee9afab6f7beDavid Gross            if (DEBUG) Log.v(TAG, "  Re-using existing loader " + info);
392e413eef7e5f790acdb8e5d07cacfee9afab6f7beDavid Gross            return info.setCallback(mLifecycleOwner, callback);
393e413eef7e5f790acdb8e5d07cacfee9afab6f7beDavid Gross        }
394e413eef7e5f790acdb8e5d07cacfee9afab6f7beDavid Gross    }
395e413eef7e5f790acdb8e5d07cacfee9afab6f7beDavid Gross
396e413eef7e5f790acdb8e5d07cacfee9afab6f7beDavid Gross    @MainThread
3978b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet    @NonNull
398e413eef7e5f790acdb8e5d07cacfee9afab6f7beDavid Gross    @Override
399707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet    public <D> Loader<D> restartLoader(int id, @Nullable Bundle args,
400707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            @NonNull LoaderCallbacks<D> callback) {
401707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet        if (mLoaderViewModel.isCreatingLoader()) {
402e413eef7e5f790acdb8e5d07cacfee9afab6f7beDavid Gross            throw new IllegalStateException("Called while creating a loader");
403707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet        }
404707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet        if (Looper.getMainLooper() != Looper.myLooper()) {
405707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            throw new IllegalStateException("restartLoader must be called on the main thread");
406707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet        }
4078b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet
408e413eef7e5f790acdb8e5d07cacfee9afab6f7beDavid Gross        if (DEBUG) Log.v(TAG, "restartLoader in " + this + ": args=" + args);
4098b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet        // Destroy any existing Loader
4108b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet        destroyLoader(id);
4118b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet        // And create a new Loader
4122150f1d186b2854fb5aa609594be12a667f845f0Jean-Luc Brouillet        return createAndInstallLoader(id, args, callback);
413e413eef7e5f790acdb8e5d07cacfee9afab6f7beDavid Gross    }
4142150f1d186b2854fb5aa609594be12a667f845f0Jean-Luc Brouillet
4152150f1d186b2854fb5aa609594be12a667f845f0Jean-Luc Brouillet    @MainThread
4162150f1d186b2854fb5aa609594be12a667f845f0Jean-Luc Brouillet    @Override
4178b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet    public void destroyLoader(int id) {
4188b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet        if (mLoaderViewModel.isCreatingLoader()) {
419707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            throw new IllegalStateException("Called while creating a loader");
420e413eef7e5f790acdb8e5d07cacfee9afab6f7beDavid Gross        }
421707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet        if (Looper.getMainLooper() != Looper.myLooper()) {
422707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet            throw new IllegalStateException("destroyLoader must be called on the main thread");
4238b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet        }
4248b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet
4258b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet        if (DEBUG) Log.v(TAG, "destroyLoader in " + this + " of " + id);
4268b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet        LoaderInfo info = mLoaderViewModel.getLoader(id);
4278b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet        if (info != null) {
4288b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet            info.destroy();
4298b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet            mLoaderViewModel.removeLoader(id);
430707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet        }
431033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler    }
432033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler
433033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler    @Nullable
434033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler    @Override
435033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler    public <D> Loader<D> getLoader(int id) {
436033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler        if (mLoaderViewModel.isCreatingLoader()) {
437033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler            throw new IllegalStateException("Called while creating a loader");
438689d892203c06c66c7bb2e374462a8434e40b75fMichael Butler        }
439033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler
440689d892203c06c66c7bb2e374462a8434e40b75fMichael Butler        LoaderInfo<D> info = mLoaderViewModel.getLoader(id);
441033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler        return info != null ? info.getLoader() : null;
442689d892203c06c66c7bb2e374462a8434e40b75fMichael Butler    }
443b26049114bc4c64e6bea3a5d5d129fcaec8e69b6David Gross
4443ced3cfd5b8f22b632c35f24e585c4847383b195David Gross    @Override
445033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler    public void markForRedelivery() {
446033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler        mLoaderViewModel.markForRedelivery();
447689d892203c06c66c7bb2e374462a8434e40b75fMichael Butler    }
448689d892203c06c66c7bb2e374462a8434e40b75fMichael Butler
449033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler    @Override
450689d892203c06c66c7bb2e374462a8434e40b75fMichael Butler    public String toString() {
451033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler        StringBuilder sb = new StringBuilder(128);
452707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet        sb.append("LoaderManager{");
453707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet        sb.append(Integer.toHexString(System.identityHashCode(this)));
454707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet        sb.append(" in ");
455707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet        DebugUtils.buildShortClassTag(mLifecycleOwner, sb);
456689d892203c06c66c7bb2e374462a8434e40b75fMichael Butler        sb.append("}}");
457689d892203c06c66c7bb2e374462a8434e40b75fMichael Butler        return sb.toString();
458033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler    }
459033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler
460033b8a6ce8ebd2a01ecccc6bae96d0fff8d4964eMichael Butler    @Override
461689d892203c06c66c7bb2e374462a8434e40b75fMichael Butler    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
462689d892203c06c66c7bb2e374462a8434e40b75fMichael Butler        mLoaderViewModel.dump(prefix, fd, writer, args);
463689d892203c06c66c7bb2e374462a8434e40b75fMichael Butler    }
464689d892203c06c66c7bb2e374462a8434e40b75fMichael Butler
465707dbd2d55f5dacf78ffb3ad7c8b3f37c2e9d758Jean-Luc Brouillet    @Override
466689d892203c06c66c7bb2e374462a8434e40b75fMichael Butler    public boolean hasRunningLoaders() {
467689d892203c06c66c7bb2e374462a8434e40b75fMichael Butler        return mLoaderViewModel.hasRunningLoaders();
468689d892203c06c66c7bb2e374462a8434e40b75fMichael Butler    }
4698b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet}
4708b99bb1d98a42b67ba1c00e12c7abb3708cf7c05Jean-Luc Brouillet