我的 Android 应用程序 (Jetpack Compose) 需要在非常精确的时间触发手机振动器(最大延迟几毫秒)。
振动器必须在手机和应用程序的任何状态下触发:手机唤醒并且应用程序在前台,手机处于空闲状态并且应用程序在后台,其他应用程序获得大量处理器,...我只想告诉用户“请不要关闭应用程序,而是用手机做任何您想做的事”:-)
为此,我使用(请参阅下面的代码):
它工作得很好,但在某些情况下(手机长时间闲置,很多应用程序运行,...),振动器启动有延迟,可以达到几秒钟,这在我的用例中并不好:-)
您是否看到我应该使用任何其他 Android 例程或工具来使我的振动器触发非常精确?谢谢!
<application>
...
<receiver android:name=".AlarmReceiver" />
<service android:name=".VibrationService" android:exported="false" android:foregroundServiceType="phoneCall"/>
...
</application>
...
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL" />
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
Project4Theme {
ScheduleVibrationAlarm(context = this)
}
}
}
}
}
@Composable
fun ScheduleVibrationAlarm(context: Context) {
var calendar by remember { mutableStateOf(Calendar.getInstance()) }
var timeDifference by remember { mutableStateOf<Long?>(null) }
Column(
) {
Text(text = "Schedule Vibration Alarm")
Button(onClick = {
Thread {
try {
// Get NTP time
val ntpClient = NTPUDPClient()
ntpClient.defaultTimeout = 10000
val inetAddress = InetAddress.getByName("pool.ntp.org")
val timeInfo = ntpClient.getTime(inetAddress)
timeInfo.computeDetails()
// Get local system time
val localTime = System.currentTimeMillis()
// Get difference
val ntpTime = timeInfo.message.transmitTimeStamp.time
timeDifference = ntpTime - localTime
// Set vibrator alarm time (17:00 today)
calendar.set(Calendar.HOUR_OF_DAY, 17)
calendar.set(Calendar.MINUTE, 0)
calendar.set(Calendar.SECOND, 0)
calendar.set(Calendar.MILLISECOND, (timeDifference!!.toInt()*-1))
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent1 = Intent(context, AlarmReceiver::class.java)
val pendingIntent1 = PendingIntent.getBroadcast(context, 0, intent1, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.timeInMillis, pendingIntent1)
} catch (e: Exception) {
Log.e("NTP", "Fail on NTP get", e)
}
}.start()
}) {
Text(text = "Set Vibrator Alarm")
}
}
}
class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val vibrationIntent = Intent(context, VibrationService::class.java)
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
context.startForegroundService(vibrationIntent)
} else {
context.startService(vibrationIntent)
}
}
}
class VibrationService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
// Create a notif (if not, Android kill foreground service :)
createNotificationChannel()
val notification = NotificationCompat.Builder(this, "VibrationServiceChannel")
.setContentTitle("Vibrator")
.setContentText("Vibrator is running ")
.build()
// Start foreground service
startForeground(1, notification)
// Vibrate
val vibrator = getSystemService(VIBRATOR_SERVICE) as Vibrator
vibrator.vibrate(1000)
// Stop service
stopSelf()
return START_NOT_STICKY
}
override fun onBind(intent: Intent?): IBinder? = null
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val serviceChannel = NotificationChannel(
"VibrationServiceChannel",
"Vibration Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
)
val manager = getSystemService(NotificationManager::class.java)
manager.createNotificationChannel(serviceChannel)
}
}
}
您想要的东西在 Android 手机上是不可能实现的。 该操作系统不是实时操作系统,它的设计初衷并不是提供这种时间关键型性能。 如果您确实需要此功能,则需要完全使用不同的操作系统。 或者您需要重新考虑您的要求 - 为什么您需要这些振动精确到秒?