【问题标题】:Fetching a URL in Android Kotlin asynchronously在 Android Kotlin 中异步获取 URL
【发布时间】:2017-06-02 00:03:28
【问题描述】:

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

【问题讨论】:

  • 似乎我使用的 kotlin.io kotlin-stdlib 库版本不适用于 android-extensions 或类似的东西。它现在又开始工作了。
  • 这里是 build.gradle 文件,供参考:paste.ee/p/zJtZO
  • 您将阻塞函数命名为异步?
  • runBlocking 更改为launch(UI) 是否有效?为此,您需要 this 库。
  • ViewModel 中做网络逻辑比在Activity 中更好

标签: android kotlin kotlin-android-extensions


【解决方案1】:

我知道你的情况,是因为你在使用runBlocking,虽然await没有阻塞线程,但是它会暂停协程,并且由于当前协程还没有完成,@987654323 @线程将被阻塞等待。

所以只使用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】:

    这是一个可与 kotlin 一起使用的异步示例,非常适合我

    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);
                }
            }
        }
    

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        task = new AsyncTask<Void, Void, String>() {
            @Override protected String doInBackground(Void... params) {
                return requestFromServer("<api call>");
            }
    
            @Override protected void onPostExecute(String s) {
                if (!isFinishing() && !isCancelled()) {
                    Log.d("Request", s);
                    Toast.makeText(ExampleActivity.this, "Request performed", Toast.LENGTH_LONG).show();
                }
            }
        };
    }
    
    @Override protected void onDestroy() {
        super.onDestroy();
    
        if (task != null) {
            task.cancel(true);
            task = null;
        }
    }
    

    引用自 - antonioleiva

    【讨论】:

      【解决方案3】:

      您必须切换到主线程才能从挂起功能更新 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/")
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-01-25
        • 2018-03-19
        • 2022-01-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多