所以我试图编写一个非常简单的Android应用程序,当按下按钮时,该应用程序从URL获取响应。 kotlin Android扩展已经被广告宣传为Java中必需的样板文件的替代品,所以我试了试。这是我到目前为止所做的:
package com.example.susemihl.myapplication
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.widget.TextView
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.async
import kotlinx.coroutines.experimental.runBlocking
import java.net.URL
suspend fun fetch_url(url: String): String {
return URL(url).readText()
}
fun fetch_async(url: String, view: TextView) = runBlocking {
val result = async(CommonPool) { fetch_url(url) }
view.setText(result.await())
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mainTextView.setText("Hello there.")
mainButton.setOnClickListener {
mainButton.setText("Check again.")
fetch_async("https://random-app.appspot.com/",
mainTextView)
}
}
}
这是间歇性的,但现在完全被打破了。单击按钮没有响应。打印调试向我显示线程被执行,但似乎挂起readText()调用。我在这里做错了什么蠢事?
答案 0 :(得分:0)
我认为你正在寻找类似的东西
async {
val result = URL("url").readText()
uiThread {
mainTextView.setText(result)
}
}
除非我弄错了,否则你的代码看起来像在UI线程上阻塞,而不是等待第一次返回的响应
答案 1 :(得分:0)
我知道你的情况,这是因为你正在使用runBlocking
,虽然await
没有阻止线程,但它会暂停协程,并且因为当前的协程还没有完成,runBlocking
线程将被阻止等待它。
因此,只需使用launc(UI)
代替runBlocking
即可解决此问题:
package com.example.susemihl.myapplication
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.widget.TextView
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.android.UI
import kotlinx.coroutines.experimental.async
import kotlinx.coroutines.experimental.launch
import java.net.URL
fun fetch_url(url: String): String {
return URL(url).readText()
}
fun fetch_async(url: String, view: TextView) = launch(UI) {
val result = async(CommonPool) { fetch_url(url) }
view.text = result.await()
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mainTextView.text = "Hello there."
mainButton.setOnClickListener {
mainButton.text = "Check again."
fetch_async("https://jacksgong.com", mainTextView)
}
}
}
答案 2 :(得分:0)
这是一个可与kotlin一起使用的异步样本,对我来说非常适合
bufferSize
val result = URL("<api call>").readText()
try {
URL url = new URL("<api call>");
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
// Nothing to do.
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
return null;
}
result = buffer.toString();
} catch (IOException e) {
Log.e("Request", "Error ", e);
return null;
} finally{
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e("Request", "Error closing stream", e);
}
}
}
引自 - StreamWriter()
答案 3 :(得分:0)
您必须切换到主线程才能通过暂挂功能更新UI。我将在 ViewModel 中进行联网逻辑,并将结果作为 LiveData 公开给您的 Activity :
class MainViewModel : ViewModel() {
val urlLiveData = MutableLiveData<String>()
fun fetchUrl(url: String): String {
viewModelScope.launch {
// Dispatchers.IO (main-safety block)
withContext(Dispatchers.IO) {
fetchAsync(url)
}
}
}
private suspend fun fetchAsync(url: String) {
urlLiveData.postValue(URL(url).readText())
}
}
class MainActivity : AppCompatActivity() {
private val mainViewModel by viewModels<MainViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mainViewModel.urlLiveData.observe(
viewLifecycleOwner,
Observer { urlText ->
mainTextView.setText(urlText)
}
)
}
mainViewModel.fetchUrl(""https://random-app.appspot.com/")
}