问题
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();
}
}
回答1:
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 :
来源:https://stackoverflow.com/questions/45638838/why-wont-a-toast-notification-appear-in-my-background-service-using-system-tim