GitHub user riknoll opened a pull request: https://github.com/apache/cordova-android/pull/239
CB-8917: Added pending plugin callbacks to resume event payload This is a redo of #236 after receiving some feedback. This relates to CB-8917 and CB-9189. ### Background The issue at hand is that plugins can make calls to an external Activity and, if the device is low on memory, there is a chance that the CordovaActivity will get killed in the background causing the plugin to lose its state as well as its context for the callback. Activities in Android typically handle this situation by using `onSaveInstanceState()` and `onCreate()` methods to save and restore state respectively as the Activity is created and destroyed. This solution exposes that lifecycle to plugins, allowing them to save state and have it restored if necessary. ### Saving/Restoring plugin state Two new methods are exposed to plugins that they can override to save/restore state. ```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) {} ``` The plugin is given a replacement CallbackContext as part of `onRestoreStateForActivityResult` that can accept the result the plugin would normally return and add it to the resume event payload for use in the js (see JSON below). Thus, it requires minimal modifications to existing plugins _NOTE:_ When I mention that plugins are given the opportunity to restore state, I want to clarify that this only happens for plugins that are waiting for an external Activity result. This makes the API a little less intuitive, but otherwise we would be conflicting with the accepted behavior that plugins currently get destroyed (i.e. lose all of their state) and are selectively rebuilt whenever a new URL is loaded into the webview. If we restore state on resume, then we can end up with some awkward cases where part of the resuming involves loading a new page so the state gets lost again and so on and so forth. My thinking is that restoring the other state is better left to app developers ### Saving/Restoring js state We already send out pause and resume events. This solution enhances these events in the case of Activity destruction by adding to them the result of any pending Plugin calls. The resume event is of the form ``` { action: "resume", pendingResult: { pluginServiceName: <plugin service name e.g. "Camera">, pluginStatus: <description of result' status (see PluginResult.java)>, result: <argument(s) that would have been given to the callback> } } ``` It is the responsibility of the application developer to properly use these events and save their state as well as keep information about what plugin results they have pending. We should provide guidance for this in the Android documentation and plugin documentation should clearly communicate when it is necessary. ### Discussion #### Benefits: * It requires minimal updates to existing plugins (and no updates at all if the plugin doesn't use an external Activity) * It is a general solution/pattern that plugins can follow rather than forcing them to include platform specific methods in their APIs #### Downsides: * The resume callback will only ever get received after the initial page loads (potential page flickering) * The pending result part of the event object doesn't provide much context (so it puts more responsibility on the app developer to keep state so they know what they're getting) In the core plugins, this is mostly relevant to the Camera plugin which previously would crash upon receiving the Activity result if the CordovaActivity had been killed by the OS while a picture was being taken/chosen (CB-9189). The updated Camera Plugin can be found in [this branch](https://github.com/MSOpenTech/cordova-plugin-camera/tree/save-state-plugin-only) and a (trivial) example application that uses this API + instructions for testing can be found [here](https://gist.github.com/riknoll/d0ab25583b1dc8ab22af). You can merge this pull request into a Git repository by running: $ git pull https://github.com/MSOpenTech/cordova-android save-state-plugin-only Alternatively you can review and apply these changes as the patch at: https://github.com/apache/cordova-android/pull/239.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #239 ---- commit 62a7873792205696c25b8498b521ef9828648e59 Author: riknoll <richard.b.kn...@gmail.com> Date: 2015-11-10T23:01:13Z CB-8917: Added pending plugin callbacks to resume event payload ---- --- If your project is set up for it, you can reply to this email and have your reply appear on GitHub as well. If your project does not have this feature enabled and wishes so, or if the feature is enabled but not working, please contact infrastructure at infrastruct...@apache.org or file a JIRA ticket with INFRA. --- --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@cordova.apache.org For additional commands, e-mail: dev-h...@cordova.apache.org