This section describes how to adopt
LIB:
Mark Murphy's enhancements to Android's
Loader Framework introduced by Honeycomb.
Sample LoaderCursor within ApiDemos illustrate how to use loaders.
The compatibility library also includes a loader.
LoaderThrottle within ApiDemos shows throttling to reduce content provider queries when data changes.
Loader Fundamentals note that each activity or fragment has a single LoaderManager which manages one or more Loader instances for its Activity or Fragment.
A CursorLoader is expected to retain its data after being stopped. so when users return to an application, apps have kept state across the activity or fragment's onStop() and onStart() methods, and users don't have to wait for data reload on the main UI thread.
The abstract ListFragment class is subclassed (extended) with methods within LoaderManager.LoaderCallbacks trigger when a new loader is to be created and when it is time to stop using a loader's data.
public static class CursorLoaderListFragment extends ListFragment implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> { SimpleCursorAdapter mAdapter; // Adapter used to display the list's data. String mCurFilter; // If non-null, holds the current filter specified by the user.
When a new activity is created:
@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); // Prepare the loader. Either re-connect with an existing one, // or start a new one. getLoaderManager().initLoader(0, null, this); }
Place an action bar item for searching:
@Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { MenuItem item = menu.add("Search"); item.setIcon(android.R.drawable.ic_menu_search); item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); SearchView sv = new SearchView(getActivity()); sv.setOnQueryTextListener(this); item.setActionView(sv); }
Define the data structure to be retrieved:
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, };
When a new Loader needs to be created, pick the base URI to use depending on whether we are currently filtering (mCurFilter != null).
This sample only has one Loader, so we don't care about the ID.
Then create and return a CursorLoader SQL select statement which creates the Cursor for data being displayed.
public Loader<Cursor> onCreateLoader(int id, Bundle args) { Uri baseUri; if (mCurFilter != null) { baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(mCurFilter)); } else { baseUri = Contacts.CONTENT_URI; } 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"); }
When search filter text is changed by the user, restart the loader to do a new query using the new filter:
public boolean onQueryTextChanged(String newText) { mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; getLoaderManager().restartLoader(0, null, this); return true; }
Clean-up methods:
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); } 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); }
BOOK:
The Definitive Guide to SQLite
by Michael Owens.
APP: SQLite Editor from well-regarded Speed Software, for $2.99, edits and deletes records in any SQLite database.
To auto-generate tables and CRUD functions used by a lightweight ORM, SQLiteOpenHelper and SQLiteDatabase from
OBB (Opaque Binary Blobs), introduced in Gingerbread (2.3, API 9), can be encrypted and be several gigabytes large. Good for GPS/Mapping apps.
"NoSQL" databases are becoming popular (to not just Google and Facebook) for their ability to accept a massive amount of data all at once (rather than the sequential update inherent in SQL databases).
Casandra on web servers
LIB: CouchBase
Obscura using OISafe, both from Openintents, encrypts picture files. Scarlette Johansen, you hearing this?
Encryption is not hardware‐accelerated. So there is a 54% degradation in I/O read performance on Samsung Galaxy Tab 10.1
LIB: CouchBase
WEBSITE: odata.org is under Microsoft’s Open Specification Promise.
This enables devices to store data on industrial-strength databases (Oracle, MS SQL Server, etc.) that load balance themselves and other tricks for scalability and redundancy to ensure high-availability (HA).
So SQL for web based data, supporting querying, inserting and updating data remotely.
OData makes use of REST, HTTP, Atom Publishing Protocol (AtomPub), and JSON (or XML).
LIB: odata4j at version 0.4 as of this writing, is built on JAX-RS, JPA, and StAX using jersey & Joda Time libraries
See remobjects.com by Jim McKeeth
Peer-to-peer bi-directional communication to share photos, music, gaming, etc. without setting up a hot spot.