为什么不会在我的后台服务中使用Toast通知(使用System.Timer)?

时间:2017-08-11 15:31:24

标签: c# android multithreading xamarin xamarin.android

在后台服务中,我使用System.Timers创建倒计时器。

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

但是,Toast通知没有出现,我想知道为什么

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

1 个答案:

答案 0 :(得分:2)

  

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

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

如文档所述,服务可以显示Toast

  

可以从活动或服务创建和显示Toast。如果您从服务创建Toast通知,它将显示在当前处于焦点的活动的前面。

为什么它不能出现在这个问题中?请注意Toast.MakeText方法:

enter image description here

这意味着如果你想要展示吐司,你必须把Toast放在主线程上,我想这就是原因。您的问题是OnTimedEvent方法将在不同的主题中运行,因此您在Android 中不允许的主题中显示Toast

如你所说,You simply initialize it, then it gets passed off to a system service queue。  在Toast源代码中,我们可以证明您的意见:

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

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

我们只需将吐司放入主线程的消息队列中,Android就会给我们一个API Looper.getMainLooper()来实现这个功能,修改你的代码如下:

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

效果:

enter image description here