1. Loaders
loaders make it easy to asynchronously load data in an activity or fragment. Loaders have these characteristics:
<1>They are available to every Activity
and Fragment
.
<2>They provide asynchronous loading of data
<3>They monitor the source of their data and deliver new results when the content changes
<4>They automatically reconnect to the last loader's cursor when being recreated after a configuration change. Thus, they don't need to
re-query their data
2. Using Loaders in an appliction
An application that uses loaders typically includes the following:
<1> An Activity
or Fragment
.
<2> An instance of the LoaderManager
.
<3> A CursorLoader
to load data backed by a ContentProvider
.
Alternatively, you can implement your own subclass of Loader
or AsyncTaskLoader
to load data from some other source.
<4> An implementation for LoaderManager.LoaderCallbacks
.
This is where you create new loaders and manage your references to existing loaders.
<5> A way of displaying the loader's data, such as a SimpleCursorAdapter
.
<6> A data source, such as a ContentProvider
, when using a CursorLoader
.
3. Starting a Loader
The LoaderManager
manages one or more Loader
instances within an Activity
or Fragment
. There is only one LoaderManager
per activity or fragment.
You typically initialize a Loader
within the activity's onCreate()
method, or within the fragment's onActivityCreated()
method. You do this as follows:
// Prepare the loader. Either re-connect with an existing one,// or start a new one.getLoaderManager().initLoader(0, null, this);
4.Restart a Loader
When you use initLoader()
, as shown above, it uses an existing loader with the specified ID if there is one. If there isn't, it creates one. But
sometimes you want to discard your old data and start over.
To discard your old data, you use restartLoader()
. For example, this implementation of SearchView.OnQueryTextListener
restarts the loader when
the user's query changes. The loader needs to be restarted so that it can use the revised search filter to do a new query:
public boolean onQueryTextChanged(String newText) { // Called when the action bar search text has changed. Update // the search filter, and restart the loader to do a new query // with this filter. mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; getLoaderManager().restartLoader(0, null, this); return true;}
5. Using the LoaderManager Callbacks
LoaderManager.LoaderCallbacks
is a callback interface that lets a client interact with the LoaderManager
.
Loaders, in particular CursorLoader
, are expected to retain their data after being stopped.
This allows applications to keep their data across the activity or fragment's onStop()
and onStart()
methods, so that when users return to an
application, they don't have to wait for the data to reload. You use the LoaderManager.LoaderCallbacks
methods when to know when to create
a new loader, and to tell the application when it is time to stop using a loader's data.
5.1 onCreateLoader
When you attempt to access a loader (for example, through initLoader()
), it checks to see whether the loader specified by the ID exists.
If it doesn't, it triggers the LoaderManager.LoaderCallbacks
method onCreateLoader()
. This is where you create a new loader. Typically this
will be a CursorLoader
, but you can implement your own Loader
subclass.
5.2 onLoadFinished
This method is called when a previously created loader has finished its load. This method is guaranteed to be called prior to the release of
the last data that was supplied for this loader. At this point you should remove all use of the old data (since it will be released soon),
but should not do your own release of the data since its loader owns it and will take care of that.
5.3 onLoaderReset
This method is called when a previously created loader is being reset, thus making its data unavailable. This callback lets you find out
when the data is about to be released so you can remove your reference to it.
6. Example
As an example, here is the full implementation of a Fragment
that displays a ListView
containing the results of a query against the contacts
content provider. It uses a CursorLoader
to manage the query on the provider.
For an application to access a user's contacts, as shown in this example, its manifest must include the permission READ_CONTACTS
.
//activity_main.xml
//MainActivitypackage mirror.android.loader_test;import android.app.Activity;import android.os.Bundle;public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }}
//CursorLoaderListFragment.javapackage mirror.android.loader_test;import android.app.ListFragment;import android.app.LoaderManager.LoaderCallbacks;import android.content.CursorLoader;import android.content.Loader;import android.database.Cursor;import android.net.Uri;import android.os.Bundle;import android.provider.ContactsContract.Contacts;import android.text.TextUtils;import android.view.Menu;import android.view.MenuInflater;import android.view.MenuItem;import android.view.View;import android.widget.ListView;import android.widget.SearchView;import android.widget.SimpleCursorAdapter;import android.widget.Toast;import android.widget.SearchView.OnQueryTextListener;/* * 实现LoaderManager.LoaderCallbacks接口,用于与Loader的交互 * 官方文档: A callback interface for a client to interact with the LoaderManager. * For example, you use the onCreateLoader() callback method to create a new loader. */ public class CursorLoaderListFragment extends ListFragment implements OnQueryTextListener, LoaderCallbacks{ // 显示联系人 // This is the Adapter being used to display the list's data. SimpleCursorAdapter mAdapter; // 判断 手机联系人列表 是否有符合 搜索框内搜索人名字的 // If non-null, this is the current filter the user has provided. String mCurFilter; @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); //当List为空时可以看到这个文字 setEmptyText("No phone numbers"); // We have a menu item to show in action bar. setHasOptionsMenu(true); // Create an empty adapter we will use to display the loaded data. mAdapter = new SimpleCursorAdapter(getActivity() ,android.R.layout.simple_list_item_2 ,null ,new String[] {Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS} ,new int[] {android.R.id.text1, android.R.id.text2} ,0); setListAdapter(mAdapter); // Prepare the loader. Either re-connect with an existing one, or start a new one. // You typically initialize a Loader within the activity's onCreate() method, // or within the fragment's onActivityCreated() method. getLoaderManager().initLoader(0, null,this); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { // TODO Auto-generated method stub MenuItem item = menu.add("Search"); item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); //A widget that provides a user interface for the user to enter a search query and submit a request //to a search provider. Shows a list of query suggestions or results, if available, and allows the //user to pick a suggestion or result to launch into. //加上搜索框 SearchView sv = new SearchView(getActivity()); //搜索框监听文字输入 sv.setOnQueryTextListener(this); item.setActionView(sv); } @Override public boolean onQueryTextSubmit(String query) { return true; } @Override public boolean onQueryTextChange(String newText) { // Called when the action bar search text has changed. Update // the search filter, and restart the loader to do a new query // with this filter. // 输入后List会根据输入自动匹配新的List, 所以需要restart a new Loader mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; getLoaderManager().restartLoader(0, null, this); return true; } @Override public void onListItemClick(ListView l, View v, int position, long id) { Toast.makeText(getActivity(), "Item clicked: " + id, Toast.LENGTH_SHORT).show(); } // These are the Contacts rows that we will retrieve. static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] { Contacts._ID, Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS, Contacts.CONTACT_PRESENCE, Contacts.PHOTO_ID, Contacts.LOOKUP_KEY, }; @Override public Loader onCreateLoader(int id, Bundle args) { // This is called when a new Loader needs to be created. This // sample only has one Loader, so we don't care about the ID. // First, pick the base URI to use depending on whether we are // currently filtering. Uri baseUri; if (mCurFilter != null) { baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(mCurFilter)); } else { baseUri = Contacts.CONTENT_URI; } // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" + Contacts.HAS_PHONE_NUMBER + "=1) AND (" + Contacts.DISPLAY_NAME + " != '' ))"; return new CursorLoader(getActivity(), baseUri, CONTACTS_SUMMARY_PROJECTION, select, null, Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); } @Override public void onLoaderReset(Loader loader) { // This is called when the last Cursor provided to onLoadFinished() // above is about to be closed. We need to make sure we are no // longer using it. // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) mAdapter.swapCursor(null); } @Override public void onLoadFinished(Loader loader, Cursor data) { mAdapter.swapCursor(data); }}
run
click the icon in the Right-up decrection , will can search the Contacts
Type A, it will restart loader automatically
Besides, press Home_Key to add a contract in the contact list, then go back to this appliction,it will aumatically add a contract to the list