java - 关闭应用程序时服务不执行,但在后台执行时会执行
问题描述
我一直在尝试制作警报应用程序。我一直在努力制作全屏通知。我终于设法做到了,但它仅在应用程序在后台运行时才有效。
当您关闭应用程序时,它也需要工作。我不明白我应该做些什么来实现这一目标。我知道这是可能的,因为我每天使用的闹钟应用程序能够做到这一点。
Mainactivity.java
package com.example.wekkerapp;
import java.util.Calendar;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import android.app.AlarmManager;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private static final String CHANNEL_ID = "my_channel";
static final String FULL_SCREEN_ACTION = "full_screen_action";
static final int NOTIFICATION_ID = 1;
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "Alarm";
String description = "Het alarm gaat";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel("2", name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = (NotificationManager) getSystemService(this.NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(channel);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
createNotificationChannel(this);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TimePicker klok = findViewById(R.id.timePicker1);
klok.setIs24HourView(true);
final Button getTimeBtn = findViewById(R.id.getTimeBtn);
final TextView showText = findViewById(R.id.showText);
final AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
getTimeBtn.setOnClickListener(new View.OnClickListener() {
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onClick(View view) {
Intent intent = new Intent(FULL_SCREEN_ACTION, null, getApplicationContext(), WekkerService.class);
PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
int uur = klok.getHour();
int minuut = klok.getMinute();
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, uur);
cal.set(Calendar.MINUTE, minuut);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
Toast.makeText(getApplication().getApplicationContext(), "Alarm gaat om " + uur + ":" + minuut,Toast.LENGTH_LONG).show();
alarmManager.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pendingIntent);
showText.setText(Integer.toString(uur) + ':' + Integer.toString(minuut));
NotificationManagerCompat.from(getApplicationContext()).cancel(NOTIFICATION_ID);
}
});
}
static void CreateFullScreenNotification(Context context) {
Intent intent = new Intent(context, MainActivity2.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("Alarm")
.setContentText("Het alarm gaat")
.setPriority(NotificationCompat.PRIORITY_MAX)
.setCategory(NotificationCompat.CATEGORY_ALARM)
.setContentIntent(pendingIntent)
.setFullScreenIntent(pendingIntent, true);
NotificationManagerCompat.from(context).notify(NOTIFICATION_ID, notificationBuilder.build());
}
private static void createNotificationChannel(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
if (notificationManager.getNotificationChannel(CHANNEL_ID) == null) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "channel_name", NotificationManager.IMPORTANCE_HIGH);
channel.setDescription("channel_description");
notificationManager.createNotificationChannel(channel);
}
}
}
}
Wekkerservice.java
package com.example.wekkerapp;
import android.app.AlarmManager;
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayer;
import android.util.Log;
import androidx.annotation.Nullable;
public class WekkerService extends IntentService {
public static MediaPlayer mediaPlayer;
public WekkerService() {
super("WekkerService");
}
@Override
public void onCreate() {
super.onCreate(); // if you override onCreate(), make sure to call super().
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
Log.d("test", "onHandleIntent: ");
mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.alarmpie);
if (MainActivity.FULL_SCREEN_ACTION.equals(intent.getAction()))
mediaPlayer.setLooping(true);
mediaPlayer.start(); // no need to call prepare(); create() does that for you
MainActivity.CreateFullScreenNotification(getApplicationContext());
}
}
Mainactivity2.java
package com.example.wekkerapp;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Bundle;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.NotificationCompat;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
public class MainActivity2 extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Button stopbutton = findViewById(R.id.button2);
stopbutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
WekkerService.mediaPlayer.stop();
}
});
}
}
解决方案
我建议您使用 BroadcastReceiver,然后从其 onReceive 方法启动服务。因此,在您的 MainActivity 的 onClick 侦听器中,您应该更改以下待处理的意图,如下所示:
PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
至
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
并且您传入的意图应该启动一个广播接收器。警报管理器启动 BroadcastReceiver 后,您应该立即从其 onReceive 方法启动服务。
请记住,由于最近的更改,操作系统不会让您随时随地启动服务或后台服务!
如果应用程序已关闭并且您想启动服务,则应该将其作为 ForgroundService 启动并显示通知(您有 5 秒的时间进行此调用),否则它将抛出 RemoteServiceException,这就是您服务中的代码不会运行的原因.
我强烈建议您看看这个答案: https ://stackoverflow.com/a/56471104/9023032 这也是另一个有用的答案,可能会变得很方便: https ://stackoverflow.com/a/54035247/9023032
推荐阅读
- python - 如何使用日期时间获取另一个国家的日期?
- angular - 我可以在 app.module 提供程序中放置一个简单的类吗?
- javascript - 在 Cypress 中上传文件
- android - 安卓 | 科特林 | 流 - 不能转换为 kotlinx.coroutines.flow.StateFlow
- reactjs - React 应用程序错误对象不支持属性或方法“最近”
- javascript - 垂直翻转问题;HTML、CSS、问题:位置/显示中的某处
- swiftui - @EnvironmentObject 不会更新 SwiftUI 中的 UI
- wordpress - Cloudinary wordpress 插件同步太慢
- android - 嵌套的 ScrollView 不显示子 recyclerview 的最后一项
- python - 需要删除每个包含特定单词的文件