在系统重启后的广播接收器中显示警报对话框

36

大家好,我正在尝试在广播接收器中系统重启后显示一个警报对话框。 我已在清单文件中添加了接收器并调用了所需的权限,但在显示对话框时出现错误。 请问如何正确实现此功能?.. 谢谢

我的代码:

public void onReceive(final Context context, Intent intent) {
    Log.d(TAG, "received boot completed broadcast receiver... starting settings");


    String settings = context.getResources().getString(R.string.restart_setting);
        String yes = context.getResources().getString(R.string.Settings);
        String no = context.getResources().getString(R.string.Cancel);

              final AlertDialog.Builder builder = new AlertDialog.Builder(context);
                builder.setMessage(settings)
                       .setCancelable(false)
                       .setPositiveButton(yes, new DialogInterface.OnClickListener() {
    public void onClick(@SuppressWarnings("unused") final DialogInterface dialog, @SuppressWarnings("unused") final int id) 
   Intent config = new Intent(context, WeatherConfigure.class)
     context.startActivity(config);

    }
 })
    .setNegativeButton(no, new DialogInterface.OnClickListener() {
        public void onClick(final DialogInterface dialog, @SuppressWarnings("unused") final int id) {
             dialog.cancel();
        }
    });
  final AlertDialog alert = builder.create();
  alert.show();

    }

我得到了以下日志错误:

01-07 01:42:01.559: ERROR/AndroidRuntime(2004): Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application

01-07 01:42:01.559: ERROR/AndroidRuntime(2004): at android.view.ViewRoot.setView(ViewRoot.java:548)

01-07 01:42:01.559: ERROR/AndroidRuntime(2004):at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)

01-07 01:42:01.559: ERROR/AndroidRuntime(2004): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)

01-07 01:42:01.559: ERROR/AndroidRuntime(2004):at android.app.Dialog.show(Dialog.java:288)

01-07 01:42:01.559: ERROR/AndroidRuntime(2004):at com.MuaaApps.MyWeatherUpdate.myWeatherBroadcastReceiver.onReceive(MyWeatherBroadcastReceiver.java:59)

01-07 01:42:01.559: ERROR/AndroidRuntime(2004): at android.app.ActivityThread.handleReceiver(ActivityThread.java:1994)

在这种情况下,Toast消息或通知可能更合适,而不是在用户打开手机时用警报对话框轰炸用户。 - cottonBallPaws
@littleFluffyKitty,是的我懂你的意思。我正在尝试不同的情况,以找出哪种情况会给用户带来良好的体验,但必须承认你提出的通知建议非常有吸引力。我没有想到过。谢谢。 - irobotxx
7个回答

51
问题在于你正在尝试从一个广播接收器(BroadcastReceiver)中显示一个AlertDialog,这是不允许的。你不能从一个广播接收器(BroadcastReceiver)中显示AlertDialog,只有活动(Activity)才能显示对话框。

你应该做一些其他的事情,让BroadcastReceiver在启动时启动,并启动一个活动(Activity)来显示对话框。

这里有一篇博客文章详细介绍了此问题。

编辑:

以下是我建议的做法。从你的BroadcastReceiver开始一个带有AlertDialogActivity,如下所示...

public class NotifySMSReceived extends Activity 
{
    private static final String LOG_TAG = "SMSReceiver";
    public static final int NOTIFICATION_ID_RECEIVED = 0x1221;
    static final String ACTION = "android.provider.Telephony.SMS_RECEIVED";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        IntentFilter filter = new IntentFilter(ACTION);
        this.registerReceiver(mReceivedSMSReceiver, filter);
    }

    private void displayAlert()
    {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage("Are you sure you want to exit?").setCancelable(
            false).setPositiveButton("Yes",
            new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    dialog.cancel();
                }
            }).setNegativeButton("No",
            new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    dialog.cancel();
                }
            });
        AlertDialog alert = builder.create();
        alert.show();
    }

    private final BroadcastReceiver mReceivedSMSReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            if (ACTION.equals(action)) 
            {
                //your SMS processing code
                displayAlert();
            }
        }
    }
}

正如您在这里看到的,我从来没有调用setContentView()。这是因为活动将具有透明视图,只有警报对话框会显示。

好的。谢谢你澄清了这一点。那么这是否意味着无法从广播接收器中创建警报对话框,还是仅限于这种特定类型的广播? - irobotxx
感谢您的时间。稍后使用通知。 - irobotxx
1
触发事件后,我想显示对话框,如何实现? - AndroidOptimist
4
谢谢您的回答,但该活动有黑色背景。 - Maveňツ
我该如何创建一个活动(Activity),并在警告框关闭按钮被点击后关闭它? - Mahdi

29

在BroadcastReceiver中无法使用对话框,因此最好从BroadcastReceiver调用活动以打开对话框。

请将以下代码添加到您的onReceive函数中:

@Override
public void onReceive(Context context, Intent intent) 
{
    Intent i = new Intent(context, {CLASSNAME}.class); 
    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
    context.startActivity(i);
}

将{CLASSNAME}填入对话活动中,这是我的对话活动:

package com.example.mbanking;

import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;


// ALERT DIALOG
// Sources : http://techblogon.com/alert-dialog-with-edittext-in-android-example-with-source-code/

public class AlertDialogActivity extends Activity 
{

@Override
protected void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);

    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder
        .setTitle("Test")
        .setMessage("Are you sure you want to exit?")
        .setCancelable(false)
        .setPositiveButton("Yes", new DialogInterface.OnClickListener() 
        {
            public void onClick(DialogInterface dialog, int id) 
            {
                dialog.cancel();
            }
        })
        .setNegativeButton("No", new DialogInterface.OnClickListener() 
        {
            public void onClick(DialogInterface dialog, int id) 
            {
                dialog.cancel();
            }
        });
    AlertDialog alert = builder.create();
    alert.show();
}
}

我从哪里得到了答案?在这里:如何在Android广播接收器中使用警报对话框?感谢Femi!我只是传递好消息:D


2
@Bhimbim,它不能工作,我不知道为什么人们会对这个答案点赞。 - M.ArslanKhan

7
这里有一篇关于如何实现的文章,您可以从这里获取源代码。
您不能直接从广播接收器中显示对话框,必须使用一个Activity。此外,为了接收ACTION_BOOT_COMPLETED,您的活动必须首先由用户或另一个应用显式启动(有关更多信息,请参见google应用程序停止状态)。
基本上,要实现所需的功能,您需要执行以下操作:
1.创建显示对话框的透明活动。 2.创建接收ACTION_BOOT_COMPLETED并启动您的活动的BroadcastReceiver。 3.在清单中注册您的广播接收器并获取适当的权限。
此外,问题提供了如何创建透明活动的更多信息。

这是一篇很棒的文章。谢谢,但我想在从命令提示符触发接收器后显示对话框。如何实现这一点,因为这里对话框首先会显示出来。 - AndroidOptimist
据我所知,您的目标仍然是从“BroadcastReceiver”中显示对话框。唯一的区别是,您的接收器由另一个意图触发(而不是“android.intent.action.BOOT_COMPLETED”),对吗? - Nikolai Samteladze
我认为您只需更改 BroadcastReceiver<intent-filter> 中的 <action> 属性,以指向所需的意图。 - Nikolai Samteladze

7
最好的方法是创建一个活动并将其“Theme”属性设置为“Theme.Translucent”。
 <activity
        android:name=".MyAlertDialog"
        android:label="@string/title_activity_alert_dialog"
        android:launchMode="singleInstance"
        android:theme="@android:style/Theme.Translucent" >
    </activity>

在您的活动中创建一个提示对话框:

public class MyAlertDialog extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE); //hide activity title
    setContentView(R.layout.activity_my_alert_dialog);

    AlertDialog.Builder Builder=new AlertDialog.Builder(this)
            .setMessage("Do You Want continue ?")
            .setTitle("exit")
            .setIcon(android.R.drawable.ic_dialog_alert)
            .setNegativeButton(R.string.No, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    MyAlertDialog.this.finish();
                }
            })
            .setPositiveButton(R.string.Yes,null);
    AlertDialog alertDialog=Builder.create();
    alertDialog.show();

}

}

并且在广播接收器中:

 @Override
public void onReceive(Context context, Intent intent) {

    Intent i=new Intent(context.getApplicationContext(),MyAlertDialog.class);
    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(i);

}
}

4

这可能是一个旧的问题,已经有答案了,但是答案并不是很有帮助。

在onReceive()方法中,你不能启动弹出对话框。 BroadcastReceiver

相反,你可以使用一个被设置为对话框主题的活动来代替对话框或弹窗。

 <activity 
   android:taskAffinity=""
   android:name=".activity.CallActivity"
   android:label="@string/app_name"
   android:theme="@style/AppTheme.Dialog" />

请注意,我在(AndroidManifest.xml)的块中添加taskAffinity 然后您就可以像常规活动一样使用它。
Intent intentPhoneCall = new Intent(context, CallActivity.class);
intentPhoneCall.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intentPhoneCall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intentPhoneCall);

希望这能有所帮助。愉快地编码!

这对我也非常有效。谢谢!我们最终使用了自己现有的对话框主题,效果非常好。颜色和背景都正确无误,活动背景是透明的,动画效果是淡入淡出,而不是典型的滑动或其他启动新活动时看到的效果。 - Joshua Pinter

1
  1. 从广播接收器显示对话框是不可能的。
  2. 我们应该只从活动中显示对话框。
  3. 但是,如果您的应用程序上下文仅具有广播接收器,则我们应该将活动启动为"FLAG_ACTIVITY_NEW_TASK",然后它会创建堆栈。
  4. 如果我们使用此标志“FLAG_ACTIVITY_NEW_TASK”启动活动,则无法从堆栈中删除。

  5. 因此,在关闭应用程序后,我们尝试从堆栈中启动应用程序,它会显示相同的Activity,因为此Activity具有标志“FLAG_ACTIVITY_NEW_TASK”,所以它不应创建新实例并使用现有实例。

但是我们希望仅显示一次对话框。 为此,我们需要通过编程进行处理。

 if (count == 0) {
            mBuilder = new Dialog(this);
            mMsg = getIntent().getStringExtra(AlarmSchedulerUtils.EXTRA_MSG);
            Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
            mRingTome = RingtoneManager.getRingtone(ReminderDialog.this, notification);
            mRingTome.play();
            count++;
            showReminderDialog();
        } else {
            Intent intent=new Intent(ReminderDialog.this,SplashActivity.class);
            startActivity(intent);
            finish();
        }

这对我有用。


-1

在调用意图时,在onReceive中,您只需要将其放入延迟为400ms的处理程序中。对我来说,这个方法非常有效。

@Override
public void onReceive(Context context, Intent intent) 
{
      new Handler().postDelayed(new Runnable() {
                   @Override
                    public void run() {
        
                        Intent i = new Intent(context, {CLASSNAME}.class); 
                        i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
                        context.startActivity(i);
                   }
               }, 400);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接