Repository: cordova-docs
Updated Branches:
  refs/heads/master fc483207b -> d7e985235


CB-8917: Added docs for Android lifecycle considerations


Project: http://git-wip-us.apache.org/repos/asf/cordova-docs/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-docs/commit/d7e98523
Tree: http://git-wip-us.apache.org/repos/asf/cordova-docs/tree/d7e98523
Diff: http://git-wip-us.apache.org/repos/asf/cordova-docs/diff/d7e98523

Branch: refs/heads/master
Commit: d7e985235035f8fb164c3c738c6229b336329b28
Parents: fc48320
Author: riknoll <[email protected]>
Authored: Tue Dec 1 15:59:52 2015 -0800
Committer: riknoll <[email protected]>
Committed: Tue Dec 1 15:59:52 2015 -0800

----------------------------------------------------------------------
 .../en/dev/guide/platforms/android/lifecycle.md | 125 +++++++++++++++++++
 .../en/dev/guide/platforms/android/plugin.md    | 109 +++++++++++++++-
 www/docs/en/dev/guide/platforms/index.md        |   1 +
 3 files changed, 232 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/d7e98523/www/docs/en/dev/guide/platforms/android/lifecycle.md
----------------------------------------------------------------------
diff --git a/www/docs/en/dev/guide/platforms/android/lifecycle.md 
b/www/docs/en/dev/guide/platforms/android/lifecycle.md
new file mode 100644
index 0000000..ab29d92
--- /dev/null
+++ b/www/docs/en/dev/guide/platforms/android/lifecycle.md
@@ -0,0 +1,125 @@
+---
+license: >
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+title: Android Lifecycle Guide
+---
+
+# Android Lifecycle Guide
+
+Native Android apps typically consist of a series of "activities" that the 
user interacts with. Activities can be thought of as the individual screens 
that make up an application; different tasks in an app will often have their 
own activity. Each activity has a lifecycle, and can be created and destroyed 
as the OS sees fit.
+
+In contrast, Cordova applications on the Android platform are executed within 
a Webview that is embedded in a *single* Android activity. The lifecycle of 
this activity is exposed to your application through the document events that 
are fired. These events are not guaranteed to line up with Android's lifecycle, 
but they can provide guidelines for saving and restoring your state. These 
events roughly map to Android callbacks as follows:
+
+Cordova Event   | Rough Android Equivalent
+----------------|-----------------------------------
+`deviceready`   | `onCreate()`
+`pause`         | `onPause()`
+`resume`        | `onResume()`
+
+Often, Cordova applications are confined to the single activity that contains 
the Webview. However, there are instances in which other activities may be 
launched that push the Cordova activity to the background. It is important in 
these cases to be aware of the Android lifecycle and properly maintain your 
application's state by respecting it.
+
+## Low memory and the Activity lifecycle
+
+Plugins have the ability to launch activities beyond the Cordova activity in 
order to perform some tasks. For example, the Apache camera plugin, 
cordova-plugin-camera, launches the device's camera activity in order to take 
photos.
+
+The flow of events in this case looks something like this:
+
+1. The user is interacting with your app and needs to take a picture
+2. The camera plugin launches the native camera activity
+    * *The Cordova activity is pushed to the background (`pause` event is 
fired)*
+3. The user takes a photo
+4. The camera activity finishes
+    * *The Cordova activity is moved to the foreground (`resume` event is 
fired)*
+5. The user is returned to your application where they left off
+
+However, this flow of events can be disrupted if a device is low on memory. 
The Android OS will often kill background activities in order to free up memory 
if necessary. Unfortunately, when the activity holding your application is 
killed, the Webview in which your application lives will be destroyed as well. 
Any state that your application is maintaining will be lost in this case. When 
the user navigates back to your the application, the Activity and Webview will 
be recreated by the OS, but state will not be automatically restored.
+
+If state is not properly saved when the Activity is destroyed, the above 
sequence of events instead plays out as follows:
+
+1. The user is interacting with your app and needs to take a picture
+2. The camera plugin launches the native camera activity
+    * *The OS destroys the Cordova activity (`pause` event is fired)*
+3. The user takes a photo
+4. The camera activity finishes
+    * *The OS recreates the Cordova activity (`deviceready` and `resume` 
events are fired)*
+5. The user is confused as to why they are suddenly back at your app's login 
screen
+
+In this instance, the photo that was taken is lost and the user is given the 
confusing and frustrating experience of having your application appear to 
randomly restart. The key to preventing this experience is subscribing to 
events and properly maintaining state as part of the activity lifecycle.
+
+## Maintaining state
+
+In the examples above, the javascript events that are fired are noted in 
italics. These events are your opportunity to save and restore your 
application's state. You should register callbacks in your application's 
`bindEvents` function that respond to the lifecycle events by saving state. 
What information you save and how you save it is left to your discretion, but 
you should be sure to save enough information so that you can restore the user 
to exactly where they left off when they return to your application.
+
+## Testing the Activity Lifecycle
+
+Android provides a developer setting for debugging Activity destruction on low 
memory. Enable the "Don't keep activities" setting in the Developer Options 
menu on your device or emulator to simulate low memory scenarios. If your 
application launches external activities, you should always do some testing 
with this setting enabled to ensure that you are properly handling low memory 
scenarios.
+
+## Retrieving plugin callback results
+
+When the OS destroys the Cordova activity in the above example, any pending 
callbacks are lost as well. This means that if you passed a callback to the 
plugin that launched the new activity (e.g. cordova-plugin-camera), that 
callback will NOT be fired when the application is recreated. However, there is 
a way for plugins to pass the result of this call to your application. The 
`resume` event's payload will contain any pending plugin results from the 
plugin request that launched the external activity made prior to the activity 
being destroyed.
+
+The payload for the `resume` event adheres to the following format:
+
+```
+{
+    action: "resume",
+    pendingResult: {
+        pluginServiceName: <name of the plugin e.g. "Camera">,
+        pluginStatus: <description of the result's status (see below)>,
+        result: <argument(s) that would have been given to the callback>
+    }
+}
+```
+
+The possible plugin statuses in the `pendingResult` field include the 
following values:
+
+```
+"No result"
+"OK"
+"Class not found"
+"Illegal access"
+"Instantiation error"
+"Malformed url"
+"IO error"
+"Invalid action"
+"JSON error"
+"Error
+```
+
+>**NOTE:** It is up to the plugin to decide what is contained in the `result` 
field and the meaning of the `pluginStatus` that is returned. Reference the API 
of the plugin you are using to see what you should expect those fields to 
contain and how to use their values
+
+A `resume` callback that makes use of the event payload might look something 
like this:
+
+```javascript
+onResume(event) {
+    // Restore your application's state here. It's up to you to keep track of
+    // where this plugin result is coming from (i.e. what part of your code 
made
+    // the call) and what arguments you provided to the plugin
+
+    // Next, check if there is a plugin result in the event object
+    if(event.pendingResult) {
+        // Figure out whether or not the plugin call was successful
+        if(event.pendingResult.pluginStatus === "OK") {
+            successCallback(event.result);
+        } else {
+            failCallback(event.result);
+        }
+    }
+}
+```

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/d7e98523/www/docs/en/dev/guide/platforms/android/plugin.md
----------------------------------------------------------------------
diff --git a/www/docs/en/dev/guide/platforms/android/plugin.md 
b/www/docs/en/dev/guide/platforms/android/plugin.md
index e232ba6..eb077b5 100644
--- a/www/docs/en/dev/guide/platforms/android/plugin.md
+++ b/www/docs/en/dev/guide/platforms/android/plugin.md
@@ -346,16 +346,119 @@ In addition to asking for permission for a single 
permission, it is also possibl
     String [] permissions = { Manifest.permission.ACCESS_COARSE_LOCATION, 
Manifest.permission.ACCESS_FINE_LOCATION };
 
 Then when requesting the permission, all that needs to be done is the 
following:
-    
+
     cordova.requestPermissions(this, 0, permissions);
 
-This requests the permissions specified in the array.  It's a good idea to 
provide a publicly accessible permissions array since this can be used by 
plugins that use your plugin as a 
+This requests the permissions specified in the array.  It's a good idea to 
provide a publicly accessible permissions array since this can be used by 
plugins that use your plugin as a
 dependency, although this is not required.
 
 ## Debugging Android Plugins
 
 Android debugging can be done with either Eclipse or Android Studio, although 
Android
 studio is recommended.  Since Cordova-Android is currently used as a library 
project,
-and plugins are supported as source code, it is possible to debug the Java 
code inside 
+and plugins are supported as source code, it is possible to debug the Java 
code inside
 a Cordova application just like a native Android application.
 
+## Launching Other Activities
+
+There are special considerations to be made if your plugin launches an Activity
+that pushes the Cordova Activity to the background. The Android OS will destroy
+Activities in the background if the device is running low on memory. In that
+case, the CordovaPlugin instance will be destroyed as well. If your plugin is
+waiting on a result from the Activity it launched, a new instance of your 
plugin
+will be created when the Cordova Activity is brought back to the foreground and
+the result is obtained. However, state for the plugin will not be automatically
+saved or restored and the CallbackContext for the plugin will be lost. There 
are
+two methods that your CordovaPlugin may implement to handle this situation:
+
+```java
+/**
+ * Called when the Activity is being destroyed (e.g. if a plugin calls out to 
an
+ * external Activity and the OS kills the CordovaActivity in the background).
+ * The plugin should save its state in this method only if it is awaiting the
+ * result of an external Activity and needs to preserve some information so as
+ * to handle that result; onRestoreStateForActivityResult() will only be called
+ * if the plugin is the recipient of an Activity result
+ *
+ * @return  Bundle containing the state of the plugin or null if state does not
+ *          need to be saved
+ */
+public Bundle onSaveInstanceState() {}
+
+/**
+ * Called when a plugin is the recipient of an Activity result after the
+ * CordovaActivity has been destroyed. The Bundle will be the same as the one
+ * the plugin returned in onSaveInstanceState()
+ *
+ * @param state             Bundle containing the state of the plugin
+ * @param callbackContext   Replacement Context to return the plugin result to
+ */
+public void onRestoreStateForActivityResult(Bundle state, CallbackContext 
callbackContext) {}
+```
+
+It is important to note that the above methods should only be used if your
+plugin launches an Activity for a result and should only restore the state
+necessary to handle that Activity result. The state of the plugin will *NOT* be
+restored except in the case where an Activity result is obtained that your
+plugin requested using the CordovaInterface's `startActivityForResult()` method
+and the Cordova Activity was destroyed by the OS while in the background.
+
+As part of `onRestoreStateForActivityResult()`, your plugin will be passed a
+replacement CallbackContext. It is important to realize that this
+CallbackContext *IS NOT* the same one that was destroyed with the Activity. The
+original callback is lost, and will not be fired in the javascript application.
+Instead, this replacement CallbackContext will return the result as part of the
+`resume` event that is fired when the application resumes. The payload of the
+`resume` event follows this structure:
+
+```
+{
+    action: "resume",
+    pendingResult: {
+        pluginServiceName: <name of the plugin e.g. "Camera">,
+        pluginStatus: <description of the result's status>,
+        result: <argument(s) that would have been given to the callback>
+    }
+}
+```
+
+* `pluginServiceName` will match the `name` attribute from your plugin.xml
+* `pluginStatus` will be a String describing the status of the PluginResult
+   passed to the CallbackContext. See PluginResult.java for the String values
+   that correspond to plugin statuses
+* `result` will be whatever result the plugin passes to the CallbackContext
+   (e.g. a String, a number, a JSON object, etc.)
+
+This resume payload will be passed to any callbacks that the javascript
+application has registered for the `resume` event. This means that the result 
is
+going *directly* to the Cordova application; your plugin will not have a chance
+to process the result with javascript before the application receives it.
+Consequently, you should strive to make the result returned by the native code
+as complete as possible and not rely on any javascript callbacks when launching
+activities.
+
+Be sure to communicate how the Cordova application should interpret the result
+they receive in the `resume` event. It is up to the Cordova application to
+maintain their own state and remember what requests they made and what 
arguments
+they provided if necessary. However, you should still clearly communicate the
+meaning of `pluginStatus` values and what sort of data is being returned in the
+`result` field as part of your plugin's API.
+
+The complete sequence of events for launching an Activity is as follows
+
+1. The Cordova application makes a call to your plugin
+2. Your plugin launches an Activity for a result
+3. The Android OS destroys the Cordova Activity and your plugin instance
+    * *`onSaveInstanceState()` is called*
+4. The user interacts with your Activity and the Activity finishes
+5. The Cordova Activity is recreated and the Activity result is received
+    * *`onRestoreStateForActivityResult()` is called*
+6. `onActivityResult()` is called and your plugin passes a result to the new
+    CallbackContext
+7. The `resume` event is fired and received by the Cordova application
+
+Android provides a developer setting for debugging Activity destruction on low
+memory. Enable the "Don't keep activities" setting in the Developer Options 
menu
+on your device or emulator to simulate low memory scenarios. If your plugin
+launches external activities, you should always do some testing with this
+setting enabled to ensure that you are properly handling low memory scenarios.

http://git-wip-us.apache.org/repos/asf/cordova-docs/blob/d7e98523/www/docs/en/dev/guide/platforms/index.md
----------------------------------------------------------------------
diff --git a/www/docs/en/dev/guide/platforms/index.md 
b/www/docs/en/dev/guide/platforms/index.md
index 286e6fd..9e19e3f 100644
--- a/www/docs/en/dev/guide/platforms/index.md
+++ b/www/docs/en/dev/guide/platforms/index.md
@@ -55,6 +55,7 @@ a lower-level alternative to the `cordova` command-line 
utility.
 * [Android Plugins](android/plugin.html)
 * [Android WebViews](android/webview.html)
 * [Upgrading Android](android/upgrade.html)
+* [Android Lifecycle Guide](android/lifecycle.html)
 
 ## BlackBerry 10
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to