Android:如何在活动和在不同进程中运行的服务之间进行通信?

如何解决Android:如何在活动和在不同进程中运行的服务之间进行通信?

我在与 service 不同的 process 中开始 activityservice 旨在即使在应用程序关闭时也能运行。 从 service 启动 activity 后,我关闭了应用程序。现在,当我重新打开应用程序时,service 可能正在运行,也可能没有运行。但我还没有办法知道 service 是否正在运行。 我怎样才能做到这一点?

仅供参考:我已经在 SO 上检查了所有相关的答案,但是当服务在不同的进程中运行时,它们都不起作用。 这是我得到的最接近的答案 link。但是这个答案似乎有缺陷,我也想听听您的意见。

这是我目前正在做的事情:

AndroidManifest.xml

<service
        android:name=".services.MyService"
        android:enabled="true"
        android:exported="false"
        android:process=":backgroundProcess" />

MainApplication.kt(目的:只有一个 SettingsRepository 类的实例)

class MainApplication : Application() {

   val settingsRepository by lazy { SettingsRepository(this) }

}

SettingsRepository.kt(目的:在 Preference DataStore 中保存服务的运行状态)

class SettingsRepository(context: Context) {

    private val dataStore = context.createDataStore(name = "settings_prefs")

    companion object {
        val SERVICE_STATE_KEY = booleanPreferencesKey("SERVICE_STATE_KEY")
    }

    suspend fun saveServiceStatetoDataStore(state: Boolean) {
        dataStore.edit {
            it[SERVICE_STATE_KEY] = state
        }
    }

    val getServiceStateFromDataStore: Flow<Boolean> = dataStore.data.map {
        val state = it[SERVICE_STATE_KEY] ?: false
        state
    }

}

Service.kt

private lateinit var settingsRepository: SettingsRepository

override fun onStartCommand(intent: Intent?,flags: Int,startId: Int): Int {

    settingsRepository = (application.applicationContext as MainApplication).settingsRepository
    
    saveStatetoDataStore(true)

    return START_REDELIVER_INTENT
}

private fun saveStatetoDataStore(state: Boolean): Job {

    return Coroutinescope(dispatchers.IO).launch {
        settingsRepository.saveServiceStatetoDataStore(state)
    }
}

Activity.kt

private fun observeDataFromviewmodel() {
    mainviewmodel.readServiceStateFromrepository.observe(this,{state ->
        Toast.makeText(this,"Service state changed to $state",Toast.LENGTH_SHORT).show()

        // should get the new data when service stores it in onStartCommand but doesn't get it
        // maybe because the service doesn't stores the data for some reason I am not aware of.
       
    })
    
}
private fun handleClickListener() {
    btn_start_service.setonClickListener {
            startForegroundService(serviceIntent)
        }
    }

    btn_stop_service.setonClickListener {
        mainviewmodel.saveServiceState(false)
        stopService(serviceIntent)
    }
}

viewmodel.kt

class Mainviewmodel(application: Application) : Androidviewmodel(application) {

   private val settingsRepository = (application.applicationContext as MainApplication).settingsRepository

   val readServiceStateFromrepository = settingsRepository.getServiceStateFromDataStore.asLiveData()


   fun saveServiceState(state: Boolean): Job {
       return viewmodelScope.launch(dispatchers.IO) {
           settingsRepository.saveServiceStatetoDataStore(state)
       }
   }
}

解决方法

使用 Messenger 类与服务器 https://developer.android.com/reference/android/app/Service.html#remote-messenger-service-sample

通信

或者使用 BroadcastReceiver 从另一个进程获取服务状态

class MainActivity : AppCompatActivity() {
    private var receiver: TmpReceiver? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.view_main)
        val intent = Intent(this,TmpService::class.java)
        receiver = TmpReceiver()
        val filter = IntentFilter().apply {
            addAction("SERVICE_START")
            addAction("SERVICE_STOP")
        }
        registerReceiver(receiver,filter)
        startService(intent)
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(receiver)
        receiver = null
    }
}

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

    override fun onCreate() {
        super.onCreate()
        sendBroadcast("SERVICE_START")
    }

    override fun onDestroy() {
        sendBroadcast("SERVICE_STOP")
        super.onDestroy()
    }

    private fun sendBroadcast(action: String) {
        Intent().also { intent ->
            intent.action = action
            sendBroadcast(intent)
        }
    }
}

class TmpReceiver: BroadcastReceiver() {
    override fun onReceive(p0: Context?,p1: Intent?) {
        Log.d("TmpReceiver","action=${p1?.action}")
    }
}

您可以在服务中再注册一个接收器,以便从活动中 ping 它。

关于它仅适用于单个流程应用程序的最接近的答案

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?