问题
New to kotlin, i tried many examples and tutorials to no avail, My requirement is:
Ui creates a coroutine that initiates a network connection
on press of a button, that coroutine sends a msg like "i need info about foo" (taken from a edittext?) to the connected server.
coroutine should also be listening for incoming messages and pass those messages to ui (or update ui directly)
coroutine should keep connected to the server unless it is told to close the connection.
I feel that i need global scope, dispatcher.io.
All the examples i found do nothing more than printing values and terminating coroutines and doesn't mention how to implement a long running coroutine which can act as a continues background socket connection.
I do understand that listening from a socket in loop can achieve that but what kind of coroutine do i need here and how do i send messages to and from ui?
Update:Code
// Added comments for new devs who love copy-pasting as it is a nice little startup code
// you can add android:screenOrientation="portrait" in manifest if you want to use this code
class MainActivity2 : AppCompatActivity(), CoroutineScope {
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
private lateinit var job: Job // lateinit = will be initialized later
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
job = Job() // initialized
launch(Dispatchers.IO) { //dispatcher defined, otherwise launch{
// activity also extends coroutine scope so it will be launched in that scope
connector()
}
}
override fun onDestroy() {
// to avoid launching multiple coroutines
// on configuration changes and cancelling it on exit
job.cancel()
super.onDestroy()
}
suspend fun connector() = withContext(Dispatchers.IO){ //defined dispatcher twice here
// useless, once is enough, either here or on launch
//if you defined dispatcher on launch, fun should look like
// suspend fun connector(){
while(true){
// talk to a server
// need to update ui?
withContext(Dispatchers.Main){ // back to UI
// you can update/modify ui here
Toast.makeText(this@MainActivity2, "hi there", Toast.LENGTH_LONG).show()
}
}
}
}
New Question: How do i handle configuration changes :(
Answer: I used Fragments with ViewModels and coroutine launched via viewmodelScope, working flawlessly so far.
回答1:
From what I understand you want to create a coroutine that listens for responses over a connection. In that case the only thing that you need make sure is that the coroutine should be cancellable, once activity is closed.
suspend fun connector() = withContext(Dispatchers.IO){
try {
// open the connection here
while(isActive) {
var doing : String = "nothing" // fetched from a network call
withContext(Dispatchers.Main){
Toast.makeText(this@MainActivity2, doing, Toast.LENGTH_LONG).show()
}
}
} finally {
withContext(NonCancellable) {
//close the connection here
}
}
isActive
is an extension property available inside the coroutine via the CoroutineScope
object.
When the screen is rotated, the connection is closed and a new one is being opened once the coroutine is called again in onCreate
.
来源:https://stackoverflow.com/questions/57717328/kotlin-coroutines-continues-updates