Android 服务在一段时间后停止广播进度

Android Service stops broadcasting progress after a while

我有一个 Activity 用户可以下载视频的地方。用户单击后,下载服务开始下载内容。 Activity UI 中有一个进度条,我想根据定期广播进度的服务中的下载进度更新它。

一切正常,但在一定时间后服务停止发送任何广播进度,因此,UI 不再更新。

此外,当用户转到另一个 Activity 并返回此 Activity 时,我如何恢复接收进度广播?我的意思是,即使上述问题已解决,当用户按下后退按钮并转到其他 activity 并返回到此 activity 时,进度会很大。我如何检查任何现有广播并在用户访问此 activity.

时接收它

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

在 onResume() 中:

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

在 onPause() 中:

unregisterReceiver(receiver);

在服务中:

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

下载和进度正常到 38% 然后停止。

似乎该服务正在 stopped/killed 来自 OS,以避免使用前台服务,因此您可以确保它不会被 OS 杀死。

查看下面的示例代码:

服务

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 你可能需要

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