Android - mengimplementasikan startForeground untuk layanan?


124

Jadi saya tidak yakin di mana / bagaimana menerapkan metode ini untuk membuat layanan saya berjalan di latar depan. Saat ini saya memulai layanan saya dengan mengikuti di aktivitas lain:

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

Dan kemudian di myServices 'onCreate () saya mencoba startForeground () ...?

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

Jadi ya saya agak bingung dan tidak yakin bagaimana menerapkan ini.


Ini tidak berhasil, setidaknya sejauh yang saya tahu layanan saya masih berfungsi sebagai layanan latar belakang dan terbunuh.
JDS

Jawaban:


131

Saya akan mulai dengan mengisi file Notification. Berikut adalah contoh proyek yang mendemonstrasikan penggunaan startForeground().


8
Apakah mungkin menggunakan startForeground () tanpa pemberitahuan? Atau bisakah kita memperbarui pemberitahuan yang sama nanti?
JRC

2
Apakah ada alasan tertentu yang Anda gunakan 1337?
Cody

33
@DoctorOreo: Ini harus unik di dalam aplikasi, meskipun tidak harus unik di perangkat. Saya memilih 1337 karena, yah, itu 1337 . :-)
CommonsWare

Pertanyaan @JRC adalah pertanyaan yang bagus. Apakah mungkin menggunakan startForeground () tanpa pemberitahuan?
Snicolas

2
@Snicolas: Terima kasih telah menunjukkan kelemahan di Android. Saya akan berusaha memperbaikinya.
CommonsWare

78

Dari aktivitas utama Anda, mulai layanan dengan kode berikut:

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

Kemudian dalam layanan onCreate()Anda untuk Anda akan membuat notifikasi dan menyetelnya sebagai latar depan seperti:

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 bagaimana cara memperbarui pemberitahuan ini dari MainActivity?
Roon13

1
@ Roon13 menggunakan ID, dalam hal ini 1337 ... Anda harus dapat membuat pemberitahuan baru dan memanggil startForeground dengan ID
mikebertiean


@mikebertiean Bagaimana cara memanggil startForeground dari MainActivity? juga bagaimana cara menghapus notfication dari MainActvity saat proses selesai?
Roon13

@ Mikebertiean Saya mengerti bahwa saya harus memanggil startForeground lagi di kelas Layanan tetapi bagaimana? Apakah saya harus memanggil startService () lagi?
Roon13

30

Ini adalah kode saya untuk mengatur layanan ke latar depan:

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

}

Saya perlu membuat notifikasi menggunakan PendingIntent, sehingga saya bisa memulai aktivitas utama saya dari notifikasi tersebut.

Untuk menghapus notifikasi, cukup panggil stopForeground (true);

Ini dipanggil di onStartCommand (). Silakan merujuk ke kode saya di: https://github.com/bearstand/greyparrot/blob/master/src/com/xiong/richard/greyparrot/Mp3Recorder.java


Jika Anda menghapus notifikasi yang memanggil stopForeground (true), Anda membatalkan layanan
startforeground

6
Dari mana Anda memanggil metode ini?
Srujan Barai

7
Intent.FLAG_ACTIVITY_NEW_TASKtidak valid dalam konteks PendingIntent.
mixel

30

Solusi untuk Oreo 8.1

Saya mengalami beberapa masalah seperti RemoteServiceException karena ID saluran tidak valid dengan versi Android terbaru. Beginilah cara saya menyelesaikannya:

Aktivitas :

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
}

SETARA JAWA

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
Anda dapat menggunakan ContextCompat.startForegroundService(Context,Intent)dalam Aktivitas Anda yang akan melakukan hal yang benar. ( developer.android.com/reference/android/support/v4/content/… )
Simon Featherstone

3
Anda mungkin ingin menggunakan .setCategory(NotificationCompat.CATEGORY_SERVICE)daripada Notification.CATEGORY_SERVICEjika min API Anda <21
Someone Somewhere

6
Harap dicatat bahwa penargetan aplikasi Build.VERSION_CODES.P(API level 28) atau yang lebih baru harus meminta izin Manifest.permission.FOREGROUND_SERVICEuntuk menggunakan startForeground()- lihat developer.android.com/reference/android/app/…
Vadim Kotov

21

Selain jawaban RAWA , kode damai ini:

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

Anda dapat mengubah ke:

ContextCompat.startForegroundService(context, yourIntent);

Jika Anda akan melihat ke dalam metode ini maka Anda dapat melihat bahwa metode ini melakukan semua pekerjaan pemeriksaan untuk Anda.


9

Jika Anda ingin menjadikan IntentService sebagai Layanan Latar Depan

maka Anda harus menimpa onHandleIntent()seperti ini

Override
protected void onHandleIntent(@Nullable Intent intent) {


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

   // Do something

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

}

Bagaimana cara membuat notifikasi?

sederhana. Inilah getNotification()Metodenya

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

Pemahaman Lebih Dalam

Apa yang terjadi saat layanan menjadi layanan latar depan

Ini terjadi

masukkan deskripsi gambar di sini

Apa itu Layanan Latar Depan?

Sebuah layanan latar depan,

  • memastikan bahwa pengguna secara aktif mengetahui bahwa ada sesuatu yang terjadi di latar belakang dengan memberikan notifikasi.

  • (yang terpenting) tidak dimatikan oleh Sistem saat memori hampir habis

Kasus penggunaan layanan latar depan

Menerapkan fungsionalitas pengunduhan lagu di Aplikasi Musik


5

Tambahkan kode yang diberikan Kelas layanan untuk "OS> = Build.VERSION_CODES.O" di 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;
}

Tambahkan izin ini di file manifes:

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

1

Tangani maksud pada startCommand layanan dengan menggunakan.

 stopForeground(true)

Panggilan ini akan menghapus layanan dari keadaan latar depan , sehingga memungkinkan untuk dimatikan jika diperlukan lebih banyak memori. Ini tidak menghentikan layanan dari berjalan. Untuk itu, Anda perlu memanggil stopSelf () atau metode terkait.

Passing value true or false ditunjukkan jika Anda ingin menghapus notifikasi atau tidak.

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
}

Menangani tugas Anda saat dihancurkan dipanggil oleh stopSelf () .

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

Buat notifikasi untuk menjaga layanan tetap berjalan di latar depan.

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

Berikan tombol stop pada notifikasi untuk menghentikan layanan saat pengguna membutuhkan.

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

Catatan: Jika aplikasi Anda menargetkan API level 26 atau lebih tinggi, sistem akan memberlakukan batasan pada penggunaan atau pembuatan layanan latar belakang kecuali jika aplikasi itu sendiri berada di latar depan.

Jika suatu aplikasi perlu membuat layanan latar depan, aplikasi tersebut harus memanggil startForegroundService(). Metode itu membuat layanan latar belakang, tetapi metode memberi sinyal ke sistem bahwa layanan akan mempromosikan dirinya sendiri ke latar depan.

Setelah layanan dibuat, layanan harus memanggilnya startForeground() method within five seconds.


1
Saya harap Anda berbicara tentang pertanyaan saat ini. Jika tidak, tidak ada aturan seperti itu di komunitas Stackoverflow
Farid

@RogerGusmao dalam kode lingkungan siap produksi tidak akan selalu menyimpan proyek Anda. Selain itu - ada banyak contoh bagus dengan kode di bawah dan di atas jawaban saya .. Proyek saya mengalami masalah selama rilis persis karena saya tidak tahu tentang startForegroundServicemetode
Andrii Kovalchuk

0

Dalam kasus saya Ini sangat berbeda karena saya tidak memiliki aktivitas untuk meluncurkan layanan di Oreo.

Berikut adalah langkah-langkah yang saya gunakan untuk menyelesaikan masalah layanan latar depan ini -

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

Dan setelah itu untuk memulai layanan ini saya memicu di bawah cmd -


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


Jadi ini membantu saya memulai layanan tanpa aktivitas di perangkat Oreo :)


0

Solusi @mikebertiean hampir berhasil, tetapi saya memiliki masalah ini dengan twist tambahan - saya menggunakan sistem Gingerbread dan saya tidak ingin menambahkan beberapa paket tambahan hanya untuk menjalankan notifikasi. Akhirnya saya menemukan: https://android.googlesource.com/platform/frameworks/support.git+/f9fd97499795cd47473f0344e00db9c9837eea36/v4/gingerbread/android/support/v4/app/NotificationCompatGingerbread.java

kemudian saya mengalami masalah tambahan - pemberitahuan hanya mematikan aplikasi saya ketika berjalan (cara mengatasi masalah ini: Android: Bagaimana menghindari mengklik pada panggilan Pemberitahuan onCreate () ), jadi secara total kode saya dalam layanan terlihat seperti ini (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);
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.