谷歌有它的时钟应用程序,其中包括它的秒表。我目前正在我的应用程序中创建一个计时器,或者你可以叫它秒表,它可以在后台运行,当它在后台运行时,我希望它也显示一个通知,显示计时时间和"停止"按钮(所有这些都发生在谷歌时钟应用程序(see here)中)对于我的应用程序中的计时器,我使用了一个处理程序,该处理程序会发布一个Runnable,它会自己发布。我用Java写我的应用程序。
定义"计时器"的代码(处理程序和可运行):
Handler timerHandler = new Handler();
Runnable timerRunnable = new Runnable() {
@Override
public void run() {
long millis = System.currentTimeMillis() - startTime;
seconds = (millis / 1000) + PrefUtil.getTimerSecondsPassed();
timerHandler.postDelayed(this, 500);
}
};
我的onPause函数:
@Override
public void onPause() {
super.onPause();
if (timerState == TimerState.Running) {
timerHandler.removeCallbacks(timerRunnable);
//TODO: start background timer, show notification
}
PrefUtil.setTimerSecondsPassed(seconds);
PrefUtil.setTimerState(timerState);
}
如何在应用中实现后台服务和通知?
编辑
我已经成功地创建了一个运行计时器的前台服务,但是遇到了两个问题:
1.当我在大约5分钟后运行应用程序时,通知会在10秒的延迟后显示。
1.通知在启动/恢复后约30秒后停止更新(计时器在后台持续运行,但通知不会随计时器持续更新)。
下面是我的Service
s代码:
public class TimerService extends Service {
Long startTime = 0L, seconds = 0L;
boolean notificationJustStarted = true;
Handler timerHandler = new Handler();
Runnable timerRunnable;
NotificationCompat.Builder timerNotificationBuilder = new NotificationCompat.Builder(this, CHANNEL_ID);
public static final String TIMER_BROADCAST_ID = "TimerBroadcast";
Intent timerBroadcastIntent = new Intent(TIMER_BROADCAST_ID);
@Override
public void onCreate() {
Log.d(TAG, "onCreate: started service");
startForeground(1, new NotificationCompat.Builder(this, CHANNEL_ID).setSmallIcon(R.drawable.timer).setContentTitle("Goal In Progress").build());
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String goalName = intent.getStringExtra(PublicMethods.getAppContext().getString(R.string.timer_notification_service_current_goal_extra_name));
startTime = System.currentTimeMillis();
notificationJustStarted = true;
timerRunnable = new Runnable() {
@Override
public void run() {
long millis = System.currentTimeMillis() - startTime;
seconds = (millis / 1000) + PrefUtil.getTimerSecondsPassed();
updateNotification(goalName, seconds);
timerHandler.postDelayed(this, 500);
}
};
timerHandler.postDelayed(timerRunnable, 0);
return START_STICKY;
}
public void updateNotification(String goalName, Long seconds) {
try {
if (notificationJustStarted) {
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);
timerNotificationBuilder.setContentTitle("Goal In Progress")
.setOngoing(true)
.setSmallIcon(R.drawable.timer)
.setContentIntent(pendingIntent)
.setOnlyAlertOnce(true)
.setOngoing(true)
.setPriority(NotificationCompat.PRIORITY_MAX);
notificationJustStarted = false;
}
timerNotificationBuilder.setContentText(goalName + " is in progress\nthis session's length: " + seconds);
startForeground(1, timerNotificationBuilder.build());
} catch (Exception e) {
Log.d(TAG, "updateNotification: Couldn't display a notification, due to:");
e.printStackTrace();
}
}
@Override
public void onDestroy() {
timerHandler.removeCallbacks(timerRunnable);
PrefUtil.setTimerSecondsPassed(seconds);
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
这是我在片段中的开头:
private void startTimerService() {
Intent serviceIntent = new Intent(getContext(), TimerService.class);
serviceIntent.putExtra(getString(R.string.timer_notification_service_current_goal_extra_name), "*Current Goal Name Here*");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Objects.requireNonNull(getContext()).startForegroundService(serviceIntent);
}
}
更新
当我在谷歌像素模拟器上运行应用程序时,我不会遇到上面列出的任何问题
3条答案
按热度按时间cwtwac6a1#
有两个问题。我会尽力解决它们。
首次发布
当我在大约5分钟后运行应用程序时,通知会在10秒的延迟后显示。
为此,您需要使用通知的代码更新通知。现在,由于通知需要时间显示,因此请在启动服务的Activity中显示它,然后使用其构造函数将通知ID传递给服务。使用该ID在服务中更新通知。
希望这能解决第一个问题。
第二次发布
通知在启动/恢复后约30秒后停止更新(计时器在后台持续运行,但通知不会随计时器持续更新)。
要解决这个问题,你可以在10秒后清除之前的通知,然后你可以为通知创建一个新的随机密钥(我更喜欢
new Random().nextInt()
),然后显示它。但是你或任何人都会说,当通知到来时有这么多的声音。在创建一个通道时,只需禁用它:如果这看起来很复杂,请看这个:
编辑
这是我的工作代码:
你也可以在这个here上查看我的repo,它是一个完整的秒表应用程序
mv1qrgav2#
我已经找到了为什么我的通知在30秒后停止更新的原因!显然,(根据this thread)在一些运行Android版本高于9的设备上有后台限制。
这些限制是从应用程序关闭的那一刻起30秒后阻止我的通知更新的限制,或者换句话说,从它们成为后台活动的那一刻起(即使它们是通过
startForeground()
调用的)。无法绕过此设置。您无法以编程方式禁用此设置。唯一的选择是使用ActivityManager.isBackgroundRestricted()以编程方式检查是否已启用此设置,并显示一个弹出窗口,通知用户如何禁用此设置
用户根据线程中接受的答案回答。
这样,通知没有按预期更新的问题就解决了。但显示第一个通知的延迟问题仍然没有解决,还有另一个问题-每次通知更新时,整个通知面板都会冻结一小段时间。
um6iljoc3#
如果你在
onStartCommand
函数内的TimerService
中用scheduleAtFixedRate
替换递归的postDelayed
,解决方案的效果会更好,即使在启用了电池限制的情况下也是如此。另外,如果您允许的话,我可以更新您的git仓库)