Android 实现的 startForeground 服务?

因此,我不确定在哪里/如何实现这个方法,使我的服务在前台运行。目前,我通过另一个活动开始我的服务:

Intent i = new Intent(context, myService.class);
context.startService(i);

然后在 myServices 的 onCreate ()中尝试 startForeground () ... ?

Notification notification = new Notification();
startForeground(1, notification);

所以,是的,我有点迷茫,不确定如何实现这一点。

235142 次浏览

我将从完全填写 Notification.下面是一个示例项目开始,演示如何使用 startForeground()

这是我将服务设置为前台的代码:

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


}

我需要使用 PendingInent 构建一个通知,这样我就可以从通知开始我的主要活动。

要删除通知,只需调用 stopForeground (true) ;

它在 onStartCommand ()中被调用。请参考我的代码: https://github.com/bearstand/greyparrot/blob/master/src/com/xiong/richard/greyparrot/Mp3Recorder.java

从您的主要活动开始,使用以下代码启动服务:

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

如果您想使意图服务成为前台服务

那么你应该像这样覆盖 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();
}

深入了解

当服务成为前台服务时会发生什么

这种事时有发生

enter image description here

什么是前台服务?

前台服务,

  • 确保用户能够主动意识到后台正在发生的事情 提供通知。

  • (最重要的是)在内存不足时不会被 System 杀死

前台服务的用例

在音乐应用程序中实现歌曲下载功能

奥利奥8.1的解决方案

我遇到过一些问题,比如 RemoteServiceException,因为最新版本的 Android 通道 ID 无效。我是这么解决的:

活动 :

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

背景资料服务:

override fun onCreate() {
super.onCreate()
startForeground()
}


private fun startForeground() {


  

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 等价物

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

就我而言,情况完全不同,因为我没有在 Oreo 推出这项服务的活动。

下面是我用来解决这个前台服务问题的步骤-

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“ + Series _ id +”shell am startforeground service-n com.test.socket.sample/. SocketService


因此,这有助于我在 Oreo 设备上启动无活动服务:)

除了 RAWA的回答,这段和平的代码:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent)
} else {
startService(intent)
}

你可以改为:

ContextCompat.startForegroundService(context, yourIntent);

如果你看看这个方法的内部,你会发现这个方法为你做了所有的检查工作。

通过使用。

 stopForeground(true)

这个调用将 从前台状态删除服务,允许在需要更多内存时杀死它。从运行 这不会停止服务。为此,需要调用 Stop Self ()或相关方法。

传递值 没错假的指示是否要删除通知。

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
}

处理你的任务时,在销毁是由 Stop Self ()调用。

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

在 onCreate ()中为“ OS > = Build.VERION _ CODES.O” 添加给定的代码 Service 类

@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" />

注意: 如果你的应用程序目标 API 级别为26或更高,系统会对使用或创建后台服务施加限制,除非应用程序本身在前台。

如果应用程序需要创建前台服务,应用程序应该调用 startForegroundService()。该方法创建了一个后台服务,但是该方法向系统发出信号,表明该服务将自我推广到前台。

一旦创建了服务,服务就必须调用它的 startForeground() method within five seconds.

@ mikebertiean 解决方案差点就成功了,但是我遇到了一个额外的问题——我使用 Gingerbread 系统,我不想为了运行通知而添加一些额外的包。最后我发现: Https://android.googlesource.com/platform/frameworks/support.git+/f9fd97499795cd47473f0344e00db9c9837eea36/v4/gingerbread/android/support/v4/app/notificationcompatgingerbread.java

然后我遇到了额外的问题——通知在应用程序运行时简单地杀死了它(如何解决这个问题: Android: 如何避免单击 Notification 调用 onCreate ()) ,所以总的来说我的服务代码看起来像这样(C #/Xamarin) :

Intent notificationIntent = new Intent(this, typeof(MainActivity));
// make the changes to manifest as well
notificationIntent.SetFlags(ActivityFlags.ClearTop | ActivityFlags.SingleTop);
PendingIntent pendingIntent = PendingIntent.GetActivity(this, 0, notificationIntent, 0);
Notification notification = new Notification(Resource.Drawable.Icon, "Starting service");
notification.SetLatestEventInfo(this, "MyApp", "Monitoring...", pendingIntent);
StartForeground(1337, notification);