从服务中显示警报对话框时遇到异常 - 无法添加窗口 - 令牌为空不是应用程序。

7

从服务中显示警告对话框时出现异常。

以下是我Service类中的代码:我试图显示一个AlertDialog。

但我遇到了错误:无法添加窗口--令牌null不是应用程序的令牌。

我还附加了我的日志快照到这个问题。

 if(!mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)&& !mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)){

                Log.d("TrackingService","H: Exception after this");

                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setMessage("Your GPS seems to be disabled, do you want to enable it?")
                .setCancelable(false)
                .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                    public void onClick(final DialogInterface dialog, final int id) {
                        startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
                    }
                })
                .setNegativeButton("No", new DialogInterface.OnClickListener() {
                    public void onClick(final DialogInterface dialog,  final int id) {
                        dialog.cancel();
                    }
                });
                AlertDialog alert = builder.create();
                alert.show();
            }

enter image description here


2
你无法在服务中控制GUI,最好的方法是启动一个新的Activity并使其看起来像对话框。干杯! - user2652394
@user2652394 这必须是一个活动吗?还是只能是一个XML布局? - Dawood Awan
你的服务是否从任何活动开始? - Bharat Sharma
5个回答

22

我曾遇到这个问题,但现在已经被解决了。如果你想要从一个服务中真正地运行一个弹出对话框,你应该将对话框配置为系统警报,并记得在你的AndroidManifest.xml文件中添加权限:

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

/这是示例代码:

AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
builder.setTitle("Test dialog");
builder.setIcon(R.drawable.icon);
builder.setMessage("Content");
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int whichButton) {
        //Do something
        dialog.dismiss();
   }
});
builder.setNegativeButton("Close", new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int whichButton) {
        dialog.dismiss();
    }
});
AlertDialog alert = builder.create();
alert.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
alert.show();

1
看起来你多加了一个括号在builder.setTitle()中,而且builder.setPositiveButton.onClick()缺少了一个闭合括号。 - jakeneff
如何将对话框配置为系统警报? - Muhammad Dyas Yaskur

4

在创建 GUI 时,需要注意以下几点:

  1. 所有耗时的非 GUI 工作都应该在后台完成(使用 asyncTask、Services、Threads 等)。

  2. GUI(如视图和其他图形对象)应始终从 UI 线程创建和更新。

因此,创建和显示对话框是 UI 工作,因此应该在 UI 线程中执行。要在 UI 线程中运行任何代码,可以使用不同的方法,例如:

  1. 您可以使用 runOnUiThread 在 UI 线程中运行一段代码。
  2. 您可以使用 messageHandler。
  3. 您可以使用广播发送器和接收器。

我认为对于您的情况,runOnUiThread 是最好的选择,因此请使用它。

runOnUiThread (new Runnable() {
                public void run ()
                {
                    // WRITE YOUR PIECE OF CODE HERE TO UPDATE OR CREATE GUI.
                }
            });

为了理解这个概念,可以参考以下网站:

http://developer.android.com/guide/components/processes-and-threads.html

创建广播的步骤如下:

步骤1:在启动服务的活动中创建一个广播接收器。

   BroadcastReceiver receiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals("create_dialog")) {
                // create your dialog here.
            }
        }
    };

步骤2:在创建广播接收器后注册您的接收器。
IntentFilter filter = new IntentFilter("create_dialog");
registerReceiver(receiver, filter);

第三步:从您的服务中发送广播以显示对话框。
Intent intent = new Intent("create_dialog");
intent.putExtra("dialog_data", data_object to display in dialog);
SendBroadcast(intent);

我希望这可以帮助你。


1
runOnUiThread这个方法在Activity中。但是我的服务并没有继承Activity。那我该怎么处理呢? - Dawood Awan
1
真正的问题是你不能在非 UI 线程中创建 UI,因此你需要从服务发送广播到活动中,在那里你可以创建对话框。 - Bharat Sharma
1
这个答案是不正确的。通常所说的“UI线程”实际上只是应用程序的主线程。除非您启动自己的线程,或者您正在使用IntentService,否则您的服务和活动都将在主线程中运行。您也可以通过直接访问WindowManager从服务中直接生成UI。这里的实际限制是,您需要将对话框的窗口类型设置为从服务显示它。Ziprox09给出了正确的答案。 - simonp

2

不要创建新的透明活动,使用SYSTEM_ALERT_WINDOW权限来实现此功能。

public void onReceive(Context ctx, Intent intent) {
    LayoutInflater inflater = (LayoutInflater)ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View popup = inflater.inflate(R.layout.mypopup, null, false);
    CustomDialog dialog = new CustomDialog(ctx, popup );

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

    dialog.getWindow().getAttributes().windowAnimations = R.style.PauseDialogAnimation;
    dialog.show();
}

1
尝试一下。
AlertDialog.Builder alertDialog  = new AlertDialog.Builder(myContext);

编辑。

对于缺少评论,将启动您的服务的上下文(例如实例)放入服务中并使用它。

class SomeService 
{   
     private final Context myContext;
     public WebService(Context myContext) 
     {

        this.myContext= myContext;
     }

   public void showDialog()
   {
        AlertDialog d = new AlertDialog.Builder(myContext);
   }
}

0

您可以执行 UI 相关的操作,例如在 UI 线程中显示 AlertDialog

由于您的 service 不在 UI 线程上运行,因此会导致此异常。

尝试使用 runOnUiThread 方法来显示提示:

if(!mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)&& !mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)){

            runOnUiThread(new Runnable(){

            public void run(){
                Log.d("TrackingService","H: Exception after this");

                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setMessage("Your GPS seems to be disabled, do you want to enable it?")
                            .setCancelable(false)
                            .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                                public void onClick(final DialogInterface dialog, final int id) {
                                    startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
                                }
                            })
                            .setNegativeButton("No", new DialogInterface.OnClickListener() {
                                public void onClick(final DialogInterface dialog,  final int id) {
                                    dialog.cancel();
                                }
                            });
               AlertDialog alert = builder.create();
               alert.show();
            }

            });
}

runOnUiThread这个方法在Activity中。但是我的服务并没有扩展Activity。那么我该怎么处理呢? - Dawood Awan
你的服务从哪里开始?从接收器开始吗? - bakriOnFire

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