具体来说,我需要它在我的前台服务中使用,目前我有这个,当应用程序在前台处于活动状态时它可以工作,但一旦我最小化或关闭它,协程似乎就会停止工作。 Shell 仍在工作并记录其行,但观察者部分不执行任何操作。如何正确设置它,以便代码块不会经常运行?我应该用什么替换已弃用的 java 部件? (最好是科特林)
另外,还有一点解释:这段代码观察 shell 的输出,一旦这样做,它应该将刷新率更改为模式 0,然后在 5 秒倒计时后将其设置为 2。 我不确定这是否是我应该观察字符串或执行大多数其他操作的方式,因此任何帮助将不胜感激。
import android.app.Application
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Intent
import android.os.Handler
import android.os.IBinder
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.OnLifecycleEvent
import androidx.lifecycle.ProcessLifecycleOwner
import com.jaredrummler.ktsh.Shell
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import pro.themed.manager.R
import java.util.concurrent.TimeUnit
class StringObserver {
private val _stringLiveData = MutableLiveData<String>()
val stringLiveData: LiveData<String> get() = _stringLiveData
fun updateString(newString: String) {
_stringLiveData.postValue(newString)
}
}
class MyForegroundService : Service() {
private val stringObserver = StringObserver()
private val handler = Handler()
private val serviceScope = CoroutineScope(Dispatchers.IO)
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
Thread {}.start()
Shell.SH.run("su -c getevent | grep 0003") {
onStdOut = { line: String ->
Log.d("StringObserver", "String changed: $line")
handler.post {
stringObserver.updateString(newString = line)
}
}
onStdErr = { line: String ->
Log.d("ShellCommand", "StdErr: $line") // Log any errors
}
timeout = Shell.Timeout(100, TimeUnit.MILLISECONDS)
}
// Create a LifecycleOwner using Application context
val appContext = applicationContext as Application
val lifecycleOwner = ProcessLifecycleOwner.get()
val notificationManager =
getSystemService(NotificationManager::class.java) as NotificationManager
lifecycleOwner.lifecycle.addObserver(object : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun connectListener() {
// Observe changes to the stringLiveData when the app is in the foreground
stringObserver.stringLiveData.observe(lifecycleOwner) { _ ->
// Execute code block when the string changes
serviceScope.launch {
try {
val shell2 = Shell.SU
shell2.run("service call SurfaceFlinger 1035 i32 0")
Log.d("test", "setting 120")
var countdown = 5
while (countdown > 0) {
delay(1000) // 1-second delay
countdown -= 1
Log.d("test", "Countdown: $countdown")
}
// Check if the timer has reached 0 and execute "setting 60" only once
if (countdown == 0) {
shell2.run("service call SurfaceFlinger 1035 i32 2")
Log.d("test", "setting 60")
}
} catch (e: Exception) {
Log.e("test", "Error in coroutine: ${e.message}")
}
}
}
}
})
val CHANNELID = "Foreground Service ID"
val channel = NotificationChannel(
CHANNELID, CHANNELID, NotificationManager.IMPORTANCE_LOW
)
notificationManager.createNotificationChannel(channel)
val notification =
NotificationCompat.Builder(this, CHANNELID)
.setSmallIcon(R.drawable.palette_48px)
.setContentTitle("")
.setContentText("")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
startForeground(1001, notification.build())
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
// Cancel the serviceScope when the service is destroyed
serviceScope.cancel()
super.onDestroy()
}
override fun onBind(intent: Intent): IBinder? {
return null
}
}
getSystemService(NotificationManager::class.java).createNotificationChannel(channel)
val notification = NotificationCompat.Builder(this, CHANNELID)
.setSmallIcon(R.drawable.palette_48px)
.setContentTitle("")
.setContentText("")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
startForeground(1001, notification.build())
return super.onStartCommand(intent, flags, startId)
}
override fun onBind(intent: Intent): IBinder? {
return null
}
}
好吧,我想我从来不需要字符串观察器,因为它从来没有正常工作过
package pro.themed.manager.utils
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.lifecycle.ProcessLifecycleOwner
import com.jaredrummler.ktsh.Shell
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import pro.themed.manager.R
import java.util.concurrent.TimeUnit
class MyForegroundService : Service() {
private val serviceScope = CoroutineScope(Dispatchers.IO)
private var countdown = 3 // Initial countdown value
private val shell2 = Shell.SU
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
Thread {}.start()
Shell.SH.run("su -c getevent | grep 0003") {
onStdOut = {
CoroutineScope(Dispatchers.IO).launch {
shell2.run("service call SurfaceFlinger 1035 i32 0")
Log.d("test", "setting 120")
countdown = 3 // Reset countdown to the initial value
while (countdown > 0) {
delay(1000)
countdown -= 1
}
if (countdown == 0) {
shell2.run("service call SurfaceFlinger 1035 i32 2")
Log.d("test", "setting 60")
}
}
}
onStdErr = { line: String ->
Log.d("ShellCommand", "StdErr: $line")
}
timeout = Shell.Timeout(200, TimeUnit.MILLISECONDS)
}
val lifecycleOwner = ProcessLifecycleOwner.get()
val notificationManager =
getSystemService(NotificationManager::class.java) as NotificationManager
val notificationChannelId = "ForegroundServiceChannel"
val notificationBuilder = NotificationCompat.Builder(this, notificationChannelId)
.setSmallIcon(R.drawable.palette_48px)
.setContentTitle("")
.setContentText("")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
val notificationChannel = NotificationChannel(
notificationChannelId,
notificationChannelId,
NotificationManager.IMPORTANCE_LOW
)
notificationManager.createNotificationChannel(notificationChannel)
startForeground(1001, notificationBuilder.build())
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
serviceScope.cancel()
super.onDestroy()
}
override fun onBind(intent: Intent): IBinder? {
return null
}
}