【问题标题】:Launch popup message from service从服务启动弹出消息
【发布时间】:2019-06-13 16:14:19
【问题描述】:

当从服务器接收到消息时,我需要从服务启动弹出消息。我可以使用toast 并且当应用程序在前台或后台时显示消息,这正是我需要的,除了我需要捕获对消息的响应,所以toastnotification 对我不起作用.我有以下代码:

public async void showMessage(string message)
{

    Android.App.AlertDialog.Builder alert = new Android.App.AlertDialog.Builder(this);
    alert.SetTitle("Message");
    alert.SetMessage(message);
    alert.SetPositiveButton("OK", (senderAlert, args) => {
        // I need to construct a number of buttons to capture user response, not just "Ok"
    });
    Dialog dialog = alert.Create();
    dialog.Window.SetType(Android.Views.WindowManagerTypes.SystemAlert);
    dialog.Show();

    //ToastLength duration = ToastLength.Short;

    //var toast = Toast.MakeText(context, message, duration);
    //toast.Show();
 }

从服务中的这一行调用该方法:

mHandler.Post(() => { showMessage(message); });

我已在清单中设置了所有适当的权限。当我运行代码时出现错误:

Exception:

Android.Views.WindowManagerBadTokenException

这是我的服务代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Acr.UserDialogs;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Support.V4.App;
using Android.Views;
using Android.Widget;
using Java.Lang;
using Java.Util.Concurrent;
using Microsoft.AspNet.SignalR.Client;
using Microsoft.AspNet.SignalR.Client.Transports;


namespace MyAndroid
{
    [Service]
    public class SignalRSrv : Service
    {
        private bool InstanceFieldsInitialized = false;
        private string username = "";
        private string firstname = "";
        private string lastname = "";
        private string company= "";
        private string department = "";
        private string section = "";

        private void InitializeInstanceFields()
        {
            mBinder = new LocalBinder(this);
        }

        private Handler mHandler; // to display any received messages
        private IBinder mBinder; // Binder given to clients
        private SignalRSingleton mInstance;

        public SignalRSrv()
        {
            if (!InstanceFieldsInitialized)
            {
                InitializeInstanceFields();
                InstanceFieldsInitialized = true;
            }

        }

        public override void OnCreate()
        {
            base.OnCreate();
            mInstance = SignalRSingleton.getInstance();
            mHandler = new Handler(Looper.MainLooper);
        }

        public override void OnDestroy()
        {
            base.OnDestroy();
        }


        public override IBinder OnBind(Intent intent)
        {

            //binder = new LocalBinder(this);
            User MyUser = new User("", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "");
            Bundle bundlee = intent.GetBundleExtra("TheBundle");
            MyUser = bundlee.GetParcelable("MyUser") as User;

            username = MyUser.Username;
            firstname = MyUser.Firstname;
            lastname = MyUser.Lastname;
            company = intent.GetStringExtra("theSelectedCompany");
            department = intent.GetStringExtra("theSelectedDepartment");
            section = intent.GetStringExtra("theSelectedSection");

            startSignalR();
            return mBinder;
        }

        private void startSignalR()
        {
            mInstance.setmHubConnection(username, firstname,lastname,company,department,section);
            mInstance.setHubProxy();

            try
            {
                // Connect the client to the hup
                mInstance.mHubConnection.Start();

                mInstance.mHubProxy.On("broadcastMessage", (string platform, string message) =>
                {
                    mHandler.Post(() => { showMessage(message); });
                });

            }
            catch (System.Exception e) when (e is InterruptedException || e is ExecutionException)
            {
                //opps

                var x = 1;
                return;
            }
        }

        public async void showMessage(string message)
        {


            try
            {
                Android.App.AlertDialog.Builder alert = new Android.App.AlertDialog.Builder(this);
                alert.SetTitle("Message");
                alert.SetMessage(message);
                alert.SetPositiveButton("OK", (senderAlert, args) => {
                    Toast.MakeText(this, "Ok button Tapped!", ToastLength.Short).Show();
                });
                Dialog dialog = alert.Create();
                dialog.Window.SetType(Android.Views.WindowManagerTypes.Toast);
                dialog.Show();

            }
            catch (System.Exception e)
            {
                var s = e.Message;
            }


            //AlertDialog alert = builder.Create();

            //alert.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
            //alert.show();

        }

        public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
        {

            User MyUser = new User("", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "");
            Bundle bundlee = intent.GetBundleExtra("TheBundle");
            MyUser = bundlee.GetParcelable("MyUser") as User;

            username = MyUser.Username;
            firstname = MyUser.Firstname;
            lastname = MyUser.Lastname;
            company = intent.GetStringExtra("theSelectedCompany");
            department = intent.GetStringExtra("theSelectedDepartment");
            section = intent.GetStringExtra("theSelectedsection");

            startSignalR();
            RegisterForegroundService();

            // This tells Android not to restart the service if it is killed to reclaim resources.
            return StartCommandResult.Sticky;
        }

        void RegisterForegroundService()
        {
            var notification = new NotificationCompat.Builder(this)
                .SetContentTitle(Resources.GetString(Resource.String.app_name))
                .SetContentText(Resources.GetString(Resource.String.notification_text))
                .SetSmallIcon(Resource.Drawable.alert_box)
                .SetOngoing(true)
                .Build();


            // Enlist this instance of the service as a foreground service
            StartForeground(Constants.SERVICE_RUNNING_NOTIFICATION_ID, notification);
        }

    }
    public class LocalBinder : Binder
    {
        private readonly SignalRSrv outerInstance;

        public LocalBinder(SignalRSrv outerInstance)
        {
            this.outerInstance = outerInstance;
        }

        public virtual SignalRSrv Service
        {
            get
            {
                // Return this instance of SignalRService so clients can call public methods
                return outerInstance;
            }
        }
    }
}

我的清单:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="OML_Android.OML_Android" android:installLocation="auto">
<uses-sdk android:minSdkVersion="26" android:targetSdkVersion="28" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" />
<service android:name=".SignalRSrv" android:label="Messenger" android:enabled="true"></service>
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"></application>

我已经到处寻找解决方案,我发现的所有结果都表明 Types.SystemAlertTypes.ApplicationOverlay 在清单中具有适当的权限可以解决问题,但显然情况不再如此。鉴于我发现的所有“解决方案”都在 4 到 8 岁之间,它们显然已经过时,更不用说它们是用 java 编写的,而不是 c#,这让我更难理解。似乎没有人用 c# 编写这些东西。无论如何,我正在寻找解决方案。

【问题讨论】:

  • 如果您能提供更多有关这方面的详细信息,它真的会帮助我为您找到解决方案。例如,Stacktrace 和完整的 Message(Exception)!!
  • 完整的错误是:Unhandled Exception: Android.Views.WindowManagerBadTokenException: &lt;Timeout exceeded getting exception details&gt; occurred
  • 你确定你不是从后台线程调用它,并且你正在使用服务的上下文来显示AlertDialog吗?
  • 这是我捕获错误时收到的消息:"Unable to add window -- token null is not valid; is your activity running?"
  • 在拨打电话的地方添加了我的服务代码。

标签: c# xamarin.android visual-studio-2017


【解决方案1】:

在 xamarin 中可以像这样调用其他应用程序的绘制权限:

 private const int RequestCode = 1000;

    private void CheckForOverlayPermission()
    {
        if (Build.VERSION.SdkInt < BuildVersionCodes.M) return;
        if (!Settings.CanDrawOverlays(this)) return;

        var intent = new Intent(Settings.ActionManageOverlayPermission);
        intent.SetPackage(PackageName);
        StartActivityForResult(intent, RequestCode);
    }

    protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
    {
        if (requestCode == RequestCode)
        {
            if (Settings.CanDrawOverlays(this))
            {
                // we have permission
            }
        }

        base.OnActivityResult(requestCode, resultCode, data);
    }

【讨论】:

    【解决方案2】:

    鉴于最近对 android 操作系统的更新,现在不可能做到这一点,所以我不得不推送通知而不是显示弹出窗口。我已经让通知在我的服务中工作,接下来我将弄清楚当用户点击通知时如何让它将应用程序带到前台。我的(现在工作的)服务和通知代码位于此链接: Send notification from service

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-10-17
      • 2012-05-07
      • 2018-10-02
      • 2018-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多