简体   繁体   English

在android中显示来自非活动类的对话框警报

[英]Show dialog alert from a non-activity class in android

I want to show an Alert Dialog via AlertDialogManager class to a non-activity class DeviceAdminReceiverSample 's method onDisabled , but whenever I call alertDialog via that method it generates error with following text我想通过AlertDialogManager类向non-activityDeviceAdminReceiverSample的方法onDisabled显示警报对话框,但是每当我通过该方法调用alertDialog ,它都会生成错误并显示以下文本

Error错误

06-12 12:01:19.923: E/AndroidRuntime(468): FATAL EXCEPTION: main
06-12 12:01:19.923: E/AndroidRuntime(468): java.lang.RuntimeException: Unable to start           
receiver com.android.remotewipedata.DeviceAdminReceiverSample:   
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not   
for an application

I know the issue is with context thing but I don't know what to put there so that it work, I tried this , getApplicationContext() but all vain.我知道问题出在context但我不知道该放什么才能让它工作,我试过this getApplicationContext()但都是徒劳的。 My code for both classes is below我的两个类的代码如下

AlertDialogManager警报对话框管理器

public class AlertDialogManager {

public void showAlertDialog(Context context, String title, String message,
        Boolean status) {
    final AlertDialog alertDialog = new AlertDialog.Builder(context).create();
    alertDialog.setTitle(title);
    alertDialog.setMessage(message);

    if (status != null)
        alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                alertDialog.dismiss();
            }
        });
    alertDialog.show();
}

} }

DeviceAdminReceiverSample设备管理接收器示例

public class DeviceAdminReceiverSample extends DeviceAdminReceiver {
static final String TAG = "DeviceAdminReceiver";
AlertDialogManager alert = new AlertDialogManager();

/** Called when this application is no longer the device administrator. */
@Override
public void onDisabled(Context context, Intent intent) {
    super.onDisabled(context, intent);
    Toast.makeText(context, R.string.device_admin_disabled,
            Toast.LENGTH_LONG).show();
    // intent.putExtra("dialogMessage", "Device admin has been disabled");
    // intent.setClass(context, DialogActivity.class);
    // intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    // context.startActivity(intent);
    alert.showAlertDialog(context, "Alert",
            "Device admin has been disabled", true);
}

Just add this before your alertDialog.show();只需在您的alertDialog.show();之前添加它alertDialog.show();

alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

or try following if above didn't work:或者如果以上不起作用,请尝试以下操作:

alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_PANEL); 

and use this permission:并使用此权限:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

The problem is ' You can show AlertDialogs from Activity only '.问题是“ You can show AlertDialogs from Activity only ”。 This is not an issue of context.这不是上下文的问题。

Although this is not a good idea to show dialog from receiver (better is to use Notification), But if you want to do so you can create an Activity as dialog and show虽然从接收器显示对话框不是一个好主意(最好使用通知),但是如果你想这样做,你可以创建一个Activity 作为对话框并显示

If you always want to get the current activity from anywhere in the app you can register an ActivityLifecycleCallback on your Application instance.如果您总是想从应用程序的任何地方获取当前活动,您可以在您的应用程序实例上注册一个 ActivityLifecycleCallback。

Here's an untested implementation that might get you closer.这是一个未经测试的实现,可能会让你更接近。

public class TestApp extends Application {

    private WeakReference<Activity> mActivity = null;

    @Override
    public void onCreate() {
        super.onCreate();
        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                mActivity = new WeakReference<Activity>(activity);
            }

            @Override
            public void onActivityDestroyed(Activity activity) {
                mActivity.clear();
            }

            /** Unused implementation **/
            @Override
            public void onActivityStarted(Activity activity) {}

            @Override
            public void onActivityResumed(Activity activity) {}
            @Override
            public void onActivityPaused(Activity activity) {}

            @Override
            public void onActivityStopped(Activity activity) {}

            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
        });
    }

    public Activity getCurrentActivity() {
        return mActivity.get();
    }

}

Then to use this throughout your app you would do some call like this ...然后在你的应用程序中使用它,你会做一些这样的调用......

Activity activity = ((TestApp)getApplicationContext()).getCurrentActivity(); 

The advantages are you can always keep track of your current activity, however its a little too overkill for just handling Dialogs from within the Activity.优点是您可以始终跟踪当前的活动,但是对于仅从 Activity 中处理 Dialogs 而言,它有点过于矫枉过正。

call this method in activity class在活动类中调用此方法

public static void showAlert(Activity activity, String message) {

        TextView title = new TextView(activity);
        title.setText("Title");
        title.setPadding(10, 10, 10, 10);
        title.setGravity(Gravity.CENTER);
        title.setTextColor(Color.WHITE);
        title.setTextSize(20);

        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
        // builder.setTitle("Title");
        builder.setCustomTitle(title);
        // builder.setIcon(R.drawable.alert_36);

        builder.setMessage(message);

        builder.setCancelable(false);
        builder.setNegativeButton("OK", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                dialog.cancel();

            }

        });

        AlertDialog alert = builder.create();
        alert.show();
    }

As AJAY suggested, the best way is to work with the 'Activity' in parameter instead of using the 'context'. 正如AJAY所建议的,最好的方法是使用参数中的“活动”而不是使用“上下文”。

In your personal class, just ask for the activity in its constructor as a mandatory parameter => public void constructorOfTheClass(Activity activity){...}. 在您的个人课堂中,只需在其构造函数中要求提供活动作为强制性参数=> public void constructorOfTheClass(Activity activity){...}。

When you call the constructor in your Activity, just indicate this parameter and you'll be able to work with it inside the class directly. 当您在Activity中调用构造函数时,只需指出此参数,您就可以直接在类中使用它。

Then you can use this 'activity' information in your AlertDialog method within your class as SUNIL noticed to be prompted correctly in the desired Activity. 然后,您可以在类中的AlertDialog方法中使用此“活动”信息,因为SUNIL会在所需的Activity中正确提示。

Hope it helps... and be sure it will work ! 希望它能对您有所帮助,并确保它会起作用! ;o) ; o)

Here's what I made and use:这是我制作和使用的:

myDialog.java:我的Dialog.java:

import android.app.Activity;
import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

public class myDialog {
    private Activity mActivity;

    myDialog(Activity a) {
        this.mActivity = a;
    }

    @SuppressWarnings("InflateParams")
    public void build(String title, String msg) {
        LayoutInflater inflater = LayoutInflater.from(mActivity);
        View subView = inflater.inflate(R.layout.dialog_box_text, null);
        final TextView message = subView.findViewById(R.id.message);
        message.setText(msg);
        AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
        builder.setTitle(title);
        builder.setView(subView);
        builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        AlertDialog alert = builder.create();
        alert.show();
    }
}

dialog_box_text.xml: dialog_box_text.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:weightSum="1"
    android:orientation="horizontal">
    <TextView
        android:id="@+id/message"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="  "
        android:maxLines="1"
        android:textColor="@color/colorBlack" />
</LinearLayout>

Example code:示例代码:

public class MainActivity extends AppCompatActivity {
    private myDialog md;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        md = new myDialog(this);

...

        md.build("Title", "Message");

You can define a public Context var in the MainActivity with initial value (this);您可以在 MainActivity 中定义一个具有初始值 (this) 的公共上下文变量; As show here:如图所示:

public class MainActivity< alertdail > extends AppCompatActivity {

    ////////////////////////////////////////////////////////////
    //Public var refers to Main Activity:
    Context mainActivity = this;
    ////////////////////////////////////////////////////////////

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate ( savedInstanceState );
        setContentView ( R.layout.activity_main );
        AlertDialogManager alert  =new AlertDialogManager ();
alert.showAlertDialog ( this,"Title","Message",true );


     }


    public class AlertDialogManager {

        public void showAlertDialog(Context context, String title, String message,
                                    Boolean status) {
            final AlertDialog alertDialog = new AlertDialog.Builder ( mainActivity ).create ( );
            alertDialog.setTitle ( title );
            alertDialog.setMessage ( message );

            if (status != null)
                alertDialog.setButton ( "OK", new DialogInterface.OnClickListener ( ) {
                    public void onClick(DialogInterface dialog, int which) {
                        alertDialog.dismiss ( );
                    }
                } );
            alertDialog.show ( );
        }

        public void showAlertDialog(Context c) {
        }
    }


    public class DeviceAdminReceiverSample extends DeviceAdminReceiver {
        static final String TAG = "DeviceAdminReceiver";
        AlertDialogManager alert = new AlertDialogManager ( );

        /**
         * Called when this application is no longer the device administrator.
         */
        @Override
        public void onDisabled(Context context, Intent intent) {
            super.onDisabled ( context, intent );
            Toast.makeText ( context, R.string.device_admin_disabled,
                    Toast.LENGTH_LONG ).show ( );
            // intent.putExtra("dialogMessage", "Device admin has been disabled");
            // intent.setClass(context, DialogActivity.class);
            // intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            // context.startActivity(intent);
            alert.showAlertDialog ( context, "Alert",
                    "Device admin has been disabled", true );
        }
    }
}

Here's a quick method of properly performing this task that has done the job for me.这是正确执行此任务的快速方法,它为我完成了这项工作。 Basically, what you would do is just create a new thread.基本上,您要做的就是创建一个新线程。


  1. Declare a public and static variable with a type that matches the original activity class.声明一个类型与原始活动类匹配的公共和静态变量。

    public static Activity1 activity;

Activity1 is the class that the variable resides in. Activity1 是变量所在的类。


  1. Upon calling the method onCreate();调用方法onCreate(); , set the variable to be equal to the context of the activity, otherwise known as this . ,将变量设置为等于活动的上下文,也称为this

Example:例子:

@Override 
    protected void onCreate( Bundle savedInstanceState ) {
    super.onCreate( savedInstanceState );
    activity = this;
}


3. Since we now have the context of the activity, we can use it to create a function with an alert dialog by using the runOnUiThread(); 3. 由于我们现在有了活动的上下文,我们可以使用它通过runOnUiThread();来创建一个带有警报对话框的函数runOnUiThread(); method inside of the function that will call the alert dialog. 将调用警报对话框的函数内部的方法。 We would use a new Runnable() for the runnable action required for runOnUiThread(); 对于runOnUiThread();所需的可运行操作,我们将使用new Runnable() runOnUiThread(); , and to have the alert dialog actually open, we would override the run function of a runnable item and place the code for the alert dialog in there. ,并且要真正打开警报对话框,我们将覆盖可运行项的运行函数并将警报对话框的代码放在那里。

Example function:示例函数:

 public static void exampleDialog(){ Activity1.activity.runOnUiThread(new Runnable){ @Override public void run(){ //alert dialog code goes here. For the context, use the activity variable from Activity1. } } }

Hope this helps :)希望这可以帮助 :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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