1

I have a class inheriting from dialogfragment:

import org.xwalk.core.*;
// ...

public class WebViewDialogFragment extends DialogFragment {
    private XWalkView webView;
    public static final String LOG_TAG = "WebViewDialogFragment";
    
    private String url;
    private WebViewJavascriptInterface javaScriptInterface;
    
    // The constructor I use to set the url.
    public WebViewDialogFragment(String url, WebViewJavascriptInterface javascriptInterface) {
        this.url = url;
    }

    public WebViewDialogFragment() {
        Log.d(LOG_TAG, "WebViewDialogFragment empty constructor was called.");
    }
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(LOG_TAG, "Setting fullscreen mode");
        setStyle(DialogFragment.STYLE_NORMAL, R.style.SagoBizWebViewFullScreenTheme);
    }
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.d(LOG_TAG, "Setting Xwalkview");
        webView = new XWalkView(getActivity(), getActivity());
        webView.clearCache(true);
        Log.d(LOG_TAG, "Loading the url: " + url);
        webView.load(url, null);
        return webView;
    }
    
    @Override 
    public void onStart() {
        super.onStart();
        
        Dialog dialog = getDialog();
        if (dialog != null) {
            int width = ViewGroup.LayoutParams.MATCH_PARENT;
            int height = ViewGroup.LayoutParams.MATCH_PARENT;
            dialog.getWindow().setLayout(width, height);
        }
    }
    
    @Override
    public void onPause() {
        super.onPause();
        if (webView != null) {
            webView.pauseTimers();
            webView.onHide();
        }
    }   
    
    @Override
    public void onResume() {
        super.onResume();
        if (webView != null) {
            webView.resumeTimers();
            webView.onShow();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (webView != null) {
            webView.onDestroy();
        }
    }
    
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (webView != null) {
            webView.onActivityResult(requestCode, resultCode, data);
        }
    }
}

And I have another class who has a member of type WebViewDialogFragment:

public class WebView {
    protected static final String DIALOG_FRAGMENT_TAG = "WebViewDialogFragment";
    
    protected Activity activity;
    protected String dialogFragmentTag = DIALOG_FRAGMENT_TAG;   
    protected WebViewDialogFragment webViewDialogFragment;
        
    public WebView(Activity activity) {
        this.activity = activity;
    }

    public void display(final String url) {
        Log.d("TEST", "WebView display");
        
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                webViewDialogFragment = new WebViewDialogFragment(url, getWebViewJavascriptInterface());
                
                if (webViewDialogFragment != null) {
                    FragmentManager fm;
                    fm = activity.getFragmentManager();
                    Log.d("TEST", "Showing webview");
                    webViewDialogFragment.show(fm, WebView.this.dialogFragmentTag);
                } else {
                    Log.e("TEST", "webViewDialogFragment is null");
                }
            }
        });
    }

}

I call the display(String url) method of webview to show the dialog that is going to show the webview.

Using @javascriptinterface attribute I have created a bridge between the webview javascript and the native java so that i may open external browser (or store) from within the dialogfragment. The javascript interface has a method like so:

@JavascriptInterface
public void urlExternalAction(string url) {
    Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
    webView.activity.startActivity(browserIntent);
}

The problem is that after opening the external activity (from the dialog fragment), when you come back to my app (either by pressing the back button or by task switching) the app crashes:

AndroidRuntime java.lang.RuntimeException: Unable to start activity ComponentInfo{com.myapp.Test/com.myapp.testActivity}:

android.app.Fragment$InstantiationException: Unable to instantiate fragment com.myapp.Test.WebViewDialogFragment: make sure class name exists, is public, and has an empty constructor that is public

I solved the crash by adding an empty constructor to webviewdialogfragment, but that is not what i want. I want a dialogfragment that preserves its state.

Could you help me modify the code to resolve the issue?

Note that the parent activity's onCreate is not in my control and I prefer not to modify it.

Thank you and I look forward to your input. Let me know if a part needs a better explanation.

Community
  • 1
  • 1
Aaron Azhari
  • 987
  • 1
  • 10
  • 24

1 Answers1

1

Fragments and Activities need one empty contructor, and, if provided, that must be the only constructor. If you want to initialize a fragment with some data, you must create the fragment and use the setArguments method before adding the fragment to the fragment manager. Look at this question.

Community
  • 1
  • 1
Mimmo Grottoli
  • 5,758
  • 2
  • 17
  • 27