Pop-up this diagram to its own window
|
In Android docs:
ARTICLE:
Managing the Activity Lifecycle
ARTICLE:
Activity Lifecycle Reference
ARTICLE:
Managing State in an Android
Activity
by Martin Belcher
Androidology 2 of 3 - Application Lifecycle
by Mike Cleron on the Android dev. team.
Inside the Android Application Framework
@ Google I/O May 20, 2008
Dan Morrill explains lifecycle use cases
using
this reference illustration.
1:02:08+ into Class 1 Part 4
and also in his
WEBSITE:
ebook.
public class ..AppActivity extends Activity { ImageView ...; protected Launcher mLauncher; ...
This "main" thread is also called the UI thread because it dispatches and draws events to widgets such as ImageView.
The main thread also interacts with running components of the Android UI toolkit.
The state of an Android activity is the value of each UI control displayed, plus other information needed to get the activity back to where it was when the home key was pressed, the screen rotated, etc.
@Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); StrictWrapper.init(); ... }
"super." is the context class interface to global information about the application environment via "this" because Activities and Services extend the "Context" class to receive Android services, e.g. the Location Service.
The Bundle argument is the equivalent of (String args[]) to access command-line invocation variables in standard Java programs.
Bundle "icicle" is used in code samples early in Android's life because function onFreeze() was used to save temporary state information instead of the more current onSaveInstanceState() function and associated savedInstanceState() bundle name.
public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); if( savedInstanceState != null){ // retrieve them into the view: // Log.d(TAG,savedInstanceState.getString("Name")); String strValue = savedInstanceState.getString("Name"); if (strValue != null){ EditText oControl = (EditText)findViewById(R.id.txtName); oControl.setText(strValue); } ... CheckBox chkTandC = (CheckBox)findViewById(R.id.chkTandC); chkTandC.setChecked(savedInstanceState.getBoolean("TandC")); } }
TEST: Specifying the wrong type to a variable are caught by the compiler. Mis-assigning a value to the wrong field name is an easy to do. So such common mistake needs manual verification.
Information controlling the logic of activity start-up can also be in SharedPreferences.
SharedPreferences preferences = PerferenceManager.getDefaultSharedPreferences(getApplicationContext()); // TODO: Pull default from selection in Contacts: String txtPrefVar = "Phone"; String txtValue = preferences.getString(txtPrefVar,"+1 310.320-7878"); // establilshes default. Log.d(txtActivityName+":"+txtPrefVar, txtValue); SharedPreferences preferences = PerferenceManager.getDefaultSharedPreferences(getApplicationContext()); Editor editor = preferences.edit(); editor.putStrong("Phone","+1 310.320-7878"); editor.commit(); // SharedPreferences preferences = PerferenceManager.getPreferences(MODE_PRIVATE); // or MODE_WORLD_READABLE oControl = (EditText)findViewById(R.id.txtEmail); oControl.setText(preferences.getString("Email", null));
TEST: Coding mistakes in moving data between screen inputs and default preferences need to be manually verified for correspondance between them.
TEST: If editor.commit() is not specified, data on the screen will not be actually saved. So use an alternate tool to examine stored valuess of preferences after execting the app.
setContentView(R.layout.main);
UI controls (such as buttons) and data Loaders are also instantiated in this section:
getCheckoutButton(...); // Re-connect existing or invoke LoaderManager.LoaderCallbacks method onCreateLoader() to start new data loader: getLoaderManager().initLoader(ListLoaderIndex, null, this); StrictMode.enableDefaults();
Variable ListLoaderIndex begins from zero.
After onCreate(), the OS automatically transfers control to onStart().
2. Android v2.0 and later invokes onStartCommand() automatically. Prior versions (1.6 and before) invokes onStart().
This is where an activity's functionality occurs and focus is defined. So overrride onStartCommand() called to pass requests to the service via component Context.startService. This normally dispatch work to a background thread, whose return values are:
The transition from Starting State to Running State is one of the most battery-draining operations in terms of computing time, so the system avoids this by keeping activities around for re-use when memory allows.
Service components are always killed (destroyed) from the running state.
3. Code to override onResume() is called by the OS after the device goes to sleep or after an Alert or other partial-screen child activity leaves a portion of the previous window visible so a method is need to re-initialize fields (within a try structure with a catch of exceptions). Such a situation does not cause onStop() to be invoked when the child closes.
public void onResume() { super.onResume(); try { // Do whatever this activity should do... } catch (java.io.FileNotFoundException e) { // Maybe OK to be here if it hasn't been created yet. } catch (Throwable t) { Toast .makeText(this, "Exception: "+t.toString(), Toast.LENGTH_LONG).show(); } }
To preserve battery life, register for service updates onResume() and unregister in onPause() -- only while in the Running state.
4. onSaveInstanceState(), previously onFreeze(), goes to work to pre-emptively save UI state (not persistent data) in a bundle for the activity's "future self". If the activity is about to be destroyed, there is no need to call this.
So that the activity can restore its state when/if re-started:
the text field on the screen defined as txtName is
retrieved, converted to a string, whose value is put into the "Name" field of the bundle;
the checkbox on the screen named chkTandC is
retrieved, converted to a boolean, whose value is put into the "TandC" field of the bundle.
@Override protected void onSaveInstanceState(Bundle outState){ EditText txtName = (EditText)findViewById(R.id.txtName); String strName = txtName.getText().toString(); outState.putString("Name", txtName); CheckBox chkTandC = (CheckBox)findViewById(R.id.chkTandC); boolean blnTandC = chkTandC.isChecked(); outState.putBoolean("TandC", blnTandC); super.onSaveInstanceState(outState); }
TEST: The same fields (and type) should be in onCreate() Automated generation of code can ensure this occurs and thus avoid manual checking.
NOTE: Dialog box views are not an activity and have no impact on the lifecycle.
onSaveInstanceState() is not guaranteed to be called, so use record only activity transient state and use onPause() to store persistent data into Preferences or a database table.
5. When the user rotates the screen, presses Back button to a previous screen, presses the Home/Menu key, or another activity comes in front, an activity no longer has focus at the top of the run stack, onPause() is called on the way to the activity being stopped.
public void onPause() { super.onPause(); try { // Because this occurs at a critical time (user is waiting), // writing state to a file is quicker than writing to a database: OutputStreamWriter out=new OutputStreamWriter(openFileOutput(OUTPUT_FILE_1_NAME,0)); out.write(worker.getText().toString()); out.close(); // releases resources. // Dtore values from a view into persistent Preferences: SharedPreferences preferences = getPreferences(MODE_PRIVATE); SharedPreferences.Editor editor = preferences.edit(); EditText txtName = (EditText)findViewById(R.id.txtName); String strName = txtName.getText().toString(); editor.putString("Name", strName); // value to store editor.commit(); } catch (Throwable t) { Toast .makeText(this, "Exception: "+t.toString(), Toast.LENGTH_LONG).show(); } }
Notice that OUTPUT_FILE_1_NAME is a static string defined early in code (under class ... extends) to contain the file name:
private final static String OUTPUT_FILE_1_NAME="notes.txt"; worker;
Programming code have not much control of state after this point.
REMINDER:
All roads out of Running state go via onPause().
REMINDER:
All roads into Running state go via onResume().
6. onStop() is called immediately after onPause().
7. onRestart() is always followed by onStart()
8. To make room in memory, an activity can be terminated automatically by the operating system.
9. The app may be killed if a control (such as OK or END) is provided in the UI. Override onDestroy() to notify the Service is being shut down.
@Override public void onDestroy() { super.onDestroy(); }
This code is called by a component stopping itself with a call to stopSelf() or by another component calling stopService().
Java Base Class: ContentProvider store, query, and retrieve data (such as open a phone contact) across apps.
WEBSITE: Tutorial on this (and other Android topics) on Sai Geetha's excellent blog.
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.