LoaderManager的使用(以加载系统app为例)

在要监听查看数据的地方实现LoaderManager.LoaderCallbacks<List<XXXX>>(XXXX为适配器对象)

/**
	 * This ListFragment displays a list of all installed applications on the
	 * device as its sole content. It uses an {@link AppListLoader} to load its
	 * data and the LoaderManager to manage the loader across the activity and
	 * fragment life cycles.
	 */
	public static class AppListFragment extends ListFragment implements
			LoaderManager.LoaderCallbacks<List<AppEntry>> {
		private static final String TAG = "ADP_AppListFragment";
		private static final boolean DEBUG = true;

		// We use a custom ArrayAdapter to bind application info to the
		// ListView.
		private AppListAdapter mAdapter;

		// The Loader's id (this id is specific to the ListFragment's
		// LoaderManager)
		private static final int LOADER_ID = 1;

		@Override
		public void onActivityCreated(Bundle savedInstanceState) {
			super.onActivityCreated(savedInstanceState);
			setHasOptionsMenu(true);

			mAdapter = new AppListAdapter(getActivity());
			setEmptyText("No applications");
			setListAdapter(mAdapter);
			setListShown(false);

			if (DEBUG) {
				Log.i(TAG, "+++ Calling initLoader()! +++");
				if (getLoaderManager().getLoader(LOADER_ID) == null) {
					Log.i(TAG, "+++ Initializing the new Loader... +++");
				} else {
					Log.i(TAG,
							"+++ Reconnecting with existing Loader (id '1')... +++");
				}
			}

			// Initialize a Loader with id '1'. If the Loader with this id
			// already
			// exists, then the LoaderManager will reuse the existing Loader.
			getLoaderManager().initLoader(LOADER_ID, null, this);
		}

		/**********************/
		/** LOADER CALLBACKS **/
		/**********************/

		@Override
		public Loader<List<AppEntry>> onCreateLoader(int id, Bundle args) {
			if (DEBUG)
				Log.i(TAG, "+++ onCreateLoader() called! +++");
			return new AppListLoader(getActivity());
		}

		@Override
		public void onLoadFinished(Loader<List<AppEntry>> loader,
				List<AppEntry> data) {
			if (DEBUG)
				Log.i(TAG, "+++ onLoadFinished() called! +++");
			mAdapter.setData(data);

			if (isResumed()) {
				setListShown(true);
			} else {
				setListShownNoAnimation(true);
			}
		}

		@Override
		public void onLoaderReset(Loader<List<AppEntry>> loader) {
			if (DEBUG)
				Log.i(TAG, "+++ onLoadReset() called! +++");
			mAdapter.setData(null);
		}

		/**********************/
		/** CONFIGURE LOCALE **/
		/**********************/

		@Override
		public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
			inflater.inflate(R.menu.activity_main, menu);
		}

		@Override
		public boolean onOptionsItemSelected(MenuItem item) {
			switch (item.getItemId()) {
			case R.id.menu_configure_locale:
				configureLocale();
				return true;
			}
			return false;
		}

		/**
		 * Notifies the Loader that a configuration change has has occurred
		 * (i.e. by calling {@link Loader#onContentChanged()}).
		 * 
		 * This feature was added so that it would be easy to see the sequence
		 * of events that occurs when a content change is detected. Connect your
		 * device via USB and analyze the logcat to see the sequence of methods
		 * that are called as a result!
		 */
		private void configureLocale() {
			Loader<AppEntry> loader = getLoaderManager().getLoader(LOADER_ID);
			if (loader != null) {
				startActivity(new Intent(Settings.ACTION_LOCALE_SETTINGS));
			}
		}
	}

实现AsyncTaskLoader类:

/**
 * An implementation of AsyncTaskLoader which loads a {@code List<AppEntry>}
 * containing all installed applications on the device.
 */
public class AppListLoader extends AsyncTaskLoader<List<AppEntry>> {
	private static final String TAG = "ADP_AppListLoader";
	private static final boolean DEBUG = true;

	final PackageManager mPm;

	// We hold a reference to the Loader's data here.
	private List<AppEntry> mApps;

	public AppListLoader(Context ctx) {
		// Loaders may be used across multiple Activitys (assuming they aren't
		// bound to the LoaderManager), so NEVER hold a reference to the context
		// directly. Doing so will cause you to leak an entire Activity's
		// context.
		// The superclass constructor will store a reference to the Application
		// Context instead, and can be retrieved with a call to getContext().
		super(ctx);
		mPm = getContext().getPackageManager();
	}

	/****************************************************/
	/** (1) A task that performs the asynchronous load **/
	/****************************************************/

	/**
	 * This method is called on a background thread and generates a List of
	 * {@link AppEntry} objects. Each entry corresponds to a single installed
	 * application on the device.
	 */
	@Override
	public List<AppEntry> loadInBackground() {
		if (DEBUG)
			Log.i(TAG, "+++ loadInBackground() called! +++");

		// Retrieve all installed applications.
		List<ApplicationInfo> apps = mPm.getInstalledApplications(0);

		if (apps == null) {
			apps = new ArrayList<ApplicationInfo>();
		}

		// Create corresponding array of entries and load their labels.
		List<AppEntry> entries = new ArrayList<AppEntry>(apps.size());
		for (int i = 0; i < apps.size(); i++) {
			AppEntry entry = new AppEntry(this, apps.get(i));
			entry.loadLabel(getContext());
			entries.add(entry);
		}

		// Sort the list.
		Collections.sort(entries, ALPHA_COMPARATOR);

		return entries;
	}

	/*******************************************/
	/** (2) Deliver the results to the client **/
	/*******************************************/

	/**
	 * Called when there is new data to deliver to the client. The superclass
	 * will deliver it to the registered listener (i.e. the LoaderManager),
	 * which will forward the results to the client through a call to
	 * onLoadFinished.
	 */
	@Override
	public void deliverResult(List<AppEntry> apps) {
		if (isReset()) {
			if (DEBUG)
				Log.w(TAG,
						"+++ Warning! An async query came in while the Loader was reset! +++");
			// The Loader has been reset; ignore the result and invalidate the
			// data.
			// This can happen when the Loader is reset while an asynchronous
			// query
			// is working in the background. That is, when the background thread
			// finishes its work and attempts to deliver the results to the
			// client,
			// it will see here that the Loader has been reset and discard any
			// resources associated with the new data as necessary.
			if (apps != null) {
				releaseResources(apps);
				return;
			}
		}

		// Hold a reference to the old data so it doesn't get garbage collected.
		// We must protect it until the new data has been delivered.
		List<AppEntry> oldApps = mApps;
		mApps = apps;

		if (isStarted()) {
			if (DEBUG)
				Log.i(TAG, "+++ Delivering results to the LoaderManager for"
						+ " the ListFragment to display! +++");
			// If the Loader is in a started state, have the superclass deliver
			// the
			// results to the client.
			super.deliverResult(apps);
		}

		// Invalidate the old data as we don't need it any more.
		if (oldApps != null && oldApps != apps) {
			if (DEBUG)
				Log.i(TAG,
						"+++ Releasing any old data associated with this Loader. +++");
			releaseResources(oldApps);
		}
	}

	/*********************************************************/
	/** (3) Implement the Loader锟絪 state-dependent behavior **/
	/*********************************************************/

	@Override
	protected void onStartLoading() {
		if (DEBUG)
			Log.i(TAG, "+++ onStartLoading() called! +++");

		if (mApps != null) {
			// Deliver any previously loaded data immediately.
			if (DEBUG)
				Log.i(TAG,
						"+++ Delivering previously loaded data to the client...");
			deliverResult(mApps);
		}

		// Register the observers that will notify the Loader when changes are
		// made.
		if (mAppsObserver == null) {
			mAppsObserver = new InstalledAppsObserver(this);
		}

		if (mLocaleObserver == null) {
			mLocaleObserver = new SystemLocaleObserver(this);
		}

		if (takeContentChanged()) {
			// When the observer detects a new installed application, it will
			// call
			// onContentChanged() on the Loader, which will cause the next call
			// to
			// takeContentChanged() to return true. If this is ever the case (or
			// if
			// the current data is null), we force a new load.
			if (DEBUG)
				Log.i(TAG,
						"+++ A content change has been detected... so force load! +++");
			forceLoad();
		} else if (mApps == null) {
			// If the current data is null... then we should make it non-null!
			// :)
			if (DEBUG)
				Log.i(TAG,
						"+++ The current data is data is null... so force load! +++");
			forceLoad();
		}
	}

	@Override
	protected void onStopLoading() {
		if (DEBUG)
			Log.i(TAG, "+++ onStopLoading() called! +++");

		// The Loader has been put in a stopped state, so we should attempt to
		// cancel the current load (if there is one).
		cancelLoad();

		// Note that we leave the observer as is; Loaders in a stopped state
		// should still monitor the data source for changes so that the Loader
		// will know to force a new load if it is ever started again.
	}

	@Override
	protected void onReset() {
		if (DEBUG)
			Log.i(TAG, "+++ onReset() called! +++");

		// Ensure the loader is stopped.
		onStopLoading();

		// At this point we can release the resources associated with 'apps'.
		if (mApps != null) {
			releaseResources(mApps);
			mApps = null;
		}

		// The Loader is being reset, so we should stop monitoring for changes.
		if (mAppsObserver != null) {
			getContext().unregisterReceiver(mAppsObserver);
			mAppsObserver = null;
		}

		if (mLocaleObserver != null) {
			getContext().unregisterReceiver(mLocaleObserver);
			mLocaleObserver = null;
		}
	}

	@Override
	public void onCanceled(List<AppEntry> apps) {
		if (DEBUG)
			Log.i(TAG, "+++ onCanceled() called! +++");

		// Attempt to cancel the current asynchronous load.
		super.onCanceled(apps);

		// The load has been canceled, so we should release the resources
		// associated with 'mApps'.
		releaseResources(apps);
	}

	@Override
	public void forceLoad() {
		if (DEBUG)
			Log.i(TAG, "+++ forceLoad() called! +++");
		super.forceLoad();
	}

	/**
	 * Helper method to take care of releasing resources associated with an
	 * actively loaded data set.
	 */
	private void releaseResources(List<AppEntry> apps) {
		// For a simple List, there is nothing to do. For something like a
		// Cursor,
		// we would close it in this method. All resources associated with the
		// Loader should be released here.
	}

	/*********************************************************************/
	/** (4) Observer which receives notifications when the data changes **/
	/*********************************************************************/

	// An observer to notify the Loader when new apps are installed/updated.
	private InstalledAppsObserver mAppsObserver;

	// The observer to notify the Loader when the system Locale has been
	// changed.
	private SystemLocaleObserver mLocaleObserver;

	/**************************/
	/** (5) Everything else! **/
	/**************************/

	/**
	 * Performs alphabetical comparison of {@link AppEntry} objects. This is
	 * used to sort queried data in {@link loadInBackground}.
	 */
	private static final Comparator<AppEntry> ALPHA_COMPARATOR = new Comparator<AppEntry>() {
		Collator sCollator = Collator.getInstance();

		@Override
		public int compare(AppEntry object1, AppEntry object2) {
			return sCollator.compare(object1.getLabel(), object2.getLabel());
		}
	};
}


你可能感兴趣的:(LoaderManager的使用(以加载系统app为例))