Android - bir hizmet için startForeground uygulama mı?


124

Bu yüzden hizmetimin ön planda çalışmasını sağlamak için bu yöntemi nerede / nasıl uygulayacağımdan emin değilim. Şu anda başka bir aktivitede aşağıdakileri yaparak hizmetime başlıyorum:

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

Ve sonra myServices'in onCreate () kısmında startForeground () ...

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

Yani evet, biraz kayboldum ve bunu nasıl uygulayacağımdan emin değilim.


Bu işe yaramıyor, en azından hizmetimin hala bir arka plan hizmeti olarak çalıştığını ve öldürüldüğünü söyleyebildiğim kadarıyla.
JDS

Yanıtlar:


131

Tamamen doldurarak başlıyorum Notification. İşte kullanımını gösteren örnek bir projestartForeground() .


8
StartForeground () bildirimsiz olarak kullanılabilir mi? Veya daha sonra aynı bildirimi güncelleyebilir miyiz?
JRC

2
Kullanmanızın belirli bir nedeni var 1337mı?
Cody

33
@DoctorOreo: Cihazda mutlaka benzersiz olmasa da uygulama içinde benzersiz olması gerekir. 1337'yi seçtim çünkü 1337 . :-)
CommonsWare

@JRC sorusu iyi bir sorudur. StartForeground () bildirimsiz olarak kullanılabilir mi?
Snicolas

2
@Snicolas: Android'deki bir kusuru işaret ettiğiniz için teşekkür ederiz. Bunu düzeltmek için çalışacağım.
CommonsWare

78

Ana etkinliğinizden, hizmeti aşağıdaki kodla başlatın:

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

Sonra sizin için hizmetinizde onCreate()bildiriminizi oluşturur ve şu şekilde ön plan olarak ayarlarsınız:

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'den bu bildirimi nasıl güncelleyebilirim?
Roon13

1
@ Roon13 kimliği kullanarak, bu durumda 1337 ... yeni bir bildirim oluşturabilmeli ve ID ile startForeground'u çağırabilmelisiniz
mikebertiean

@ Roon13 bu soruyu kontrol edin stackoverflow.com/questions/5528288/…
mikebertiean

@mikebertiean MainActivity'den startForeground'u nasıl çağırabilirim? ayrıca işlem bittiğinde MainActvity'den bildirimi nasıl temizleyebilirim?
Roon13

@mikebertiean Service sınıfında startForeground'u tekrar çağırmam gerektiğini anladım ama nasıl? StartService () 'i yeniden çağırmam gerekir mi?
Roon13

30

Bu hizmeti ön plana çıkarmak için benim kodum:

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

}

Ana faaliyetime bildirimden başlayabilmek için PendingIntent kullanarak bir bildirim oluşturmam gerekiyor.

Bildirimi kaldırmak için stopForeground (true) çağırın;

OnStartCommand () içinde çağrılır. Lütfen şu adresteki koduma bakın: https://github.com/bearstand/greyparrot/blob/master/src/com/xiong/richard/greyparrot/Mp3Recorder.java


StopForeground (true) çağrısı bildirimini kaldırırsanız, startforeground hizmetini iptal etmiş olursunuz
sdelvalle57

6
Bu yöntemi nereden çağırıyorsunuz?
Srujan Barai

7
Intent.FLAG_ACTIVITY_NEW_TASKbağlamında geçerli değil PendingIntent.
mixel

30

Oreo 8.1 için Çözüm

Android'in en son sürümlerinde geçersiz kanal kimliği nedeniyle RemoteServiceException gibi bazı sorunlarla karşılaştım . Ben böyle çözdüm:

Aktivite :

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 EŞDEĞER

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
Sen kullanabilirsiniz ContextCompat.startForegroundService(Context,Intent)doğru olanı yapacağız Faaliyetinizdeki. ( developer.android.com/reference/android/support/v4/content/… )
Simon Featherstone

3
min .setCategory(NotificationCompat.CATEGORY_SERVICE)Notification.CATEGORY_SERVICE
Someone Somewhere

6
Build.VERSION_CODES.P(API düzeyi 28) veya daha sonraki bir sürümü hedefleyen uygulamaların Manifest.permission.FOREGROUND_SERVICEkullanmak için izin istemesi gerektiğini lütfen unutmayın startForeground()- bkz. Developer.android.com/reference/android/app/…
Vadim Kotov

21

RAWA cevabına ek olarak , bu kod barışı:

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

Değiştirebilirsiniz:

ContextCompat.startForegroundService(context, yourIntent);

Bu yöntemin içine bakarsanız, bu yöntemin sizin için tüm kontrol işlerini yaptığını görebilirsiniz.


9

IntentService'i bir Ön Plan Hizmeti yapmak istiyorsanız

o zaman geçersiz kılmak gerekir onHandleIntent()böyle

Override
protected void onHandleIntent(@Nullable Intent intent) {


    startForeground(FOREGROUND_ID,getNotification());     //<-- Makes Foreground

   // Do something

    stopForeground(true);                                // <-- Makes it again a normal Service                         

}

Bildirim nasıl yapılır?

basit. İşte getNotification()Yöntem

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

Daha Derin Anlayış

Bir hizmet ön plan hizmeti olduğunda ne olur?

Bu olur

görüntü açıklamasını buraya girin

Ön plan Hizmeti nedir?

Bir ön plan hizmeti,

  • bildirimi sağlayarak kullanıcının arka planda bir şeyler olup bittiğinden aktif olarak haberdar olmasını sağlar.

  • (en önemlisi) bellek azaldığında Sistem tarafından öldürülmez

Ön plan hizmetinin bir kullanım örneği

Müzik Uygulamasında şarkı indirme işlevini uygulama


5

OnCreate () 'de "OS> = Build.VERSION_CODES.O" için verilen kodu Hizmet sınıfını ekleyin

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

Bu izni manifest dosyasına ekleyin:

 <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

1

StartCommand of service'deki amacı kullanarak işleyin .

 stopForeground(true)

Bu çağrı , hizmeti ön plan durumundan kaldıracak ve daha fazla belleğe ihtiyaç duyulması halinde hizmetin kapatılmasına izin verecektir . Bu, hizmetin çalışmasını durdurmaz . Bunun için stopSelf () veya ilgili yöntemleri çağırmanız gerekir .

Bildirimin kaldırılmasını isteyip istemediğinizi true veya false değerini iletir .

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 () tarafından yok edildiğinde görevinizi yerine getirin .

override fun onDestroy() {
    super.onDestroy()
    //Stop whatever you started
}

Hizmetin ön planda çalışmasını sağlamak için bir bildirim oluşturun.

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

Kullanıcı ihtiyaç duyduğunda hizmeti durdurmak için bildirimde bir durdur düğmesi verin.

/**
 * 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

Not: Uygulamanız API seviyesi 26 veya üstünü hedefliyorsa, sistem, uygulamanın kendisi ön planda olmadığı sürece arka plan hizmetlerinin kullanımına veya oluşturulmasına kısıtlamalar getirir.

Bir uygulamanın bir ön plan hizmeti oluşturması gerekiyorsa, uygulamanın araması gerekir startForegroundService(). Bu yöntem bir arka plan hizmeti yaratır, ancak yöntem sisteme hizmetin kendisini ön plana çıkaracağını işaret eder.

Hizmet oluşturulduktan sonra, hizmetin kendi startForeground() method within five seconds.


1
Umarım şu anki sorudan bahsediyorsundur. Aksi takdirde, Stackoverflow topluluğunda böyle bir kural yoktur
Farid

@RogerGusmao üretime hazır ortam kodunda projenizi her zaman kaydetmeyecektir. Ayrıca - cevabımın altında ve üstünde kod bulunan pek çok harika örnek var .. startForegroundService
Projem

0

Benim durumumda Oreo'da hizmeti başlatmak için faaliyetim olmadığı için tamamen farklıydı.

Bu ön plan hizmeti sorununu çözmek için kullandığım adımlar aşağıdadır -

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

Ve bundan sonra bu hizmeti başlatmak için cmd'nin altında tetikledim -


adb -s "+ serial_id +" shell am startforegroundservice -n com.test.socket.sample / .SocketService


Bu, Oreo cihazlarında etkinlik olmadan hizmete başlamama yardımcı oluyor :)


0

@mikebertiean çözümü neredeyse hile yaptı, ancak ek bir bükülme ile bu sorunu yaşadım - Gingerbread sistemini kullanıyorum ve yalnızca bildirimi çalıştırmak için fazladan bir paket eklemek istemedim. Sonunda şunu buldum: https://android.googlesource.com/platform/frameworks/support.git+/f9fd97499795cd47473f0344e00db9c9837eea36/v4/gingerbread/android/support/v4/app/NotificationCompatGingerbread.java

daha sonra ek bir soruna çarptım - bildirim, uygulamamı çalıştırdığında basitçe öldürüyor (bu sorunu nasıl çözebilirim: Android: OnCreate () Bildirim çağrılarına tıklamaktan nasıl kaçınılır ), bu nedenle toplamda hizmetteki kodum şöyle görünür (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);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.