简体   繁体   中英

Alert Dialog crashes Android test - “Can't create handler inside thread that has not called Looper.prepare()”

    AlertDialog.Builder builder = new AlertDialog.Builder(activity);
    builder.setMessage(message)
            .setCancelable(false)
            .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    login(activity);
                }
            })
            .setNegativeButton("No", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {

                    dialog.cancel();
                    activity.finish();
                }
            });
    AlertDialog alert = builder.create(); // Crash
    alert.show();

The app runs fine and shows the alert dialog when I run it normally, but when I run it in an instrumented test, it crashes in builder.create at the first line:

        final AlertDialog dialog = new AlertDialog(P.mContext, mTheme);

with this exception:

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

This closes the app and then the test fails because there isn't any activity:

android.support.test.espresso.NoActivityResumedException: No activities in stage RESUMED. Did you forget to launch the activity. (test.getActivity() or similar)?

This is a thread problem, but that's not what I expected based on an answer here :

To verify if dialog appears you can simply check if View with a text that present inside the dialog is shown:

onView(withText("dialogText")).check(matches(isDisplayed()));

I don't understand how I'm supposed to check if the text is displayed if the app crashes before the dialog is created.

EDIT:

    mActivityRule.launchActivity(intent);

    mActivityRule.getActivity().showOptionDialog();

    onView(withText(mActivityRule.getActivity().getString(R.string.dialogText))).check(matches(isDisplayed()));

A couple things that will likely help you...

  1. Calling mActivityRule.getActivity().showOptionDialog(); in an Espresso test is not the 'Espresso' way. Unless your test is properly annotated, it's not running on the UI Thread, so this is a case where you are calling something that should be done on the UI Thread from the Instrumentation Thread. You can get around this by doing something like:

    rule.runOnUiThread(new Runnable() { @Override public void run() { mActivityRule.getActivity().showOptionDialog(); } });

Doing this may require you to build out your own synchronization logic to make sure that future Espresso statements are not run before this occurs.

The better way to test this using Espresso is to use an onView(XXX).perform(click()) on the UI control that would normally invoke showOptionsDialog() .

  1. Additionally, you don't need to resolve the string that you pass to withText() yourself, you can just use the string resource id, but this isn't the cause of the issue that you are seeing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM