为什么我的后台服务中不会出现 toast 通知(使用 System.Timer)? [英] Why won't a toast notification appear in my background Service (using System.Timer)?

查看:38
本文介绍了为什么我的后台服务中不会出现 toast 通知(使用 System.Timer)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在后台服务中,我使用 System.Timers 创建了一个倒数计时器.

它似乎有效.在控制台中 2 秒后,我可以看到 Console.WriteLine() 打印文本.

然而,Toast 通知没有出现,我想知道为什么

使用系统;使用 System.Collections.Generic;使用 System.Linq;使用 System.Text;使用 Android.App;使用 Android.Content;使用Android.OS;使用 Android.Runtime;使用 Android.Views;使用 Android.Widget;使用 Android.Media;使用 Android.Content.Res;使用 System.Timers;命名空间 AudioTour{[Service(Exported = false, Name = "com.AudioTour.AudioService")]公共类 AudioService :服务{//调用这个方法来启动Timer私有无效 StartCountdown(){运行定时器(2);}私人定时器 myTimer;私人 int countDownSeconds;//这是我的计时器私有无效运行计时器(int _timerLength){myTimer = new Timer();myTimer.Interval = 1000;myTimer.Elapsed += OnTimedEvent;倒计时秒数 = 5;myTimer.Enabled = true;}//当定时器超时时调用此事件私有无效 OnTimedEvent(对象发送者,System.Timers.ElapsedEventArgs elapsedEventArgs){倒计时秒数--;//这是我期望在计时器达到 0 时发生的情况if (countDownSeconds == 0){Console.WriteLine("定时器完成");Toast.MakeText(this, "Timer Finished", ToastLength.Short).Show();myTimer.Stop();}}

解决方案

Android 中的后台服务没有 UI,因此无法生成 Toast,因为这是一个 UI 组件.

@jason.kaisersmith,大家好,有点不同的意见,我认为无法显示吐司是因为线程而不是 Service 本身.

服务可以像文档所说的那样显示 Toast :

<块引用>

可以从活动或服务中创建和显示 Toast.如果您从服务创建 Toast 通知,它会出现在当前焦点活动的前面.

为什么不能在这个问题中显示?注意 Toast.MakeText 方法:

意思是如果你想显示toast,你必须把Toast放在主线程中,我想这就是原因.您的问题是OnTimedEvent 方法将在不同的线程 中运行,因此您在android 中不允许的线程中显示Toast.

正如您所说,您只需对其进行初始化,然后将其传递到系统服务队列.在 Toast 源代码中,我们可以证明您的意见:

//将toast插入消息队列service.enqueueToast(pkg, tn, mDuration);

现在的问题变成了如何将此消息发送到主线程.

我们只需要将toast放入主线程的消息队列中,Android给我们一个API

In a background service I create a count down timer using System.Timers.

It appears to work. After 2 seconds in the console I can see that Console.WriteLine() prints the text.

However, the Toast notification does not appear and I would like to know why

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;   
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Media;
using Android.Content.Res;
using System.Timers;


namespace AudioTour
{
    [Service(Exported = false, Name = "com.AudioTour.AudioService")]
    public class AudioService : Service
    {
        // This method is called to start the Timer
        private void StartCountdown()
        {
            RunTimer(2);
        }

        private Timer myTimer;
        private int countDownSeconds;

        // This is my timer
        private void RunTimer(int _timerLength)
        {
            myTimer = new Timer();
            myTimer.Interval = 1000;
            myTimer.Elapsed += OnTimedEvent;
            countDownSeconds = 5;
            myTimer.Enabled = true;
        }

        // When the timer has elapsed this event is called
        private void OnTimedEvent(object sender, System.Timers.ElapsedEventArgs elapsedEventArgs)
        {
            countDownSeconds--;
            // This is what I expect to happen when the timer reaches 0
            if (countDownSeconds == 0)
            {
                Console.WriteLine("Timer Finished");
                Toast.MakeText(this, "Timer Finished", ToastLength.Short).Show();
                myTimer.Stop();
            }
        }

解决方案

A background service in Android does not have an UI, so it can't produce a toast as this is a UI component.

@jason.kaisersmith, hi guys, a little different opinion, I think the toast cant shown because of the thread instead of the Service itself.

A service could show Toast as the document said :

A toast can be created and displayed from an Activity or Service. If you create a toast notification from a Service,it appears in front of the Activity currently in focus.

Why it cant be shown in this question? Notice that the Toast.MakeText method :

It means if you want to show the toast, you have to put the Toast on the main thread, I think this is the reason. Your problem is OnTimedEvent method will run in a different thread so you are showing Toast in a thread which is not allowed in android.

As you said, You simply initialize it, then it gets passed off to a system service queue. In Toast source code we can prove your opinion:

//insert toast to a messagequeue
service.enqueueToast(pkg, tn, mDuration);  

Now the problem becomes how to send this message to Main thread.

We just need to put the toast into main thread's messagequeue, and Android give us a API Looper.getMainLooper() to implement this function, modify your code like this :

private void OnTimedEvent(object sender, System.Timers.ElapsedEventArgs elapsedEventArgs)
{
     countDownSeconds--;
     // This is what I expect to happen when the timer reaches 0
     if (countDownSeconds == 0)
     {
          Console.WriteLine("Timer Finished==========================");
          Handler handler = new Handler(Looper.MainLooper);
          //Returns the application's main looper, which lives in the main thread of the application.
          Action myAction = () =>
          {
              Toast.MakeText(this, "Timer Finished", ToastLength.Short).Show();

           };
           handler.Post(myAction);
           myTimer.Stop();
     }
}

Effect :

这篇关于为什么我的后台服务中不会出现 toast 通知(使用 System.Timer)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆