如何正确设置LiveData StringObserver

问题描述 投票:0回答:1

具体来说,我需要它在我的前台服务中使用,目前我有这个,当应用程序在前台处于活动状态时它可以工作,但一旦我最小化或关闭它,协程似乎就会停止工作。 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
    }
}
android kotlin observers foreground-service
1个回答
0
投票

好吧,我想我从来不需要字符串观察器,因为它从来没有正常工作过

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
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.