1c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay/* 2c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * Copyright (C) 2017 The Android Open Source Project 3c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * 4c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * Licensed under the Apache License, Version 2.0 (the "License"); 5c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * you may not use this file except in compliance with the License. 6c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * You may obtain a copy of the License at 7c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * 8c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * http://www.apache.org/licenses/LICENSE-2.0 9c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * 10c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * Unless required by applicable law or agreed to in writing, software 11c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * distributed under the License is distributed on an "AS IS" BASIS, 12c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * See the License for the specific language governing permissions and 14c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * limitations under the License. 15c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay */ 16c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 17c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKaypackage android.support.content; 18c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 19c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport static android.support.v4.util.Preconditions.checkArgument; 20c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 21c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.app.LoaderManager; 22c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.app.LoaderManager.LoaderCallbacks; 23c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.content.Context; 24c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.content.Loader; 25c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.database.Cursor; 26c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.os.Bundle; 27c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.support.annotation.NonNull; 28c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.util.Log; 29c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 30c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay/** 31c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * A {@link ContentPager.QueryRunner} that executes queries using a {@link LoaderManager}. 32c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * Use this when preparing {@link ContentPager} to run in an Activity or Fragment scope. 33c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay */ 34c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKaypublic final class LoaderQueryRunner implements ContentPager.QueryRunner { 35c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 36c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay private static final boolean DEBUG = false; 37c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay private static final String TAG = "LoaderQueryRunner"; 38c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay private static final String CONTENT_URI_KEY = "contentUri"; 39c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 40c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay private final Context mContext; 41c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay private final LoaderManager mLoaderMgr; 42c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 43c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public LoaderQueryRunner(@NonNull Context context, @NonNull LoaderManager loaderMgr) { 44c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay mContext = context; 45c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay mLoaderMgr = loaderMgr; 46c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 47c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 48c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @Override 49c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @SuppressWarnings("unchecked") // feels spurious. But can't commit line :80 w/o this. 50c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public void query(final @NonNull Query query, @NonNull final Callback callback) { 51c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay if (DEBUG) Log.d(TAG, "Handling query: " + query); 52c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 53c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay LoaderCallbacks callbacks = new LoaderCallbacks<Cursor>() { 54c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @Override 55c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public Loader<Cursor> onCreateLoader(final int id, final Bundle args) { 56c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay if (DEBUG) Log.i(TAG, "Loading results for query: " + query); 57c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay checkArgument(id == query.getId(), "Id doesn't match query id."); 58c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 59c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return new android.content.CursorLoader(mContext) { 60c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @Override 61c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public Cursor loadInBackground() { 62c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return callback.runQueryInBackground(query); 63c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 64c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay }; 65c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 66c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 67c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @Override 68c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { 69c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay if (DEBUG) Log.i(TAG, "Finished loading: " + query); 70c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay mLoaderMgr.destroyLoader(query.getId()); 71c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay callback.onQueryFinished(query, cursor); 72c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 73c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 74c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @Override 75c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public void onLoaderReset(Loader<Cursor> loader) { 76c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay if (DEBUG) Log.w(TAG, "Ignoring loader reset for query: " + query); 77c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 78c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay }; 79c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 80c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay mLoaderMgr.restartLoader(query.getId(), null, callbacks); 81c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 82c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 83c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @Override 84c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public boolean isRunning(@NonNull Query query) { 85c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay Loader<Cursor> loader = mLoaderMgr.getLoader(query.getId()); 86c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return loader != null && loader.isStarted(); 87c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay // Hmm, when exactly would the loader not be started? Does it imply that it will 88c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay // be starting at some point? 89c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 90c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 91c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @Override 92c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public void cancel(@NonNull Query query) { 93c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay mLoaderMgr.destroyLoader(query.getId()); 94c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 95c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay} 96