模仿秒表行为|如果应用程序被终止,计时器将保持不变

问题描述

我正在使用天文钟-但在通知中保留天文钟-服务-应用程序对我来说很困难

场景-

  1. 点击按钮启动计时器
  2. 应用在后台运行时,请在自定义通知中启动计时器。
  3. 单击“计时器通知”,在通知托盘中启动带有计时器计数的应用程序
  4. Killing应用程序应在通知中继续运行计时器,从应用程序图标打开应用程序,或通知应从通知中的相同计数继续运行计时器。

方法-

  1. 在暂停时节省时间
  2. 恢复应用程序时-将计时器值设置为天文钟表

onPause代码-

   override fun onPause() {
    super.onPause()
    MainActivity.appPauseTime = SystemClock.elapsedRealtime()
    
    val intent = Intent(activity,MyTimerService::class.java)
    intent.action = MyTimerService.START_FOREGROUND_SERVICE
    intent.putExtra("timer",chronometer.base)
    activity?.startService(intent)
}

onResume的代码-

 override fun onResume() {
    super.onResume()
    if (MainActivity.appPauseTime > 0L) {
        MainActivity.appResumeTime = SystemClock.elapsedRealtime()
        startTimer(SystemClock.elapsedRealtime() - (MainActivity.appResumeTime - MainActivity.appPauseTime))
        val intent = Intent(activity,MyTimerService::class.java)
        intent.action = MyTimerService.STOP_FOREGROUND_SERVICE
        activity?.stopService(intent)
    }
}

没有寻找勺子饲料的答案,所以在下面发布了答案。

解决方法

我找到了一种运行计时器的方法-即天文钟

在片段或活动布局中设置天文钟表

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".FirstFragment">

<Button
    android:id="@+id/button_first"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/next"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/chronometer" />


<Chronometer
    android:id="@+id/chronometer"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="20dp"
    android:gravity="center"
    android:textAppearance="@style/TextAppearance.AppCompat.Large"
    android:textColor="@android:color/holo_red_dark"
    android:textSize="48sp"
    android:textStyle="bold"
    android:visibility="visible"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"/>

单击按钮或您想要的任何情况下启动计时器-

private fun startTimer(startTime: Long) {
    chronometer.base = startTime
    chronometer.setOnChronometerTickListener {
        Log.i("Timer--->","Countdown---> " + chronometer.base)
        // formattedTime = getFormattedTime(chronometer.base)
    }
    chronometer.start()
}

最主要的是通过天文钟发布通知-在这里,我会让您知道该怎么做

override fun onPause() {
    super.onPause()
    val intent = Intent(activity,MyTimerService::class.java)
    intent.action = MyTimerService.START_FOREGROUND_SERVICE
    intent.putExtra("timer",chronometer.base)
    activity?.startService(intent)
}

这是Service类-确保您在清单中注册它并提供前台用户的权限

class MyTimerService : Service() {

private lateinit var notificationView: RemoteViews
private lateinit var notiBuilder: Notification

companion object {
    const val NOTIFICATION_CHANNEL_ID = "100"
    const val NOTIFICATION_ID = 10
    const val START_FOREGROUND_SERVICE = "start_foreground_service"
    const val STOP_FOREGROUND_SERVICE = "stop_foreground_service"
}


override fun onBind(p0: Intent?): IBinder? {
    return null
}

override fun onCreate() {
    super.onCreate()
    notificationView = RemoteViews(packageName,R.layout.notification_layout)
    createNotification()
}

private fun getPendingIntent(): PendingIntent? {
    // Create an explicit intent for an Activity in your app
    val intent = Intent(this,MainActivity::class.java).apply {
        flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
    }

    // intent.putExtra("timer",notificationView.)
    return PendingIntent.getActivity(this,intent,0)


}

private fun createNotification() {
    // Create the NotificationChannel,but only on API 26+ because
    // the NotificationChannel class is new and not in the support library
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        createNotificationChannelForOreo()
    } else {
        createNotificationBelowOreo()
    }
}

private fun createNotificationBelowOreo() {
    // Create notification builder.
    val builder = NotificationCompat.Builder(this)
        .setWhen(System.currentTimeMillis())
        .setSmallIcon(R.drawable.ic_baseline_timer_24)
        .setStyle(NotificationCompat.DecoratedCustomViewStyle())
        .setCustomContentView(notificationView)
        .setContentIntent(getPendingIntent())
        .setContentTitle(baseContext.getString(R.string.app_name))
        .setContentText("Active Session")
        .setAutoCancel(true)
        .setPriority(Notification.PRIORITY_MAX)

    // Build the notification.
    notiBuilder = builder.build()
}


@RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannelForOreo() {
    val chan =
        NotificationChannel(
            NOTIFICATION_CHANNEL_ID,baseContext.getString(R.string.channel_name),NotificationManager.IMPORTANCE_DEFAULT
        )
    // chan.lightColor = Color.BLUE
    chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
    val manager = (getSystemService(NOTIFICATION_SERVICE) as NotificationManager)
    manager.createNotificationChannel(chan)
    val notificationBuilder = NotificationCompat.Builder(this,NOTIFICATION_CHANNEL_ID)
    notiBuilder = notificationBuilder.setOngoing(true)
        .setSmallIcon(R.drawable.ic_baseline_timer_24)
        .setContentTitle(baseContext.getString(R.string.app_name))
        .setContentText("Active Session")
        .setAutoCancel(true)
        .setPriority(NotificationManager.IMPORTANCE_MIN)
        .setStyle(NotificationCompat.DecoratedCustomViewStyle())
        .setCustomContentView(notificationView)
        .setCategory(Notification.CATEGORY_SERVICE)
        .setContentIntent(getPendingIntent())
        .build()
    val notificationManager = NotificationManagerCompat.from(this)
    notificationManager.notify(NOTIFICATION_ID,notificationBuilder.build())
}


private fun showNotification() {
    // Start foreground service.
    startForeground(NOTIFICATION_ID,notiBuilder)
}

override fun onDestroy() {
    super.onDestroy()
}

override fun onStartCommand(intent: Intent?,flags: Int,startId: Int): Int {
    super.onStartCommand(intent,flags,startId)
    if (intent?.extras != null) {
        when (intent.action) {

            START_FOREGROUND_SERVICE -> {
                val timestamp = intent.getLongExtra("timer",0)
                // set chronometer
                notificationView.setChronometer(R.id.chronometer,timestamp,null,true)
                // show notification
                showNotification()
            }

            STOP_FOREGROUND_SERVICE -> {
                stopForeground(true)
                stopSelf()
            }
        }
    }
    return START_STICKY
}

}

要处理计时器持久性,请将计时器的时间保存在onPause中-

 override fun onPause() {
    super.onPause()
    **Make sure you are saving this time at central place**
    MainActivity.appPauseTime = chronometer.base
}

在onResume中-

override fun onResume() {
    super.onResume()
    if (MainActivity.appPauseTime > 0L) {
        startTimer(MainActivity.appPauseTime)
        val intent = Intent(activity,MyTimerService::class.java)
        intent.action = MyTimerService.STOP_FOREGROUND_SERVICE
        activity?.stopService(intent)
    }
}

如果您认为有帮助,请告诉我并进行投票。