如何从ktor的路由API调用中获得另一个活动(registerForActivity)的结果(例如。( /POST)在非活动类中运行?
背景:对于一个安卓应用程序,我在一个非活动类HttpServer.kt中运行ktor服务器引擎'netty‘。我需要调用另一个应用程序的活动,从with in ktor的路由‘POST处理程序,所以我传递'appCompatActivity’从MainActivity.kt。这样做是因为,我猜想,registerForActivityResult()依赖于UI/生命周期类。
当按照下面的方式运行时会出现问题,因为registerForActivityResult()需要更早地运行(比如onCreate() ?),而且我在这个非活动类中没有这样的类。此外,返回ActivityResult时要运行的回调需要调用ktor ApplicationCall的响应,这也是一个挂起函数。
class HttpServer(
private val applicationContext: AppCompatActivity
) {
private val logger = LoggerFactory.getLogger(HttpServer::class.java.simpleName)
private val server = createServer()
private fun ApplicationCall.startSaleActivityForResult() { // <====== *
val activityLauncherCustom =
applicationContext.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult ->
if (result.resultCode == Activity.RESULT_OK || result.resultCode == Activity.RESULT_CANCELED) {
val transactionResultReturned = result.data
// Handle the returned result properly using transactionResultReturned
GlobalScope.launch {
respond(status = HttpStatusCode.OK, TransactionResponse())
}
}
}
val intent = Intent()
// Ignoring statements to create proper action/data intent
activityLauncherCustom.launch(intent) // <====== *
}
fun start() = server.start()
fun stop() = server.stop(0, 0)
private fun createServer(): NettyApplicationEngine {
return GlobalScope.embeddedServer(Netty) {
install(CallLogging)
install(ContentNegotiation) {
gson {
setPrettyPrinting()
}
}
routing {
route("/") {
post {
call.startSaleActivityForResult() // <====== *
}
}
}
}
}
private fun <TEngine : ApplicationEngine, TConfiguration : ApplicationEngine.Configuration>
CoroutineScope.embeddedServer(
factory: ApplicationEngineFactory<TEngine, TConfiguration>,
module: Application.() -> Unit
): TEngine {
val environment = applicationEngineEnvironment {
this.parentCoroutineContext = coroutineContext + parentCoroutineContext
this.log = logger
this.module(module)
connector {
this.port = 8081
}
}
return embeddedServer(factory, environment)
}
}以上是我尝试过的,但给出了下面的错误。我在这个非活动类上没有onCreate。
java.lang.IllegalStateException:当当前状态恢复时,LifecycleOwner com.youtap.upti.MainActivity@38dcf06正在尝试注册。LifecycleOwners必须在启动前调用寄存器。
任何解决这一问题的建议都将不胜感激。
下面同样是上面的片段,作为屏幕截图,在Android的声明/param类型上显示辅助文本:

我从onCreate()的MainActivity调用这个服务器类:

发布于 2021-10-18 13:55:48
为了解决问题并隐藏复杂性,您可以创建一个中间类,用于启动活动并等待结果的到来:
import kotlinx.coroutines.channels.Channel
class Repository(private val activity: MainActivity) {
private val channel = Channel<Int>(1)
suspend fun get(input: String): Int {
activity.activityLauncher.launch(input)
return channel.receive()
}
suspend fun callback(result: Int) {
channel.send(result)
}
}您可以在MainActivity类中存储对存储库和活动启动程序的引用:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
CoroutineScope(Dispatchers.IO).launch {
HttpServer(this@MainActivity).also { it.start() }
}
}
val activityLauncher = registerForActivityResult(MySecondActivityContract()) { result ->
GlobalScope.launch {
repository.callback(result!!)
}
}
val repository = Repository(this)
}我的第二项活动和合同如下:
class ChildActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_child)
val result = Intent()
result.putExtra("name", 6666)
result.data = Uri.parse("http://mydata")
setResult(Activity.RESULT_OK, result)
finish()
}
}
class MySecondActivityContract : ActivityResultContract<String, Int?>() {
override fun createIntent(context: Context, input: String?): Intent {
return Intent(context, ChildActivity::class.java)
.putExtra("my_input_key", input)
}
override fun parseResult(resultCode: Int, intent: Intent?): Int? = when {
resultCode != Activity.RESULT_OK -> null
else -> intent?.getIntExtra("name", 42)
}
override fun getSynchronousResult(context: Context, input: String?): SynchronousResult<Int?>? {
return if (input.isNullOrEmpty()) SynchronousResult(42) else null
}
}最简单的部分是路由处理程序:
routing {
route("/") {
post {
val result = (applicationContext as MainActivity).repository.get("input")
call.respondText { result.toString() }
}
}
}这个解决方案可以工作,但是只有一个请求是同时处理的,而且它不健壮,因为Activity可能在HTTP或存储库对象之前被销毁。
https://stackoverflow.com/questions/69609046
复制相似问题