Search code examples
javaandroidandroid-service

Android Service stops broadcasting progress after a while


I have an Activity where the user can download a video. Upon user's click, the Download Service starts to download the content. There is a progress bar in the Activity UI which I would like to update according to download progress in the service which broadcasts the progress periodically.

Everything works fine but after a certain time the service stops sending any broadcast progress, hence, the UI does not update anymore.

Additionally, how I can resume receiving the progress broadcast when the user goes to another Activity and comes back to this Activity? I mean, even if the above issue is solved, when the user presses back button and go to other activity and comes back to this activity, the progress gets lots. How can I check for any existing broadcast and receive it whenever the user comes to this activity.

In the ACTIVITY:

private BroadcastReceiver receiver = new BroadcastReceiver() {
    @Override public void onReceive(Context context, Intent intent) {
        Bundle bundle = intent.getExtras();
        if (bundle != null) {
            Log.d("DownloadService", "Progress Received In Activity");
            Double progress = bundle.getDouble("PROGRESS");
            updateDownloadProgressBar(progress);
        }
    }
};

private void startDownloadService() {
    final String videoId = mItem.getAttributes().get(KEY_ASSET_ID);
    Intent intent = new Intent(this, DownloadService.class);
    intent.putExtra("VIDEOID", videoId);
    startService(intent);
}

in the onResume():

registerReceiver(receiver, new IntentFilter(DownloadService.NOTIFICATION_SERVICE));

in the onPause():

unregisterReceiver(receiver);

In the SERVICE:

private void publishProgress(double progress) {
    Log.d(TAG, "Broadcasting progress from Service");
    Intent intent = new Intent(NOTIFICATION_SERVICE);
    intent.putExtra("PROGRESS", progress);
    sendBroadcast(intent);
}

enter image description here

The download and progress work fine to 38% then stop.


Solution

  • It seems that the service is being stopped/killed from the OS, to avoid that use foreground service so you can make sure it will not be killed from the OS.

    See the sample code below:

    Service

    public class PendingService extends Service {
    
        private final static String TAG = "PendingService";
        public final static int NOTIFICATION_ID = 94;
    
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            startInForeground();
    
            // Do your work here ...
    
            return START_STICKY;
        }
    
        private void startInForeground() {
            String NOTIFICATION_CHANNEL_ID = "default";
            String NOTIFICATION_CHANNEL_NAME = "My Pending Service";
            String NOTIFICATION_CHANNEL_DESC = "This notification holding a pending task";
    
            Intent notificationIntent = new Intent(this, SplashActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
                    .setSmallIcon(R.drawable.notification)
                    .setOngoing(true)
                    .setAutoCancel(true)
                    .setContentIntent(pendingIntent);
    
            if (Build.VERSION.SDK_INT >= 26) {
                NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);
                channel.setDescription(NOTIFICATION_CHANNEL_DESC);
                channel.setSound(null, null);
                NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
                if (notificationManager != null) {
                    notificationManager.createNotificationChannel(channel);
                }
            }
    
            Notification notification = builder.build();
            startForeground(NOTIFICATION_ID, notification);
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            removeNotification(NOTIFICATION_ID);
            // ....
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        private void removeNotification(int notificationId) {
            NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            if (notificationManager != null) {
                notificationManager.cancel(notificationId);
            }
        }
    }
    

    Utils you may need

    class ServiceUtils {
    
        /**
         * @param service: Service to run
         */
        fun startService(context: Context, service: Class<out Service>) {
            val serviceIntent = Intent(context, service)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                context.startForegroundService(serviceIntent)
            } else {
                context.startService(serviceIntent)
            }
        }
    
        /**
         * @return True: if the service is running
         */
        fun isServiceRunning(context: Context, serviceClass: Class<*>): Boolean {
            val manager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
            for (service in manager.getRunningServices(Integer.MAX_VALUE)) {
                if (serviceClass.name == service.service.className) {
                    return true
                }
            }
            return false
        }
    }