Ответ 1
Я бы начал с полного заполнения Notification
. Вот пример проекта, демонстрирующий использование startForeground()
.
Поэтому я не уверен, где/как реализовать этот метод, чтобы мой сервис выполнялся на переднем плане. В настоящее время я запускаю свою службу следующим образом:
Intent i = new Intent(context, myService.class);
context.startService(i);
И затем в myServices 'onCreate() я попробую startForeground()...?
Notification notification = new Notification();
startForeground(1, notification);
Итак, я немного потерял и не знаю, как это реализовать.
Я бы начал с полного заполнения Notification
. Вот пример проекта, демонстрирующий использование startForeground()
.
В своем основном действии запустите службу с помощью следующего кода:
Intent i = new Intent(context, MyService.class);
context.startService(i);
Затем в вашей службе для onCreate()
вы создадите свое уведомление и установите его как передний план следующим образом:
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.app_icon)
.setContentTitle("My Awesome App")
.setContentText("Doing some work...")
.setContentIntent(pendingIntent).build();
startForeground(1337, notification);
Это мой код, чтобы настроить службу на передний план:
private void runAsForeground(){
Intent notificationIntent = new Intent(this, RecorderMainActivity.class);
PendingIntent pendingIntent=PendingIntent.getActivity(this, 0,
notificationIntent, Intent.FLAG_ACTIVITY_NEW_TASK);
Notification notification=new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentText(getString(R.string.isRecording))
.setContentIntent(pendingIntent).build();
startForeground(NOTIFICATION_ID, notification);
}
Мне нужно создать уведомление с помощью PendingIntent, чтобы я мог начать свою основную деятельность из уведомления.
Чтобы удалить уведомление, просто вызовите stopForeground (true);
Он вызывается в onStartCommand(). Пожалуйста, обратитесь к моему коду: https://github.com/bearstand/greyparrot/blob/master/src/com/xiong/richard/greyparrot/Mp3Recorder.java
Я столкнулся с некоторыми проблемами, такими как RemoteServiceException из-за неверного идентификатора канала с последними версиями Android. Вот как я решил это:
Деятельность:
override fun onCreate(savedInstanceState: Bundle?) {
val intent = Intent(this, BackgroundService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent)
} else {
startService(intent)
}
}
BackgroundService:
override fun onCreate() {
super.onCreate()
startForeground()
}
private fun startForeground() {
val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val channelId =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel()
} else {
// If earlier version channel ID is not used
// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
""
}
val notificationBuilder = NotificationCompat.Builder(this, channelId )
val notification = notificationBuilder.setOngoing(true)
.setSmallIcon(R.mipmap.ic_launcher)
.setPriority(PRIORITY_MIN)
.setCategory(Notification.CATEGORY_SERVICE)
.build()
startForeground(101, notification)
}
@RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(): String{
val channelId = "my_service"
val channelName = "My Background Service"
val chan = NotificationChannel(channelId,
channelName, NotificationManager.IMPORTANCE_HIGH)
chan.lightColor = Color.BLUE
chan.importance = NotificationManager.IMPORTANCE_NONE
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
service.createNotificationChannel(chan)
return channelId
}
JAVA EQUIVALENT
public class YourService extends Service {
// Constants
private static final int ID_SERVICE = 101;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
@Override
public void onCreate() {
super.onCreate();
// do stuff like register for BroadcastReceiver, etc.
// Create the Foreground Service
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
String channelId = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? createNotificationChannel(notificationManager) : "";
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId);
Notification notification = notificationBuilder.setOngoing(true)
.setSmallIcon(R.mipmap.ic_launcher)
.setPriority(PRIORITY_MIN)
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.build();
startForeground(ID_SERVICE, notification);
}
@RequiresApi(Build.VERSION_CODES.O)
private String createNotificationChannel(NotificationManager notificationManager){
String channelId = "my_service_channelid";
String channelName = "My Foreground Service";
NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH);
// omitted the LED color
channel.setImportance(NotificationManager.IMPORTANCE_NONE);
channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
notificationManager.createNotificationChannel(channel);
return channelId;
}
}
то вы должны переопределить onHandleIntent()
как это
Override
protected void onHandleIntent(@Nullable Intent intent) {
startForeground(FOREGROUND_ID,getNotification()); //<-- Makes Foreground
// Do something
stopForeground(true); // <-- Makes it again a normal Service
}
просто. Вот метод getNotification()
public Notification getNotification()
{
Intent intent = new Intent(this, SecondActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,intent,0);
NotificationCompat.Builder foregroundNotification = new NotificationCompat.Builder(this);
foregroundNotification.setOngoing(true);
foregroundNotification.setContentTitle("MY Foreground Notification")
.setContentText("This is the first foreground notification Peace")
.setSmallIcon(android.R.drawable.ic_btn_speak_now)
.setContentIntent(pendingIntent);
return foregroundNotification.build();
}
Бывает
Служба переднего плана,
что пользователь активно осознает, что что-то происходит в фоновом режиме, предоставляя уведомление.
(что наиболее важно) не будет уничтожено Системой, когда она будет работать с низким объемом памяти
В дополнение к ответу RAWA этот мир кода:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent)
} else {
startService(intent)
}
Вы можете изменить:
ContextCompat.startForegroundService(context, yourIntent);
Если вы заглянете внутрь этого метода, вы увидите, что этот метод выполняет всю проверку работы.
Добавить заданный код Класс обслуживания для "OS> = Build.VERSION_CODES.O" в onCreate()
@Override
public void onCreate(){
super.onCreate();
.................................
.................................
//For creating the Foreground Service
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
String channelId = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? getNotificationChannel(notificationManager) : "";
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId);
Notification notification = notificationBuilder.setOngoing(true)
.setSmallIcon(R.mipmap.ic_launcher)
// .setPriority(PRIORITY_MIN)
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.build();
startForeground(110, notification);
}
@RequiresApi(Build.VERSION_CODES.O)
private String getNotificationChannel(NotificationManager notificationManager){
String channelId = "channelid";
String channelName = getResources().getString(R.string.app_name);
NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH);
channel.setImportance(NotificationManager.IMPORTANCE_NONE);
channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
notificationManager.createNotificationChannel(channel);
return channelId;
}
Добавьте это разрешение в файл манифеста:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
В моем случае это было совершенно иначе, поскольку у меня не было активности для запуска службы в Орео.
Ниже приведены шаги, которые я использовал для решения этой проблемы переднего плана -
public class SocketService extends Service {
private String TAG = this.getClass().getSimpleName();
@Override
public void onCreate() {
Log.d(TAG, "Inside onCreate() API");
if (Build.VERSION.SDK_INT >= 26) {
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
mBuilder.setSmallIcon(R.drawable.ic_launcher);
mBuilder.setContentTitle("Notification Alert, Click Me!");
mBuilder.setContentText("Hi, This is Android Notification Detail!");
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// notificationID allows you to update the notification later on.
mNotificationManager.notify(100, mBuilder.build());
startForeground(100, mBuilder.mNotification);
}
Toast.makeText(getApplicationContext(), "inside onCreate()", Toast.LENGTH_LONG).show();
}
@Override
public int onStartCommand(Intent resultIntent, int resultCode, int startId) {
Log.d(TAG, "inside onStartCommand() API");
return startId;
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "inside onDestroy() API");
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
И после этого, чтобы начать эту услугу, я вызвал ниже cmd -
adb -s "+ serial_id +" shell am startforegroundservice -n com.test.socket.sample/.SocketService
Так что это помогает мне начать сервис без активности на устройствах Oreo :)
Направляйте намерение на startCommand of service, используя.
stopForeground(true)
Этот вызов приведет к удалению службы из состояния переднего плана, что позволяет ее убить, если требуется больше памяти. Это не останавливает запуск службы. Для этого вам нужно вызвать stopSelf() или связанные с ним методы.
Передано значение true или false, если вы хотите удалить уведомление или нет.
val ACTION_STOP_SERVICE = "stop_service"
val NOTIFICATION_ID_SERVICE = 1
...
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
if (ACTION_STOP_SERVICE == intent.action) {
stopForeground(true)
stopSelf()
} else {
//Start your task
//Send forground notification that a service will run in background.
sendServiceNotification(this)
}
return Service.START_NOT_STICKY
}
Управляйте своей задачей, когда на destroy вызывается stopSelf().
override fun onDestroy() {
super.onDestroy()
//Stop whatever you started
}
Создайте уведомление, чтобы служба работала на переднем плане.
//This is from Util class so as not to cloud your service
fun sendServiceNotification(myService: Service) {
val notificationTitle = "Service running"
val notificationContent = "<My app> is using <service name> "
val actionButtonText = "Stop"
//Check android version and create channel for Android O and above
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//You can do this on your own
//createNotificationChannel(CHANNEL_ID_SERVICE)
}
//Build notification
val notificationBuilder = NotificationCompat.Builder(applicationContext, CHANNEL_ID_SERVICE)
notificationBuilder.setAutoCancel(true)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.drawable.ic_location)
.setContentTitle(notificationTitle)
.setContentText(notificationContent)
.setVibrate(null)
//Add stop button on notification
val pStopSelf = createStopButtonIntent(myService)
notificationBuilder.addAction(R.drawable.ic_location, actionButtonText, pStopSelf)
//Build notification
val notificationManagerCompact = NotificationManagerCompat.from(applicationContext)
notificationManagerCompact.notify(NOTIFICATION_ID_SERVICE, notificationBuilder.build())
val notification = notificationBuilder.build()
//Start notification in foreground to let user know which service is running.
myService.startForeground(NOTIFICATION_ID_SERVICE, notification)
//Send notification
notificationManagerCompact.notify(NOTIFICATION_ID_SERVICE, notification)
}
Дайте кнопку остановки при уведомлении, чтобы остановить службу, когда пользователь нуждается.
/**
* Function to create stop button intent to stop the service.
*/
private fun createStopButtonIntent(myService: Service): PendingIntent? {
val stopSelf = Intent(applicationContext, MyService::class.java)
stopSelf.action = ACTION_STOP_SERVICE
return PendingIntent.getService(myService, 0,
stopSelf, PendingIntent.FLAG_CANCEL_CURRENT)
}
Примечание. Если ваше приложение предназначено для уровня API 26 или выше, система накладывает ограничения на использование или создание фоновых служб, если само приложение не находится на переднем плане.
Если приложению необходимо создать службу переднего плана, оно должно вызвать startForegroundService()
. Этот метод создает фоновый сервис, но метод сигнализирует системе, что сервис будет продвигаться на передний план.
Как только служба создана, она должна вызвать свой startForeground() method within five seconds.