Android 从服务显示警报对话框时获取异常-无法添加窗口-令牌null不适用于应用程序

Android 从服务显示警报对话框时获取异常-无法添加窗口-令牌null不适用于应用程序,android,android-service,Android,Android Service,从服务显示警报对话框时获取异常 以下是我的服务类中的代码:我正在尝试显示AlertDialog 但我得到了一个错误:无法添加窗口——令牌null不适用于应用程序 我也附上我的日志快照到这个问题 if(!mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)&& !mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)){

从服务显示警报对话框时获取异常

以下是我的服务类中的代码:我正在尝试显示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();
            }

您只能在UI线程中执行UI操作,如显示
警报对话框。
由于您的
服务
未在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();
            }

            });
}

在创建gui时,您应该牢记以下几点:

  • 所有耗时的非gui工作都应该在后台完成(使用异步任务、服务、线程等)

  • GUI(如视图和其他图形对象)应始终从UIthreads创建和更新

  • 所以创建和显示对话框是一个UI工作,所以它应该在UI线程中。要在UI线程中运行任何代码,可以使用以下不同方法:

  • 您可以使用runOnUiThread在UI线程中运行一段代码
  • 您可以使用messageHandler
  • 您可以使用广播发送器和接收器
  • 我认为对于你的情况,Rununuithread是最好的,所以使用

    runOnUiThread (new Runnable() {
                    public void run ()
                    {
                        // WRITE YOUR PIECE OF CODE HERE TO UPDATE OR CREATE GUI.
                    }
                });
    
    为了理解这一概念,这可以帮助您:

    要创建广播,您可以使用:

    步骤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);
    
    步骤3:将广播从服务发送到显示对话框

    Intent intent = new Intent("create_dialog");
    intent.putExtra("dialog_data", data_object to display in dialog);
    SendBroadcast(intent);
    
    我希望这能对你有所帮助。

    试试这个

    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);
       }
    }
    

    我有这个问题,但现在已解决了
    ,如果您真的想从服务运行alertDialog,您应该将对话框配置为系统警报,并记住在AndroidManifest.xml中添加权限:

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

    使用SYSTEM\u ALERT\u 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();
    }
    

    您无法控制服务上的GUI,您可以做的最好的事情是启动一个新的活动并使其看起来像一个对话框。干杯@user2652394这必须是一个活动,还是仅仅是一个XML布局?是否存在启动服务的任何活动。runOnUiThread此方法在活动中。但我的服务并没有扩展活动。那个么我该如何处理这个问题呢?真正的问题是你们不能在非ui线程中创建你们的ui,所以你们需要将广播从你们的服务发送到你们的活动,在那个里你们可以创建你们的对话框。这个答案是不正确的。通常所谓的“UI线程”实际上只是应用程序的主线程。除非您启动自己的线程,或者您正在使用IntentService,否则您的服务和活动都将在主线程中运行。您还可以通过直接访问WindowManager直接从服务生成UI。这里的实际限制是,您需要设置对话框的窗口类型,以便从服务中显示它。Ziprox09给出了正确答案。runOnUiThread此方法正在运行。但我的服务并没有扩展活动。那么我该如何处理这个问题呢?frm您从何处开始服务..从接收方?看起来您对builder.setTitle()有一个额外的右括号,而builder.setPositiveButton.onClick()缺少一个右括号。如何将对话框配置为系统警报?
    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();
    }