异步获取Android Kotlin中的URL

时间:2017-06-02 00:03:28

标签: android kotlin kotlin-android-extensions

所以我试图编写一个非常简单的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()调用。我在这里做错了什么蠢事?

4 个答案:

答案 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/")
}