cordova-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Marcel Kinard (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (CB-6936) app crashes if webview is destroyed while dialog box open
Date Mon, 16 Jun 2014 20:22:02 GMT

    [ https://issues.apache.org/jira/browse/CB-6936?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14032879#comment-14032879
] 

Marcel Kinard commented on CB-6936:
-----------------------------------

This sounds vaguely related to CB-6837.

> app crashes if webview is destroyed while dialog box open
> ---------------------------------------------------------
>
>                 Key: CB-6936
>                 URL: https://issues.apache.org/jira/browse/CB-6936
>             Project: Apache Cordova
>          Issue Type: Bug
>          Components: Android, Plugin Dialogs
>    Affects Versions: 3.4.0
>         Environment: Android 4.x on physical device
> Or any Android environment
>            Reporter: Shingo Toda
>            Assignee: Joe Bowser
>
> We have an Android application which implements an embedded WebView "container" in which
it executes customer Cordova apps.
> Under certain conditions our container needs to terminate the customer app, and during
this termination it calls {{CordovaWebView.destroy()}} to disable CordovaWebView.
> But application may entirely crash during this termination in some scenarios. For example:
> # call {{navigator.notification.alert}}, {{confirm}} or {{prompt}} and leave popup dialog
open
> # this termination is done for some reason while dialog box is till open
> # all views on CordovaWebView are released but dialog box still remains
> # attempt to close dialog by pressing button in the dialog
> # application crashes with Unknown exception.
> {code}
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): 81508: Unknown exception occurred.
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): java.lang.NullPointerException
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): 	at android.webkit.WebView.setNetworkAvailable(WebView.java:2639)
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): 	at org.apache.cordova.NativeToJsMessageQueue$OnlineEventsBridgeMode$1.run(NativeToJsMessageQueue.java:305)
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): 	at android.app.Activity.runOnUiThread(Activity.java:4175)
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): 	at org.apache.cordova.NativeToJsMessageQueue$OnlineEventsBridgeMode.onNativeToJsMessageAvailable(NativeToJsMessageQueue.java:313)
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): 	at org.apache.cordova.NativeToJsMessageQueue.enqueueMessage(NativeToJsMessageQueue.java:253)
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): 	at org.apache.cordova.NativeToJsMessageQueue.addPluginResult(NativeToJsMessageQueue.java:246)
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): 	at org.apache.cordova.CordovaWebView.sendPluginResult(CordovaWebView.java:572)
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): 	at org.apache.cordova.CallbackContext.sendPluginResult(CallbackContext.java:64)
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): 	at org.apache.cordova.dialogs.Notification$1$1.onClick(Notification.java:150)
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): 	at com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java:167)
> {code}
> h2. Problem
> Obviously CordovaWebView is already not available but dialog still exists. If a user
press button in dialog, {{onClick()}} gets called and consequently {{CordovaWebView.setNetworkAvailable()}}
gets called to send message from queue to JavaScript even though WebView is already destroyed.
As a result, entire application crashes.
> h3. Workaround
> We made a method to check if WebView is destroyed or not.
> {code}
>     private boolean isWebViewDestroyed() {
>     	final String url = webView.getUrl();
>     	if (url == null ||
>     		url.equals("about:blank")) {
>     		return true;
>     	} else {
>         	return false;
>     	}
>     }
> {code}
> And check this before {{callbackContext.sendPluginResult()}} is called.
> {code}
>     public synchronized void alert(final String message, final String title, final String
buttonLabel, final CallbackContext callbackContext) {
>         final CordovaInterface cordova = this.cordova;
>         Runnable runnable = new Runnable() {
>             public void run() {
>                 AlertDialog.Builder dlg = new AlertDialog.Builder(cordova.getActivity());
>                 dlg.setMessage(message);
>                 dlg.setTitle(title);
>                 dlg.setCancelable(true);
>                 dlg.setPositiveButton(buttonLabel,
>                         new AlertDialog.OnClickListener() {
>                             public void onClick(DialogInterface dialog, int which) {
>                                 dialog.dismiss();
>                                 if (!isWebViewDestroyed()) {
>                                     callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK,
0));
>                                 }
>                             }
>                         });
>                 dlg.setOnCancelListener(new AlertDialog.OnCancelListener() {
>                     public void onCancel(DialogInterface dialog)
>                     {
>                         dialog.dismiss();
>                         if (!isWebViewDestroyed()) {
>                             callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK,
0));
>                         }
>                     }
>                 });
>                 dlg.create();
>                 dlg.show();
>             };
>         };
>         this.cordova.getActivity().runOnUiThread(runnable);
>     }
> {code}
> Similar changes are also applied to {{confirm()}} and {{prompt()}}. This workaround works
fine on my application.
> h2. Question
> I want to know if this workaround is correct.
> * Do you know how to check if WebView is destroyed or not? I end up choosing {{getURL()}}
as a result of experimental test. I appreciate any official or popular way.
> * {{isWebViewDestroyed()}} could be before {{webView.sendPluginResult(pluginResult, callbackId)}}
in {{CallbackContext.sendPluginResult()}}? I think this way would prevent any APIs from this
problem. But I'm afraid if this idea may impacts on other plugin API calls.



--
This message was sent by Atlassian JIRA
(v6.2#6252)

Mime
View raw message