Android-서비스에 대한 startForeground 구현?


124

따라서 내 서비스를 포 그라운드에서 실행하기 위해이 방법을 어디서 / 어떻게 구현해야할지 모르겠습니다. 현재 나는 다른 활동에서 다음과 같이 서비스를 시작합니다.

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

그리고 myServices의 onCreate ()에서 startForeground () ...?

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

그래서 그래 나는 이것을 구현하는 방법을 조금 잃어 버렸고 확실하지 않습니다.


글쎄, 이것은 적어도 내 서비스가 여전히 백그라운드 서비스로 작동하고 죽임을 알 수있는 한 작동하지 않습니다.
JDS

답변:


131

나는 완전히 작성하여 시작 했죠 Notification. 다음은 .NET Framework의 사용을 보여주는 샘플 프로젝트 입니다 startForeground().


8
알림없이 startForeground ()를 사용할 수 있습니까? 아니면 나중에 동일한 알림을 업데이트 할 수 있습니까?
JRC

2
특별한 이유가 1337있습니까?
Cody

33
@DoctorOreo : 기기에서 반드시 고유하지는 않지만 앱 내에서 고유해야합니다. 물론, 그것이, 때문에 나는 1337을 선택했다 1337 . :-)
CommonsWare

@JRC 질문은 좋은 질문입니다. 알림없이 startForeground ()를 사용할 수 있습니까?
Snicolas

2
@Snicolas : Android의 결함을 지적 해 주셔서 감사합니다. 이 문제를 해결하기 위해 노력하겠습니다.
CommonsWare

78

기본 활동에서 다음 코드로 서비스를 시작합니다.

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

@mike MainActivity에서이 알림을 업데이트하는 방법은 무엇입니까?
Roon13 2015 년

1
Roon13이 경우 1337에서 ID를 사용하여 @ ... 새 알림을 구축하고 ID와 startForeground를 호출 할 수 있어야합니다
mikebertiean

Roon13 @이 질문에 체크 아웃 stackoverflow.com/questions/5528288/...
mikebertiean

@mikebertiean MainActivity에서 startForeground를 어떻게 호출 할 수 있습니까? 프로세스가 완료되면 MainActvity에서 알림을 어떻게 지울 수 있습니까?
Roon13

@mikebertiean Service 클래스에서 startForeground를 다시 호출해야한다는 것을 알았지 만 어떻게? startService ()를 다시 호출해야합니까?
Roon13

30

이것은 서비스를 전경으로 설정하는 코드입니다.

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 에서 내 코드를 참조하십시오.


stopForeground (true)를 호출하는 알림을 제거하면 startforeground 서비스가 취소됩니다
sdelvalle57

6
이 메서드를 어디에서 호출합니까?
Srujan Barai

7
Intent.FLAG_ACTIVITY_NEW_TASK의 컨텍스트에서 유효하지 않습니다 PendingIntent.
mixel 2015

30

Oreo 8.1 용 솔루션

최신 버전의 Android에서 잘못된 채널 ID로 인해 RemoteServiceException 과 같은 몇 가지 문제가 발생했습니다 . 이것이 내가 해결 한 방법입니다.

활동 :

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 상당

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

8
ContextCompat.startForegroundService(Context,Intent)옳은 일을 할 활동에 사용할 수 있습니다 . ( developer.android.com/reference/android/support/v4/content/… )
Simon Featherstone

3
당신은 아마 사용하고자하는 것 .setCategory(NotificationCompat.CATEGORY_SERVICE)대신에 Notification.CATEGORY_SERVICE당신의 분 API는 <21 인 경우
어딘가의 누군가가

6
Build.VERSION_CODES.P(API 레벨 28) 이상을 대상으로하는 앱 은 사용하려면 권한 Manifest.permission.FOREGROUND_SERVICE을 요청해야합니다. developer.android.com/reference/android/app/…startForeground() 참조
Vadim Kotov

21

뿐만 아니라 RAWA의 대답은, 코드의 평화 :

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

다음으로 변경할 수 있습니다.

ContextCompat.startForegroundService(context, yourIntent);

이 메서드 내부를 살펴보면이 메서드가 모든 검사 작업을 수행한다는 것을 알 수 있습니다.


9

IntentService를 포 그라운드 서비스로 만들려면

다음 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();
}

더 깊은 이해

서비스가 포 그라운드 서비스가되면 어떻게 되나요?

이것은 일어난다

여기에 이미지 설명 입력

포 그라운드 서비스 란 무엇입니까?

포 그라운드 서비스,

  • 알림을 제공하여 사용자가 백그라운드에서 진행되는 작업을 적극적으로 인식하도록합니다.

  • (가장 중요한 것은) 메모리가 부족할 때 시스템에 의해 죽지 않습니다.

포 그라운드 서비스의 사용 사례

음악 앱에서 노래 다운로드 기능 구현


5

onCreate ()에서 "OS> = Build.VERSION_CODES.O"대해 지정된 코드 서비스 클래스 추가

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

1

서비스의 startCommand 에 대한 인 텐트를 사용하여 처리합니다.

 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
}

파괴시 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)
}

1

참고 : 앱이 API 레벨 26 이상을 대상으로하는 경우 앱 자체가 포 그라운드에 있지 않는 한 시스템은 백그라운드 서비스 사용 또는 생성에 제한을 부과합니다.

앱에서 포 그라운드 서비스를 만들어야하는 경우 앱은 startForegroundService(). 이 메서드는 백그라운드 서비스를 생성하지만이 메서드는 서비스가 자신을 포 그라운드로 승격시킬 것이라는 신호를 시스템에 보냅니다.

서비스가 생성되면 서비스는 startForeground() method within five seconds.


1
나는 당신이 현재 질문에 대해 이야기하고 있기를 바랍니다. 그렇지 않으면 Stackoverflow 커뮤니티에는 그러한 규칙이 없습니다
Farid

프로덕션 준비 환경 코드의 @RogerGusmao가 항상 프로젝트를 저장하는 것은 아닙니다. 게다가-내 대답 아래에 코드가 포함 된 훌륭한 예제가 많이 있습니다 .. 내 프로젝트는 startForegroundService방법 에 대해 몰랐기 때문에 릴리스 중에 문제가 발생했습니다
Andrii Kovalchuk 19

0

제 경우에는 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 "+ serial_id +"shell am startforegroundservice -n com.test.socket.sample / .SocketService


따라서 Oreo 장치에서 활동없이 서비스를 시작할 수 있습니다. :)


0

@mikebertiean 솔루션은 거의 트릭을 수행했지만 추가 트위스트 로이 문제가 발생했습니다. 저는 Gingerbread 시스템을 사용하고 알림을 실행하기 위해 추가 패키지를 추가하고 싶지 않았습니다. 마지막으로 발견했습니다 : https://android.googlesource.com/platform/frameworks/support.git+/f9fd97499795cd47473f0344e00db9c9837eea36/v4/gingerbread/android/support/v4/app/NotificationCompatGingerbread.java

그런 다음 추가 문제가 발생했습니다. 알림은 앱이 실행될 때 단순히 앱을 종료합니다 (이 문제를 해결하는 방법 : Android : 알림을 클릭하면 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);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.