Android - implementing startForeground for a service?

前端 未结 11 1156
不思量自难忘°
不思量自难忘° 2020-11-22 06:26

So I\'m not sure where/how to implement this method to make my service run in the foreground. Currently I start my service by the following in another activity:

<         


        
相关标签:
11条回答
  • 2020-11-22 07:03

    Add given code Service class for "OS >= Build.VERSION_CODES.O" in 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;
    }
    

    Add this permission in manifest file:

     <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    
    0 讨论(0)
  • 2020-11-22 07:05

    If you want to make IntentService a Foreground Service

    then you should override onHandleIntent()like this

    Override
    protected void onHandleIntent(@Nullable Intent intent) {
    
    
        startForeground(FOREGROUND_ID,getNotification());     //<-- Makes Foreground
    
       // Do something
    
        stopForeground(true);                                // <-- Makes it again a normal Service                         
    
    }
    

    How to make notification ?

    simple. Here is the getNotification() Method

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

    Deeper Understanding

    What happens when a service becomes a foreground service

    This happens

    What is a foreground Service ?

    A foreground service,

    • makes sure that user is actively aware of that something is going on in the background by providing the notification.

    • (most importantly) is not killed by System when it runs low on memory

    A use case of foreground service

    Implementing song download functionality in a Music App

    0 讨论(0)
  • 2020-11-22 07:10

    Solution for Oreo 8.1

    I've encountered some problems such as RemoteServiceException because of invalid channel id with most recent versions of Android. This is how i solved it:

    Activity:

    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;
        }
    }
    
    0 讨论(0)
  • 2020-11-22 07:13

    Handle intent on startCommand of service by using.

     stopForeground(true)
    

    This call will remove the service from foreground state, allowing it to be killed if more memory is needed. This does not stop the service from running. For that, you need to call stopSelf() or related methods.

    Passing value true or false indicated if you want to remove the notification or not.

    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
    }
    

    Handle your task when on destroy is called by stopSelf().

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

    Create a notification to keep the service running in foreground.

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

    Give a stop button on notification to stop the service when user needs.

    /**
     * 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)
    }
    
    0 讨论(0)
  • 2020-11-22 07:16

    In my case It was totally different since I was not having activity to launch the service in Oreo.

    Below are the steps which I used to resolve this foreground service issue -

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

    And after that to initiate this service I triggered below cmd -


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


    So this helps me to start service without activity on Oreo devices :)

    0 讨论(0)
  • 2020-11-22 07:17

    This is my code to set the service to foreground:

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

    I need to build a notification using PendingIntent, so that I can start my main activity from the notification.

    To remove the notification, just call the stopForeground(true);

    It is called in the onStartCommand(). Please refer to my code at : https://github.com/bearstand/greyparrot/blob/master/src/com/xiong/richard/greyparrot/Mp3Recorder.java

    0 讨论(0)
提交回复
热议问题