Add the Loader and supporting classes.
Loaders are designed to make it easier to manage asynchronously loading data. Change-Id: I948db08c721411e94fca071dc6fb4db2b83ea4d6
This commit is contained in:
542
api/current.xml
542
api/current.xml
@@ -19421,6 +19421,21 @@
|
||||
<parameter name="options" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="setDisplayOptions"
|
||||
return="void"
|
||||
abstract="true"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="options" type="int">
|
||||
</parameter>
|
||||
<parameter name="mask" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="setDividerDrawable"
|
||||
return="void"
|
||||
abstract="true"
|
||||
@@ -27547,6 +27562,109 @@
|
||||
</parameter>
|
||||
</method>
|
||||
</class>
|
||||
<class name="LoaderManagingFragment"
|
||||
extends="android.app.Fragment"
|
||||
abstract="true"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<implements name="android.content.Loader.OnLoadCompleteListener">
|
||||
</implements>
|
||||
<constructor name="LoaderManagingFragment"
|
||||
type="android.app.LoaderManagingFragment"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</constructor>
|
||||
<method name="getLoader"
|
||||
return="android.content.Loader<D>"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="id" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="onCreateLoader"
|
||||
return="android.content.Loader<D>"
|
||||
abstract="true"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="protected"
|
||||
>
|
||||
<parameter name="id" type="int">
|
||||
</parameter>
|
||||
<parameter name="args" type="android.os.Bundle">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="onInitializeLoaders"
|
||||
return="void"
|
||||
abstract="true"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="protected"
|
||||
>
|
||||
</method>
|
||||
<method name="onLoadComplete"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="loader" type="android.content.Loader<D>">
|
||||
</parameter>
|
||||
<parameter name="data" type="D">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="onLoadFinished"
|
||||
return="void"
|
||||
abstract="true"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="protected"
|
||||
>
|
||||
<parameter name="loader" type="android.content.Loader<D>">
|
||||
</parameter>
|
||||
<parameter name="data" type="D">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="startLoading"
|
||||
return="android.content.Loader<D>"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="protected"
|
||||
>
|
||||
<parameter name="id" type="int">
|
||||
</parameter>
|
||||
<parameter name="args" type="android.os.Bundle">
|
||||
</parameter>
|
||||
</method>
|
||||
</class>
|
||||
<class name="LocalActivityManager"
|
||||
extends="java.lang.Object"
|
||||
abstract="false"
|
||||
@@ -35277,6 +35395,58 @@
|
||||
</parameter>
|
||||
</constructor>
|
||||
</class>
|
||||
<class name="AsyncTaskLoader"
|
||||
extends="android.content.Loader"
|
||||
abstract="true"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<constructor name="AsyncTaskLoader"
|
||||
type="android.content.AsyncTaskLoader"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="context" type="android.content.Context">
|
||||
</parameter>
|
||||
</constructor>
|
||||
<method name="cancelLoad"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="forceLoad"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="loadInBackground"
|
||||
return="D"
|
||||
abstract="true"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
</class>
|
||||
<class name="BroadcastReceiver"
|
||||
extends="java.lang.Object"
|
||||
abstract="true"
|
||||
@@ -40673,6 +40843,212 @@
|
||||
</parameter>
|
||||
</method>
|
||||
</class>
|
||||
<class name="CursorLoader"
|
||||
extends="android.content.AsyncTaskLoader"
|
||||
abstract="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<constructor name="CursorLoader"
|
||||
type="android.content.CursorLoader"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="context" type="android.content.Context">
|
||||
</parameter>
|
||||
<parameter name="uri" type="android.net.Uri">
|
||||
</parameter>
|
||||
<parameter name="projection" type="java.lang.String[]">
|
||||
</parameter>
|
||||
<parameter name="selection" type="java.lang.String">
|
||||
</parameter>
|
||||
<parameter name="selectionArgs" type="java.lang.String[]">
|
||||
</parameter>
|
||||
<parameter name="sortOrder" type="java.lang.String">
|
||||
</parameter>
|
||||
</constructor>
|
||||
<method name="deliverResult"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="cursor" type="android.database.Cursor">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="destroy"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="getProjection"
|
||||
return="java.lang.String[]"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="getSelection"
|
||||
return="java.lang.String"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="getSelectionArgs"
|
||||
return="java.lang.String[]"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="getSortOrder"
|
||||
return="java.lang.String"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="getUri"
|
||||
return="android.net.Uri"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="loadInBackground"
|
||||
return="android.database.Cursor"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="setProjection"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="projection" type="java.lang.String[]">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="setSelection"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="selection" type="java.lang.String">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="setSelectionArgs"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="selectionArgs" type="java.lang.String[]">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="setSortOrder"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="sortOrder" type="java.lang.String">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="setUri"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="uri" type="android.net.Uri">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="startLoading"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="stopLoading"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
</class>
|
||||
<interface name="DialogInterface"
|
||||
abstract="true"
|
||||
static="false"
|
||||
@@ -45639,6 +46015,172 @@
|
||||
</parameter>
|
||||
</constructor>
|
||||
</class>
|
||||
<class name="Loader"
|
||||
extends="java.lang.Object"
|
||||
abstract="true"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<constructor name="Loader"
|
||||
type="android.content.Loader"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="context" type="android.content.Context">
|
||||
</parameter>
|
||||
</constructor>
|
||||
<method name="deliverResult"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="data" type="D">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="destroy"
|
||||
return="void"
|
||||
abstract="true"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="forceLoad"
|
||||
return="void"
|
||||
abstract="true"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="getContext"
|
||||
return="android.content.Context"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="getId"
|
||||
return="int"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="registerListener"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="id" type="int">
|
||||
</parameter>
|
||||
<parameter name="listener" type="android.content.Loader.OnLoadCompleteListener<D>">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="startLoading"
|
||||
return="void"
|
||||
abstract="true"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="stopLoading"
|
||||
return="void"
|
||||
abstract="true"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="unregisterListener"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="listener" type="android.content.Loader.OnLoadCompleteListener<D>">
|
||||
</parameter>
|
||||
</method>
|
||||
</class>
|
||||
<class name="Loader.ForceLoadContentObserver"
|
||||
extends="android.database.ContentObserver"
|
||||
abstract="false"
|
||||
static="false"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<constructor name="Loader.ForceLoadContentObserver"
|
||||
type="android.content.Loader.ForceLoadContentObserver"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</constructor>
|
||||
</class>
|
||||
<interface name="Loader.OnLoadCompleteListener"
|
||||
abstract="true"
|
||||
static="true"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<method name="onLoadComplete"
|
||||
return="void"
|
||||
abstract="true"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="loader" type="android.content.Loader<D>">
|
||||
</parameter>
|
||||
<parameter name="data" type="D">
|
||||
</parameter>
|
||||
</method>
|
||||
</interface>
|
||||
<class name="MutableContextWrapper"
|
||||
extends="android.content.ContextWrapper"
|
||||
abstract="false"
|
||||
|
||||
188
core/java/android/app/LoaderManagingFragment.java
Normal file
188
core/java/android/app/LoaderManagingFragment.java
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app;
|
||||
|
||||
import android.content.Loader;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* A Fragment that has utility methods for managing {@link Loader}s.
|
||||
*
|
||||
* @param <D> The type of data returned by the Loader. If you're using multiple Loaders with
|
||||
* different return types use Object and case the results.
|
||||
*/
|
||||
public abstract class LoaderManagingFragment<D> extends Fragment
|
||||
implements Loader.OnLoadCompleteListener<D> {
|
||||
private boolean mStarted = false;
|
||||
|
||||
static final class LoaderInfo<D> {
|
||||
public Bundle args;
|
||||
public Loader<D> loader;
|
||||
}
|
||||
private HashMap<Integer, LoaderInfo<D>> mLoaders;
|
||||
private HashMap<Integer, LoaderInfo<D>> mInactiveLoaders;
|
||||
|
||||
/**
|
||||
* Registers a loader with this activity, registers the callbacks on it, and starts it loading.
|
||||
* If a loader with the same id has previously been started it will automatically be destroyed
|
||||
* when the new loader completes it's work. The callback will be delivered before the old loader
|
||||
* is destroyed.
|
||||
*/
|
||||
protected Loader<D> startLoading(int id, Bundle args) {
|
||||
LoaderInfo<D> info = mLoaders.get(id);
|
||||
if (info != null) {
|
||||
// Keep track of the previous instance of this loader so we can destroy
|
||||
// it when the new one completes.
|
||||
mInactiveLoaders.put(id, info);
|
||||
}
|
||||
info = new LoaderInfo<D>();
|
||||
info.args = args;
|
||||
mLoaders.put(id, info);
|
||||
Loader<D> loader = onCreateLoader(id, args);
|
||||
info.loader = loader;
|
||||
if (mStarted) {
|
||||
// The activity will start all existing loaders in it's onStart(), so only start them
|
||||
// here if we're past that point of the activitiy's life cycle
|
||||
loader.registerListener(id, this);
|
||||
loader.startLoading();
|
||||
}
|
||||
return loader;
|
||||
}
|
||||
|
||||
protected abstract Loader<D> onCreateLoader(int id, Bundle args);
|
||||
protected abstract void onInitializeLoaders();
|
||||
protected abstract void onLoadFinished(Loader<D> loader, D data);
|
||||
|
||||
public final void onLoadComplete(Loader<D> loader, D data) {
|
||||
// Notify of the new data so the app can switch out the old data before
|
||||
// we try to destroy it.
|
||||
onLoadFinished(loader, data);
|
||||
|
||||
// Look for an inactive loader and destroy it if found
|
||||
int id = loader.getId();
|
||||
LoaderInfo<D> info = mInactiveLoaders.get(id);
|
||||
if (info != null) {
|
||||
Loader<D> oldLoader = info.loader;
|
||||
if (oldLoader != null) {
|
||||
oldLoader.destroy();
|
||||
}
|
||||
mInactiveLoaders.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedState) {
|
||||
super.onCreate(savedState);
|
||||
|
||||
if (mLoaders == null) {
|
||||
// Look for a passed along loader and create a new one if it's not there
|
||||
// TODO: uncomment once getLastNonConfigurationInstance method is available
|
||||
// mLoaders = (HashMap<Integer, LoaderInfo>) getLastNonConfigurationInstance();
|
||||
if (mLoaders == null) {
|
||||
mLoaders = new HashMap<Integer, LoaderInfo<D>>();
|
||||
onInitializeLoaders();
|
||||
}
|
||||
}
|
||||
if (mInactiveLoaders == null) {
|
||||
mInactiveLoaders = new HashMap<Integer, LoaderInfo<D>>();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
// Call out to sub classes so they can start their loaders
|
||||
// Let the existing loaders know that we want to be notified when a load is complete
|
||||
for (HashMap.Entry<Integer, LoaderInfo<D>> entry : mLoaders.entrySet()) {
|
||||
LoaderInfo<D> info = entry.getValue();
|
||||
Loader<D> loader = info.loader;
|
||||
int id = entry.getKey();
|
||||
if (loader == null) {
|
||||
loader = onCreateLoader(id, info.args);
|
||||
info.loader = loader;
|
||||
}
|
||||
loader.registerListener(id, this);
|
||||
loader.startLoading();
|
||||
}
|
||||
|
||||
mStarted = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
|
||||
for (HashMap.Entry<Integer, LoaderInfo<D>> entry : mLoaders.entrySet()) {
|
||||
LoaderInfo<D> info = entry.getValue();
|
||||
Loader<D> loader = info.loader;
|
||||
if (loader == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Let the loader know we're done with it
|
||||
loader.unregisterListener(this);
|
||||
|
||||
// The loader isn't getting passed along to the next instance so ask it to stop loading
|
||||
if (!getActivity().isChangingConfigurations()) {
|
||||
loader.stopLoading();
|
||||
}
|
||||
}
|
||||
|
||||
mStarted = false;
|
||||
}
|
||||
|
||||
/** TO DO: This needs to be turned into a retained fragment.
|
||||
@Override
|
||||
public Object onRetainNonConfigurationInstance() {
|
||||
// Pass the loader along to the next guy
|
||||
Object result = mLoaders;
|
||||
mLoaders = null;
|
||||
return result;
|
||||
}
|
||||
**/
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
if (mLoaders != null) {
|
||||
for (HashMap.Entry<Integer, LoaderInfo<D>> entry : mLoaders.entrySet()) {
|
||||
LoaderInfo<D> info = entry.getValue();
|
||||
Loader<D> loader = info.loader;
|
||||
if (loader == null) {
|
||||
continue;
|
||||
}
|
||||
loader.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Loader with the given id or null if no matching Loader
|
||||
* is found.
|
||||
*/
|
||||
public Loader<D> getLoader(int id) {
|
||||
LoaderInfo<D> loaderInfo = mLoaders.get(id);
|
||||
if (loaderInfo != null) {
|
||||
return mLoaders.get(id).loader;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
86
core/java/android/content/AsyncTaskLoader.java
Normal file
86
core/java/android/content/AsyncTaskLoader.java
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.content;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
/**
|
||||
* Abstract Loader that provides an {@link AsyncTask} to do the work.
|
||||
*
|
||||
* @param <D> the data type to be loaded.
|
||||
*/
|
||||
public abstract class AsyncTaskLoader<D> extends Loader<D> {
|
||||
final class LoadTask extends AsyncTask<Void, Void, D> {
|
||||
/* Runs on a worker thread */
|
||||
@Override
|
||||
protected D doInBackground(Void... params) {
|
||||
return AsyncTaskLoader.this.loadInBackground();
|
||||
}
|
||||
|
||||
/* Runs on the UI thread */
|
||||
@Override
|
||||
protected void onPostExecute(D data) {
|
||||
AsyncTaskLoader.this.dispatchOnLoadComplete(data);
|
||||
}
|
||||
}
|
||||
|
||||
LoadTask mTask;
|
||||
|
||||
public AsyncTaskLoader(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force an asynchronous load. Unlike {@link #startLoading()} this will ignore a previously
|
||||
* loaded data set and load a new one.
|
||||
*/
|
||||
@Override
|
||||
public void forceLoad() {
|
||||
mTask = new LoadTask();
|
||||
mTask.execute((Void[]) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to cancel the current load task. See {@link AsyncTask#cancel(boolean)}
|
||||
* for more info.
|
||||
*
|
||||
* @return <tt>false</tt> if the task could not be canceled,
|
||||
* typically because it has already completed normally, or
|
||||
* because {@link #startLoading()} hasn't been called, and
|
||||
* <tt>true</tt> otherwise
|
||||
*/
|
||||
public boolean cancelLoad() {
|
||||
if (mTask != null) {
|
||||
return mTask.cancel(false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void dispatchOnLoadComplete(D data) {
|
||||
mTask = null;
|
||||
deliverResult(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on a worker thread to perform the actual load. Implementations should not deliver the
|
||||
* results directly, but should return them from this method and deliver them from
|
||||
* {@link #onPostExecute()}
|
||||
*
|
||||
* @return the result of the load
|
||||
*/
|
||||
public abstract D loadInBackground();
|
||||
}
|
||||
151
core/java/android/content/CursorLoader.java
Normal file
151
core/java/android/content/CursorLoader.java
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.content;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
/**
|
||||
* A loader that queries the {@link ContentResolver} and returns a {@link Cursor}.
|
||||
*/
|
||||
public class CursorLoader extends AsyncTaskLoader<Cursor> {
|
||||
Cursor mCursor;
|
||||
ForceLoadContentObserver mObserver;
|
||||
boolean mStopped;
|
||||
Uri mUri;
|
||||
String[] mProjection;
|
||||
String mSelection;
|
||||
String[] mSelectionArgs;
|
||||
String mSortOrder;
|
||||
|
||||
/* Runs on a worker thread */
|
||||
@Override
|
||||
public Cursor loadInBackground() {
|
||||
Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
|
||||
mSelectionArgs, mSortOrder);
|
||||
// Ensure the cursor window is filled
|
||||
if (cursor != null) {
|
||||
cursor.getCount();
|
||||
cursor.registerContentObserver(mObserver);
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
|
||||
/* Runs on the UI thread */
|
||||
@Override
|
||||
public void deliverResult(Cursor cursor) {
|
||||
if (mStopped) {
|
||||
// An async query came in while the loader is stopped
|
||||
cursor.close();
|
||||
return;
|
||||
}
|
||||
mCursor = cursor;
|
||||
super.deliverResult(cursor);
|
||||
}
|
||||
|
||||
public CursorLoader(Context context, Uri uri, String[] projection, String selection,
|
||||
String[] selectionArgs, String sortOrder) {
|
||||
super(context);
|
||||
mObserver = new ForceLoadContentObserver();
|
||||
mUri = uri;
|
||||
mProjection = projection;
|
||||
mSelection = selection;
|
||||
mSelectionArgs = selectionArgs;
|
||||
mSortOrder = sortOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts an asynchronous load of the contacts list data. When the result is ready the callbacks
|
||||
* will be called on the UI thread. If a previous load has been completed and is still valid
|
||||
* the result may be passed to the callbacks immediately.
|
||||
*
|
||||
* Must be called from the UI thread
|
||||
*/
|
||||
@Override
|
||||
public void startLoading() {
|
||||
mStopped = false;
|
||||
|
||||
if (mCursor != null) {
|
||||
deliverResult(mCursor);
|
||||
} else {
|
||||
forceLoad();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be called from the UI thread
|
||||
*/
|
||||
@Override
|
||||
public void stopLoading() {
|
||||
if (mCursor != null && !mCursor.isClosed()) {
|
||||
mCursor.close();
|
||||
mCursor = null;
|
||||
}
|
||||
|
||||
// Attempt to cancel the current load task if possible.
|
||||
cancelLoad();
|
||||
|
||||
// Make sure that any outstanding loads clean themselves up properly
|
||||
mStopped = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
// Ensure the loader is stopped
|
||||
stopLoading();
|
||||
}
|
||||
|
||||
public Uri getUri() {
|
||||
return mUri;
|
||||
}
|
||||
|
||||
public void setUri(Uri uri) {
|
||||
mUri = uri;
|
||||
}
|
||||
|
||||
public String[] getProjection() {
|
||||
return mProjection;
|
||||
}
|
||||
|
||||
public void setProjection(String[] projection) {
|
||||
mProjection = projection;
|
||||
}
|
||||
|
||||
public String getSelection() {
|
||||
return mSelection;
|
||||
}
|
||||
|
||||
public void setSelection(String selection) {
|
||||
mSelection = selection;
|
||||
}
|
||||
|
||||
public String[] getSelectionArgs() {
|
||||
return mSelectionArgs;
|
||||
}
|
||||
|
||||
public void setSelectionArgs(String[] selectionArgs) {
|
||||
mSelectionArgs = selectionArgs;
|
||||
}
|
||||
|
||||
public String getSortOrder() {
|
||||
return mSortOrder;
|
||||
}
|
||||
|
||||
public void setSortOrder(String sortOrder) {
|
||||
mSortOrder = sortOrder;
|
||||
}
|
||||
}
|
||||
154
core/java/android/content/Loader.java
Normal file
154
core/java/android/content/Loader.java
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.content;
|
||||
|
||||
import android.database.ContentObserver;
|
||||
import android.os.Handler;
|
||||
|
||||
/**
|
||||
* An abstract class that performs asynchronous loading of data. While Loaders are active
|
||||
* they should monitor the source of their data and deliver new results when the contents
|
||||
* change.
|
||||
*
|
||||
* @param <D> The result returned when the load is complete
|
||||
*/
|
||||
public abstract class Loader<D> {
|
||||
int mId;
|
||||
OnLoadCompleteListener<D> mListener;
|
||||
Context mContext;
|
||||
|
||||
public final class ForceLoadContentObserver extends ContentObserver {
|
||||
public ForceLoadContentObserver() {
|
||||
super(new Handler());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deliverSelfNotifications() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
forceLoad();
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnLoadCompleteListener<D> {
|
||||
/**
|
||||
* Called on the thread that created the Loader when the load is complete.
|
||||
*
|
||||
* @param loader the loader that completed the load
|
||||
* @param data the result of the load
|
||||
*/
|
||||
public void onLoadComplete(Loader<D> loader, D data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores away the application context associated with context. Since Loaders can be used
|
||||
* across multiple activities it's dangerous to store the context directly.
|
||||
*
|
||||
* @param context used to retrieve the application context.
|
||||
*/
|
||||
public Loader(Context context) {
|
||||
mContext = context.getApplicationContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the result of the load to the registered listener. Should only be called by subclasses.
|
||||
*
|
||||
* Must be called from the UI thread.
|
||||
*
|
||||
* @param data the result of the load
|
||||
*/
|
||||
public void deliverResult(D data) {
|
||||
if (mListener != null) {
|
||||
mListener.onLoadComplete(this, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an application context retrieved from the Context passed to the constructor.
|
||||
*/
|
||||
public Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the ID of this loader
|
||||
*/
|
||||
public int getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a class that will receive callbacks when a load is complete. The callbacks will
|
||||
* be called on the UI thread so it's safe to pass the results to widgets.
|
||||
*
|
||||
* Must be called from the UI thread
|
||||
*/
|
||||
public void registerListener(int id, OnLoadCompleteListener<D> listener) {
|
||||
if (mListener != null) {
|
||||
throw new IllegalStateException("There is already a listener registered");
|
||||
}
|
||||
mListener = listener;
|
||||
mId = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be called from the UI thread
|
||||
*/
|
||||
public void unregisterListener(OnLoadCompleteListener<D> listener) {
|
||||
if (mListener == null) {
|
||||
throw new IllegalStateException("No listener register");
|
||||
}
|
||||
if (mListener != listener) {
|
||||
throw new IllegalArgumentException("Attempting to unregister the wrong listener");
|
||||
}
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts an asynchronous load of the contacts list data. When the result is ready the callbacks
|
||||
* will be called on the UI thread. If a previous load has been completed and is still valid
|
||||
* the result may be passed to the callbacks immediately. The loader will monitor the source of
|
||||
* the data set and may deliver future callbacks if the source changes. Calling
|
||||
* {@link #stopLoading} will stop the delivery of callbacks.
|
||||
*
|
||||
* Must be called from the UI thread
|
||||
*/
|
||||
public abstract void startLoading();
|
||||
|
||||
/**
|
||||
* Force an asynchronous load. Unlike {@link #startLoading()} this will ignore a previously
|
||||
* loaded data set and load a new one.
|
||||
*/
|
||||
public abstract void forceLoad();
|
||||
|
||||
/**
|
||||
* Stops delivery of updates until the next time {@link #startLoading()} is called
|
||||
*
|
||||
* Must be called from the UI thread
|
||||
*/
|
||||
public abstract void stopLoading();
|
||||
|
||||
/**
|
||||
* Destroys the loader and frees its resources, making it unusable.
|
||||
*
|
||||
* Must be called from the UI thread
|
||||
*/
|
||||
public abstract void destroy();
|
||||
}
|
||||
Reference in New Issue
Block a user