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

Shingo Toda commented on CB-6936:
---------------------------------

We are using our own BroadcastReceiver and its {{onReceived()}} calls a method 
implemented in our Activity class to terminate an app running on CordovaWebView 
container. For example, if we monitor network state to handle some situations 
by using BroadcastReceiver, when you open dialog box then change network state 
by turning on/off WiFi, {{onNetworkStateChange()}} (shown below) gets called 
while the dialog box is still open.

The BroadcastReceiver class looks like this.
{code}
    public class NetworkMonitor extends BroadcastReceiver {
        
        private TestCordovaActivity activity;
        
        public NetworkMonitor(TestCordovaActivity act) {
            this.activity = act;
        }
        
        @Override
        public void onReceive(Context context, Intent intent) {
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    activity.onNetworkStateChanged();
                }
            });        
        }
    }
{code}

And the {{onReceive()}} calls the lines shown below in our Activity class.
{code}
    public void onNetworkStateChanged(){
        terminateApp();
        setContentView(R.layout.my_view);
        initView();
    }
    
    public void terminateApp(){
        if(rootLayout != null){
            rootLayout.removeAllViews();
            rootLayout = null;
        }
        this.cwvCleanup();
    }
    
    public void cwvCleanup() {
        // cwv refers to CordovaWebView instance
        this.cwv.handlePause(true);
        this.cwv.handleDestroy();
        if (this.cwv != null) {
            this.cwv.removeAllViews();
            this.cwv.destroy();
            this.cwv = null;
        }
    }
    
    private void initView(){
        this.rootLayout = (LinearLayout)this.findViewById(R.id.layout_root);
        this.cwv = (CordovaWebView)findViewById(R.id.webView1);

        // some more initialisation here

        cwv.loadUrl(Config.getStartUrl());
    }
{code}

> 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)

Reply via email to