Android:当应用程序关闭 30 秒时,通知会延迟显示并停止更新(在 OnePlus 8T 上)

2024-01-14

谷歌有自己的时钟应用程序,其中包括秒表。我目前正在尝试在我的应用程序中创建一个(计数)计时器,或者您可以将其称为秒表,它将能够在后台运行,当它在后台运行时,我希望它也显示通知,显示计时时间和“停止”按钮(所有这些都发生在谷歌时钟应用程序中(see here https://stackoverflow.com/q/67028013/8099601))。对于我的应用程序中的计时器,我使用一个处理程序来发布一个 Runnable,它正在发布自己。我正在用 Java 编写我的应用程序。

定义“计时器”的代码(处理程序和可运行):

Handler timerHandler = new Handler();
Runnable timerRunnable = new Runnable() {
    @Override
    public void run() {
        long millis = System.currentTimeMillis() - startTime;
        seconds = (millis / 1000) + PrefUtil.getTimerSecondsPassed();
        timerHandler.postDelayed(this, 500);
    }
};

我的 onPause 函数:

@Override
public void onPause() {
    super.onPause();

    if (timerState == TimerState.Running) {
        timerHandler.removeCallbacks(timerRunnable);
        //TODO: start background timer, show notification
    }

    PrefUtil.setTimerSecondsPassed(seconds);
    PrefUtil.setTimerState(timerState);
}

如何在我的应用程序中实现后台服务和通知?

Edit

我已成功创建运行计时器的前台服务,但有两个问题:

  1. 当我在大约 5 分钟后运行应用程序时,通知会延迟 10 秒显示。
  2. 通知在启动/恢复后大约 30 秒后停止更新(计时器在后台继续运行,但通知不会随计时器一起更新)。

这是我的Services code:

public class TimerService extends Service {

    Long startTime = 0L, seconds = 0L;
    boolean notificationJustStarted = true;
    Handler timerHandler = new Handler();
    Runnable timerRunnable;
    NotificationCompat.Builder timerNotificationBuilder = new NotificationCompat.Builder(this, CHANNEL_ID);
    public static final String TIMER_BROADCAST_ID = "TimerBroadcast";
    Intent timerBroadcastIntent = new Intent(TIMER_BROADCAST_ID);

    @Override
    public void onCreate() {
        Log.d(TAG, "onCreate: started service");
        startForeground(1, new NotificationCompat.Builder(this, CHANNEL_ID).setSmallIcon(R.drawable.timer).setContentTitle("Goal In Progress").build());
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        String goalName = intent.getStringExtra(PublicMethods.getAppContext().getString(R.string.timer_notification_service_current_goal_extra_name));
        startTime = System.currentTimeMillis();
        notificationJustStarted = true;
        timerRunnable = new Runnable() {
            @Override
            public void run() {
                long millis = System.currentTimeMillis() - startTime;
                seconds = (millis / 1000) + PrefUtil.getTimerSecondsPassed();
                updateNotification(goalName, seconds);
                timerHandler.postDelayed(this, 500);
            }
        };
        timerHandler.postDelayed(timerRunnable, 0);

        return START_STICKY;
    }

    public void updateNotification(String goalName, Long seconds) {
        try {
            if (notificationJustStarted) {
                Intent notificationIntent = new Intent(this, MainActivity.class);
                PendingIntent pendingIntent = PendingIntent.getActivity(this,
                        0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);
                timerNotificationBuilder.setContentTitle("Goal In Progress")
                        .setOngoing(true)
                        .setSmallIcon(R.drawable.timer)
                        .setContentIntent(pendingIntent)
                        .setOnlyAlertOnce(true)
                        .setOngoing(true)
                        .setPriority(NotificationCompat.PRIORITY_MAX);
                notificationJustStarted = false;
            }

            timerNotificationBuilder.setContentText(goalName + " is in progress\nthis session's length: " + seconds);

            startForeground(1, timerNotificationBuilder.build());
        } catch (Exception e) {
            Log.d(TAG, "updateNotification: Couldn't display a notification, due to:");
            e.printStackTrace();
        }
    }

    @Override
    public void onDestroy() {
        timerHandler.removeCallbacks(timerRunnable);
        PrefUtil.setTimerSecondsPassed(seconds);
        super.onDestroy();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

这是我在片段中启动它的方式:

private void startTimerService() {
        Intent serviceIntent = new Intent(getContext(), TimerService.class);
        serviceIntent.putExtra(getString(R.string.timer_notification_service_current_goal_extra_name), "*Current Goal Name Here*");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            Objects.requireNonNull(getContext()).startForegroundService(serviceIntent);
        }
}

UPDATE

当我在谷歌像素模拟器上运行该应用程序时,我没有遇到列出的任何问题


如果您将递归替换为即使启用了电池限制,解决方案也会工作得更好postDelayed with scheduleAtFixedRate在你的TimerService inside onStartCommand功能。像这样的东西:

        TimerTask timerTaskNotify = new TimerTask() {
            @Override
            public void run() {
                // add a second to the counter
                seconds++;

                //update the notification with that second
                updateNotification(goalName, seconds);

                //Print the seconds
                Log.d("timerCount", seconds + "");

                //Save the seconds passed to shared preferences
                PrefUtil.setTimerSecondsPassed(TimerService.this,seconds);
            }
        };
        Timer timerNotify = new Timer();
        timerNotify.scheduleAtFixedRate(timerTaskNotify, 0, 1000);

附:如果您授予许可,我可以更新您的 git 存储库)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android:当应用程序关闭 30 秒时,通知会延迟显示并停止更新(在 OnePlus 8T 上) 的相关文章

  • android 销毁时是否有任何视图回调?

    我有一个自定义视图组件 我在片段或活动中使用了它 我想知道当它从片段 活动中销毁时是否有回调 View 没有回调 除了finalize 但我不认为这就是你所要求的 查看有onDetachedFromWindow 当它从屏幕上移除时 但这与它
  • 免费和付费版本 Android 应用程序的最佳方法?

    我开发了一个 Android 应用程序 我希望它可以作为免费版本和付费版本提供 最好的方法是什么 我可以想到三种解决方案 将项目分成两个分支并维护它们 创建一个库项目并有两个附加项目 一个 免费 版本和一个 付费 版本 使用应用内结算 问
  • 如何找到 Oracle 数据库的 URL?

    如何找到 Oracle 数据库的 URL 和端口 Example jdbc oracle thin host port dbName 用户名 密码 是否有我可以查看的 SQL 命令或日志 配置文件 对于甲骨文来说 有一个tnsnames o
  • AsyncTask:DoInBackground(String ...)与DoInBackground(Params ...)冲突?

    当尝试使用时Async task要执行 HTTP post 我得到以下信息 ASyncTask DoInBackground String clashes with DoInBackground Params in Android os A
  • 如何使用键盘上的“删除”按钮作为从 JTable 中删除行的快捷方式[重复]

    这个问题在这里已经有答案了 可能的重复 如何制作删除按钮来删除JTable中的行 https stackoverflow com questions 13236206 how to make delete button to delete
  • 如何在 Android 上通过 RTMP 进行流式传输?

    我正在尝试在远程服务器上播放视频文件 视频格式为flv 服务器为Flash Media Server3 5 我将通过 RTMP 连接到服务器并使用 Android Media Player 实现视频文件的播放 真的吗 可能吗 任何帮助都是我
  • 将 XML 从网站解析到 Android 设备

    我正在启动一个 Android 应用程序 它将解析来自网络的 XML 我创建了一些 Android 应用程序 但它们从未涉及解析 XML 我想知道是否有人对最佳方法有任何建议 这是一个例子 try URL url new URL your
  • Java 空值检查

    我有一个thread1 if object null object play 和另一个thread2可以写null into object随时参考 我将同时运行这些线程 我知道thread2可以重写object后参考null检查并会抛出Nu
  • 如果我清理了反向引用,我是否可以观察 ViewModel?

    建议的实施方式ViewModel是通过使用来公开变化的数据LiveData活动 片段和视图的对象 有一些情况 当LiveData不是一个理想的答案或根本没有答案 自然的选择是将观察者模式应用于ViewModel 使其成为可观察的 注册观察员
  • 将字符串转换为字符并按降序排序(ascii)

    我正在创建一个程序 该程序将使用户输入整数 一个接一个 存储在数组中并按降序显示整数 该程序还要求用户输入一个字符串 使用以下命令将其转换为字符string toCharArray 我已经正确地按降序显示整数 问题是我不知道如何按降序显示字
  • Wildfly 10.1 消耗所有核心

    我们最近将银行应用程序从 java 1 6 升级到 1 8 将 jboss 4 x 升级到 wildfly 10 1 我们观察到 java 消耗了机器上可用的所有核心 10 有人可以告诉是什么原因吗 通常情况下 jboss 4 x 的最大
  • 通过使用 DownloadManager,我如何查看设备中所有活动/正在运行的下载?

    通过使用 DownloadManager 我如何查看设备中所有活动 正在运行的下载 My code DownloadManager Query query null Cursor c null DownloadManager downloa
  • 通过 ssh 发送命令并读取输出结果

    我有代码通过 ssh 连接到远程服务器并向其发送 2 个或更多命令 例如 cd export home ops bin和 viewlinkload time 20131205 19 但我没有看到命令执行 也没有收到结果 我需要获取服务器返回
  • 加载带有月份标题的 recyclerview 不同类型适配器

    如果从 api 获取不同的月份名称 则尝试将月份名称显示为标题 在这里 我加载月份标题 但是当我加载标题时 它不会加载其他视图 如果数据不同 我需要将月份加载为标题 并且还加载其他视图持有者 我看到一些例子 他们都在 Model 类中使用
  • Eclipse 在单独的窗口中打开代码

    我正在 eclipse 中编程 在两个显示器设置上运行 在其中一台显示器上 我只获得了项目资源管理器和编辑器作为自定义透视图 而在另一台显示器上 我获得了其他工具 例如控制台 调试 任务 变量 断点等 例如 当我单击任务视图中的任务时 这将
  • 找出该月第一个星期日/星期一等的日期

    我想在java中检测每个月第一周 第二周的第一个星期日 星期一的日期 我怎样才能实现它 我已经检查了 java 中的 Calendar 类和 Date 类 但无法找到解决方案 所以请帮助我解决这个问题 Calendar calendar C
  • 协程中未捕获异常

    我似乎无法在协程中完成错误处理 我读了很多文章并且异常处理文档 https kotlinlang org docs reference coroutines exception handling html exception propaga
  • Pebble 应用程序设置中的开发人员选项

    I am following this manual http www sitepoint com pebble watch development javascript and I don t have the Developers Op
  • 混合语言源目录布局

    我们正在运行一个使用多种不同语言的大型项目 Java Python PHP SQL 和 Perl 到目前为止 人们一直在自己的私有存储库中工作 但现在我们希望将整个项目合并到一个存储库中 现在的问题是 目录结构应该是什么样的 我们应该为每种
  • 安装 JDK 时出错:keytool 命令需要已安装的 proc fs (/proc)。 Linux 的 Windows 子系统

    我尝试在 Linux 的 Windows 子系统 Ubuntu 14 04 上安装 Oracle JDK 1 7 但出现以下错误 the keytool command requires a mounted proc fs proc Jav

随机推荐