Android Loader机制
生活随笔
收集整理的這篇文章主要介紹了
Android Loader机制
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Android應用Loaders全面詳解及源碼淺析
加載器
LoaderCursor
public class LoaderCursor extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);FragmentManager fm = getFragmentManager();// Create the list fragment and add it as our sole content.if (fm.findFragmentById(android.R.id.content) == null) {CursorLoaderListFragment list = new CursorLoaderListFragment();fm.beginTransaction().add(android.R.id.content, list).commit();}}public static class CursorLoaderListFragment extends ListFragmentimplements OnQueryTextListener, OnCloseListener,LoaderManager.LoaderCallbacks<Cursor> {// This is the Adapter being used to display the list's data.SimpleCursorAdapter mAdapter;// The SearchView for doing filtering.SearchView mSearchView;// If non-null, this is the current filter the user has provided.String mCurFilter;@Override public void onActivityCreated(Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);// Give some text to display if there is no data. In a real// application this would come from a resource.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);// Start out with a progress indicator.setListShown(false);// Prepare the loader. Either re-connect with an existing one,// or start a new one.getLoaderManager().initLoader(0, null, this);}public static class MySearchView extends SearchView {public MySearchView(Context context) {super(context);}// The normal SearchView doesn't clear its search text when// collapsed, so we will do this for it.@Overridepublic void onActionViewCollapsed() {setQuery("", false);super.onActionViewCollapsed();}}@Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {// Place an action bar item for searching.MenuItem item = menu.add("Search");item.setIcon(android.R.drawable.ic_menu_search);item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM| MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);mSearchView = new MySearchView(getActivity());mSearchView.setOnQueryTextListener(this);mSearchView.setOnCloseListener(this);mSearchView.setIconifiedByDefault(true);item.setActionView(mSearchView);}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.String newFilter = !TextUtils.isEmpty(newText) ? newText : null;// Don't do anything if the filter hasn't actually changed.// Prevents restarting the loader when restoring state.if (mCurFilter == null && newFilter == null) {return true;}if (mCurFilter != null && mCurFilter.equals(newFilter)) {return true;}mCurFilter = newFilter;getLoaderManager().restartLoader(0, null, this);return true;}@Override public boolean onQueryTextSubmit(String query) {// Don't care about this.return true;}@Overridepublic boolean onClose() {if (!TextUtils.isEmpty(mSearchView.getQuery())) {mSearchView.setQuery(null, true);}return true;}@Override public void onListItemClick(ListView l, View v, int position, long id) {// Insert desired behavior here.Log.i("FragmentComplexList", "Item clicked: " + id);}// 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,};public Loader<Cursor> 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");}public void onLoadFinished(Loader<Cursor> loader, Cursor data) {// Swap the new cursor in. (The framework will take care of closing the// old cursor once we return.)mAdapter.swapCursor(data);// The list should now be shown.if (isResumed()) {setListShown(true);} else {setListShownNoAnimation(true);}}public void onLoaderReset(Loader<Cursor> 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.mAdapter.swapCursor(null);}}}LoaderThrottle
public class LoaderThrottle extends Activity {// Debugging.static final String TAG = "LoaderThrottle";/*** The authority we use to get to our sample provider.*/public static final String AUTHORITY = "com.example.android.apis.app.LoaderThrottle";/*** Definition of the contract for the main table of our provider.*/public static final class MainTable implements BaseColumns {// This class cannot be instantiatedprivate MainTable() {}/*** The table name offered by this provider*/public static final String TABLE_NAME = "main";/*** The content:// style URL for this table*/public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/main");/*** The content URI base for a single row of data. Callers must* append a numeric row id to this Uri to retrieve a row*/public static final Uri CONTENT_ID_URI_BASE= Uri.parse("content://" + AUTHORITY + "/main/");/*** The MIME type of {@link #CONTENT_URI}.*/public static final String CONTENT_TYPE= "vnd.android.cursor.dir/vnd.example.api-demos-throttle";/*** The MIME type of a {@link #CONTENT_URI} sub-directory of a single row.*/public static final String CONTENT_ITEM_TYPE= "vnd.android.cursor.item/vnd.example.api-demos-throttle";/*** The default sort order for this table*/public static final String DEFAULT_SORT_ORDER = "data COLLATE LOCALIZED ASC";/*** Column name for the single column holding our data.* <P>Type: TEXT</P>*/public static final String COLUMN_NAME_DATA = "data";}/*** This class helps open, create, and upgrade the database file.*/static class DatabaseHelper extends SQLiteOpenHelper {private static final String DATABASE_NAME = "loader_throttle.db";private static final int DATABASE_VERSION = 2;DatabaseHelper(Context context) {// calls the super constructor, requesting the default cursor factory.super(context, DATABASE_NAME, null, DATABASE_VERSION);}/**** Creates the underlying database with table name and column names taken from the* NotePad class.*/@Overridepublic void onCreate(SQLiteDatabase db) {db.execSQL("CREATE TABLE " + MainTable.TABLE_NAME + " ("+ MainTable._ID + " INTEGER PRIMARY KEY,"+ MainTable.COLUMN_NAME_DATA + " TEXT"+ ");");}/**** Demonstrates that the provider must consider what happens when the* underlying datastore is changed. In this sample, the database is upgraded the database* by destroying the existing data.* A real application should upgrade the database in place.*/@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {// Logs that the database is being upgradedLog.w(TAG, "Upgrading database from version " + oldVersion + " to "+ newVersion + ", which will destroy all old data");// Kills the table and existing datadb.execSQL("DROP TABLE IF EXISTS notes");// Recreates the database with a new versiononCreate(db);}}/*** A very simple implementation of a content provider.*/public static class SimpleProvider extends ContentProvider {// A projection map used to select columns from the databaseprivate final HashMap<String, String> mNotesProjectionMap;// Uri matcher to decode incoming URIs.private final UriMatcher mUriMatcher;// The incoming URI matches the main table URI patternprivate static final int MAIN = 1;// The incoming URI matches the main table row ID URI patternprivate static final int MAIN_ID = 2;// Handle to a new DatabaseHelper.private DatabaseHelper mOpenHelper;/*** Global provider initialization.*/public SimpleProvider() {// Create and initialize URI matcher.mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);mUriMatcher.addURI(AUTHORITY, MainTable.TABLE_NAME, MAIN);mUriMatcher.addURI(AUTHORITY, MainTable.TABLE_NAME + "/#", MAIN_ID);// Create and initialize projection map for all columns. This is// simply an identity mapping.mNotesProjectionMap = new HashMap<String, String>();mNotesProjectionMap.put(MainTable._ID, MainTable._ID);mNotesProjectionMap.put(MainTable.COLUMN_NAME_DATA, MainTable.COLUMN_NAME_DATA);}/*** Perform provider creation.*/@Overridepublic boolean onCreate() {mOpenHelper = new DatabaseHelper(getContext());// Assumes that any failures will be reported by a thrown exception.return true;}/*** Handle incoming queries.*/@Overridepublic Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {// Constructs a new query builder and sets its table nameSQLiteQueryBuilder qb = new SQLiteQueryBuilder();qb.setTables(MainTable.TABLE_NAME);switch (mUriMatcher.match(uri)) {case MAIN:// If the incoming URI is for main table.qb.setProjectionMap(mNotesProjectionMap);break;case MAIN_ID:// The incoming URI is for a single row.qb.setProjectionMap(mNotesProjectionMap);qb.appendWhere(MainTable._ID + "=?");selectionArgs = DatabaseUtils.appendSelectionArgs(selectionArgs,new String[] { uri.getLastPathSegment() });break;default:throw new IllegalArgumentException("Unknown URI " + uri);}if (TextUtils.isEmpty(sortOrder)) {sortOrder = MainTable.DEFAULT_SORT_ORDER;}SQLiteDatabase db = mOpenHelper.getReadableDatabase();Cursor c = qb.query(db, projection, selection, selectionArgs,null /* no group */, null /* no filter */, sortOrder);c.setNotificationUri(getContext().getContentResolver(), uri);return c;}/*** Return the MIME type for an known URI in the provider.*/@Overridepublic String getType(Uri uri) {switch (mUriMatcher.match(uri)) {case MAIN:return MainTable.CONTENT_TYPE;case MAIN_ID:return MainTable.CONTENT_ITEM_TYPE;default:throw new IllegalArgumentException("Unknown URI " + uri);}}/*** Handler inserting new data.*/@Overridepublic Uri insert(Uri uri, ContentValues initialValues) {if (mUriMatcher.match(uri) != MAIN) {// Can only insert into to main URI.throw new IllegalArgumentException("Unknown URI " + uri);}ContentValues values;if (initialValues != null) {values = new ContentValues(initialValues);} else {values = new ContentValues();}if (values.containsKey(MainTable.COLUMN_NAME_DATA) == false) {values.put(MainTable.COLUMN_NAME_DATA, "");}SQLiteDatabase db = mOpenHelper.getWritableDatabase();long rowId = db.insert(MainTable.TABLE_NAME, null, values);// If the insert succeeded, the row ID exists.if (rowId > 0) {Uri noteUri = ContentUris.withAppendedId(MainTable.CONTENT_ID_URI_BASE, rowId);getContext().getContentResolver().notifyChange(noteUri, null);return noteUri;}throw new SQLException("Failed to insert row into " + uri);}/*** Handle deleting data.*/@Overridepublic int delete(Uri uri, String where, String[] whereArgs) {SQLiteDatabase db = mOpenHelper.getWritableDatabase();String finalWhere;int count;switch (mUriMatcher.match(uri)) {case MAIN:// If URI is main table, delete uses incoming where clause and args.count = db.delete(MainTable.TABLE_NAME, where, whereArgs);break;// If the incoming URI matches a single note ID, does the delete based on the// incoming data, but modifies the where clause to restrict it to the// particular note ID.case MAIN_ID:// If URI is for a particular row ID, delete is based on incoming// data but modified to restrict to the given ID.finalWhere = DatabaseUtils.concatenateWhere(MainTable._ID + " = " + ContentUris.parseId(uri), where);count = db.delete(MainTable.TABLE_NAME, finalWhere, whereArgs);break;default:throw new IllegalArgumentException("Unknown URI " + uri);}getContext().getContentResolver().notifyChange(uri, null);return count;}/*** Handle updating data.*/@Overridepublic int update(Uri uri, ContentValues values, String where, String[] whereArgs) {SQLiteDatabase db = mOpenHelper.getWritableDatabase();int count;String finalWhere;switch (mUriMatcher.match(uri)) {case MAIN:// If URI is main table, update uses incoming where clause and args.count = db.update(MainTable.TABLE_NAME, values, where, whereArgs);break;case MAIN_ID:// If URI is for a particular row ID, update is based on incoming// data but modified to restrict to the given ID.finalWhere = DatabaseUtils.concatenateWhere(MainTable._ID + " = " + ContentUris.parseId(uri), where);count = db.update(MainTable.TABLE_NAME, values, finalWhere, whereArgs);break;default:throw new IllegalArgumentException("Unknown URI " + uri);}getContext().getContentResolver().notifyChange(uri, null);return count;}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);FragmentManager fm = getFragmentManager();// Create the list fragment and add it as our sole content.if (fm.findFragmentById(android.R.id.content) == null) {ThrottledLoaderListFragment list = new ThrottledLoaderListFragment();fm.beginTransaction().add(android.R.id.content, list).commit();}}public static class ThrottledLoaderListFragment extends ListFragmentimplements LoaderManager.LoaderCallbacks<Cursor> {// Menu identifiersstatic final int POPULATE_ID = Menu.FIRST;static final int CLEAR_ID = Menu.FIRST+1;// 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;// Task we have running to populate the database.AsyncTask<Void, Void, Void> mPopulatingTask;@Override public void onActivityCreated(Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);setEmptyText("No data. Select 'Populate' to fill with data from Z to A at a rate of 4 per second.");setHasOptionsMenu(true);// Create an empty adapter we will use to display the loaded data.mAdapter = new SimpleCursorAdapter(getActivity(),android.R.layout.simple_list_item_1, null,new String[] { MainTable.COLUMN_NAME_DATA },new int[] { android.R.id.text1 }, 0);setListAdapter(mAdapter);// Start out with a progress indicator.setListShown(false);// Prepare the loader. Either re-connect with an existing one,// or start a new one.getLoaderManager().initLoader(0, null, this);}@Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {menu.add(Menu.NONE, POPULATE_ID, 0, "Populate").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);menu.add(Menu.NONE, CLEAR_ID, 0, "Clear").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);}@Override public boolean onOptionsItemSelected(MenuItem item) {final ContentResolver cr = getActivity().getContentResolver();switch (item.getItemId()) {case POPULATE_ID:if (mPopulatingTask != null) {mPopulatingTask.cancel(false);}mPopulatingTask = new AsyncTask<Void, Void, Void>() {@Override protected Void doInBackground(Void... params) {for (char c='Z'; c>='A'; c--) {if (isCancelled()) {break;}StringBuilder builder = new StringBuilder("Data ");builder.append(c);ContentValues values = new ContentValues();values.put(MainTable.COLUMN_NAME_DATA, builder.toString());cr.insert(MainTable.CONTENT_URI, values);// Wait a bit between each insert.try {Thread.sleep(250);} catch (InterruptedException e) {}}return null;}};mPopulatingTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);return true;case CLEAR_ID:if (mPopulatingTask != null) {mPopulatingTask.cancel(false);mPopulatingTask = null;}AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {@Override protected Void doInBackground(Void... params) {cr.delete(MainTable.CONTENT_URI, null, null);return null;}};task.execute((Void[])null);return true;default:return super.onOptionsItemSelected(item);}}@Override public void onListItemClick(ListView l, View v, int position, long id) {// Insert desired behavior here.Log.i(TAG, "Item clicked: " + id);}// These are the rows that we will retrieve.static final String[] PROJECTION = new String[] {MainTable._ID,MainTable.COLUMN_NAME_DATA,};public Loader<Cursor> onCreateLoader(int id, Bundle args) {CursorLoader cl = new CursorLoader(getActivity(), MainTable.CONTENT_URI,PROJECTION, null, null, null);cl.setUpdateThrottle(2000); // update at most every 2 seconds.return cl;}public void onLoadFinished(Loader<Cursor> loader, Cursor data) {mAdapter.swapCursor(data);// The list should now be shown.if (isResumed()) {setListShown(true);} else {setListShownNoAnimation(true);}}public void onLoaderReset(Loader<Cursor> loader) {mAdapter.swapCursor(null);}} } 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的Android Loader机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android-源代码分析
- 下一篇: Java数据结构与算法:二叉树