制作前台服务 运行 直到它停止

Making a foreground service run until it's stopped

我的目标是在后台有一个应用程序 运行,即使屏幕关闭也是如此。就像一个音乐播放器。 现在每个人都声称您需要为此提供前台服务。为此,我正在使用 class 扩展 Worker:

public class WorkerKlasse extends Worker {
    String CHANNEL_ID = "1";
    Context context;
    public WorkerKlasse(
            @NonNull Context context,
            @NonNull WorkerParameters parameters) {
        super(context, parameters);
        this.context = context;
        notificationManager = (NotificationManager)
                context.getSystemService(NOTIFICATION_SERVICE);
    }
    private NotificationManager notificationManager;
    @RequiresApi(Build.VERSION_CODES.O)
    private void createChannel() {
            int importance = NotificationManager.IMPORTANCE_DEFAULT;
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "Kanal", importance);
            channel.setDescription("Beschreibung");
            channel.setSound(null,null);
            // Register the channel with the system; you can't change the importance
            // or other notification behaviors after this

                NotificationManager notificationManager = (NotificationManager)context.getSystemService(NOTIFICATION_SERVICE);
            notificationManager.createNotificationChannel(channel);
    }
    @NonNull
    private ForegroundInfo createForegroundInfo(@NonNull String progress) {
        // Build a notification using bytesRead and contentLength

        Context context = getApplicationContext();
        // This PendingIntent can be used to cancel the worker
        PendingIntent intent = WorkManager.getInstance(context)
                .createCancelPendingIntent(getId());

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            createChannel();
        }

        Notification notification = new NotificationCompat.Builder(context, CHANNEL_ID)
                .setContentTitle("Test")
                .setTicker("Test2")
                .setSound(null)
                .setSmallIcon(R.drawable.ic_launcher_background)
                .setOngoing(true)
                // Add the cancel action to the notification which can
                // be used to cancel the worker
                .addAction(android.R.drawable.ic_delete, "A", intent)
                .build();

        return new ForegroundInfo(1,notification);
    }

    @NonNull
    @Override
    public Result doWork() {
        int testint = getInputData().getInt("testint",0);
        ...
        String progress = "Beginn";
        setForegroundAsync(createForegroundInfo(progress));
        //do something, in my case
        mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.testsound);
        mediaPlayer.start();
        try {
            Thread.sleep(testint);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }            
        return Result.success();
    }

}

(在 return Result.success(); 之前,前台服务应该停止),我在 MainActivity 中从这个开始:

WorkRequest myUploadWork =
        new OneTimeWorkRequest.Builder(WorkerKlasse.class)
                .setInputData(
                        new Data.Builder()
                                .putInt("testint",testint)
                                //...
                                .build()
                )
                .build();

WorkManager
        .getInstance(MainActivity.this)
        .enqueue(myUploadWork);

然而,当屏幕变暗或我按一下电源按钮使其变暗时,它不会保持 运行ning。只有输入密码才能进入phone,它才会继续。不过,顶部的图标表明它是前台服务。

Worker 是关于您正在执行的有限工作,可能与用户进行交互。但它不适用于音乐播放等可能的无限任务。

前台服务用于执行任何具有 visible 进程表示的“后台”作业。

此处的“背景”意味着用户可能没有直接使用您的应用程序,而是有时或以并行方式与之交互。例如,收听您正在播放的音乐。

并且由于 Android... 我不记得了,但现在很常见,任何前台服务都应该有一个通知,该通知始终对用户可见。这是很好的做法。

如果您正在流式传输任何音乐或连续声音,您可能希望在此通知中添加控件,以便用户能够管理播放。

所以,首先,把worker换成前台服务。 现在是主要问题:如果您想安排前台服务的启动怎么办。

您可以创建一个警报,并在它触发时启动前台服务。例如,Whatsapp 一直这样做以同步聊天。

创建告警和启动前台服务的例子有很多:

https://developer.android.com/guide/components/services#StartingAService

https://developer.android.com/training/scheduling/alarms#set

现有解决方案如何:

Mediaplayer 操作 mediaPlayer.start(); 未阻塞线程。 通过制作 Thread.sleep 来阻止它是不好的做法。

前台服务可以用标志 Service.START_STICKY 启动,如果您还要调用 Service.startForeground,它会尽可能长 运行。没有任何流等待一些神秘的超时。