Код: Выделить всё
@Singleton
class EditorServiceConnection @Inject constructor(
@ApplicationContext private val context: Context,
@IoDispatcher private val ioScope: CoroutineScope,
) : ServiceConnection {
private val _service = MutableStateFlow(null)
val service get() = _service.asStateFlow().filterNotNull()
private var reconnectJob: Job? = null
private var isBound = false
fun bindService() {
val intent = Intent().apply {
setAction("com.scene.engine.service.action")
setComponent(
ComponentName(
"com.scene.engine",
"com.scene.engine.EngineService"
)
)
}
context.bindService(intent, this, Context.BIND_AUTO_CREATE)
}
fun unbindService() {
context.unbindService(this)
}
override fun onServiceConnected(name: ComponentName?, binder: IBinder?) {
LogUtil.d(TAG, "Service connected.")
val engine = IEngine.Stub.asInterface(binder)
val engineApi = IEditorApi.Stub.asInterface(engine.obtainEditorApi())
engineApi.registerApiStatusCallback(object : IApiStatusCallback.Stub() {
override fun onApiInitialized() {
LogUtil.d(TAG, "onApiInitialized.")
_service.update { engineApi }
}
})
isBound = true
}
override fun onServiceDisconnected(name: ComponentName?) {
LogUtil.e(TAG, "Service disconnected.")
_service.update { null }
isBound = false
startReconnectLoop()
}
private fun startReconnectLoop() {
LogUtil.e(TAG, "Service startReconnectLoop.")
reconnectJob?.cancel()
reconnectJob = ioScope.launch {
while (!isBound) {
delay(2000)
if (!isBound) {
try {
LogUtil.d(TAG, "try bind service.")
bindService()
} catch (e: Exception) {
LogUtil.e(TAG, e.toString())
}
}
}
}
}
companion object {
private const val TAG = "EditorServiceConnection"
}
}
< /code>
Ниже приведен мой метод испытаний. При отладке я обнаружил, что Connection.SetPrivateField («iSbound», True) @OptIn(ExperimentalCoroutinesApi::class)
class EditorServiceConnectionTest {
@MockK
private lateinit var mockContext: Context
@MockK
private lateinit var mockBinder: IBinder
private val testDispatcher = StandardTestDispatcher()
private val testScope = TestScope(testDispatcher)
private lateinit var connection: EditorServiceConnection
@Before
fun setup() {
MockKAnnotations.init(this)
Dispatchers.setMain(testDispatcher)
mockkStatic(XLog::class)
every { XLog.init(any(), any(), any()) } just Runs
every { XLog.tag(any()).d(any()) } just Runs
every { XLog.tag(any()).e(any()) } just Runs
connection = EditorServiceConnection(mockContext, testScope)
}
@After
fun tearDown() {
Dispatchers.resetMain()
unmockkAll()
}
@Test
fun `onServiceDisconnected should invoke startReconnectLoop`() = runTest {
connection.onServiceDisconnected(null)
advanceTimeBy(2000)
verify(exactly = 1) { connection.bindService() }
connection.setPrivateField("isBound", true)
advanceTimeBy(2000)
verify(exactly = 1) { connection.bindService() }
}
}
fun Any.setPrivateField(name: String, value: T) {
val field = this::class.java.getDeclaredField(name)
field.isAccessible = true
field.set(this, value)
}
< /code>
Я не знаю, в чем проблема. Когда я строю объект EditorServiceConnection, я прохожу в TestScope.
Подробнее здесь: https://stackoverflow.com/questions/796 ... -correctly
Мобильная версия