You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Studio中Kotlin实现从URL读取文本文件(API30+)

解决Android API30+下Kotlin读取URL文本内容的问题

原代码的核心问题

你提供的Java代码无法运行的原因有几点:

  • 直接在主线程执行网络请求,API30+会抛出android.os.NetworkOnMainThreadException
  • 缺少URL协议头(http://或https://),会触发MalformedURLException
  • 未处理超时、响应状态码等异常场景,代码健壮性不足
  • 未适配Kotlin的异步编程模型

方案1:Kotlin协程+原生HttpURLConnection(无第三方依赖)

这种方式不需要额外引入库,用Android原生API配合Kotlin协程实现线程切换,避免主线程网络请求。

第一步:添加网络权限

在AndroidManifest.xml中声明网络权限:

<uses-permission android:name="android.permission.INTERNET" />

第二步:实现读取逻辑

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.BufferedReader
import java.io.InputStreamReader
import java.net.HttpURLConnection
import java.net.URL

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 发起请求,建议用viewModelScope/LifecycleScope替代GlobalScope避免内存泄漏
        GlobalScope.launch(Dispatchers.Main) {
            val textContent = fetchTextFromUrl("https://mysite.com/thefile.txt")
            // 在这里更新UI,比如显示到TextView
            textContent?.let {
                // tv_content.text = it
            }
        }
    }

    // 挂起函数,在IO线程执行网络操作
    private suspend fun fetchTextFromUrl(urlString: String): String? {
        return withContext(Dispatchers.IO) {
            var connection: HttpURLConnection? = null
            var reader: BufferedReader? = null
            try {
                val url = URL(urlString)
                connection = url.openConnection() as HttpURLConnection
                connection.apply {
                    requestMethod = "GET"
                    connectTimeout = 5000 // 5秒连接超时
                    readTimeout = 5000    // 5秒读取超时
                }

                // 检查响应状态码
                if (connection.responseCode == HttpURLConnection.HTTP_OK) {
                    reader = BufferedReader(InputStreamReader(connection.inputStream))
                    val contentBuilder = StringBuilder()
                    var line: String?
                    while (reader.readLine().also { line = it } != null) {
                        contentBuilder.append(line).append("\n")
                    }
                    return@withContext contentBuilder.toString().trim()
                } else {
                    return@withContext null
                }
            } catch (e: Exception) {
                e.printStackTrace()
                return@withContext null
            } finally {
                // 关闭资源
                connection?.disconnect()
                reader?.close()
            }
        }
    }
}

方案2:Kotlin协程+OkHttp(简洁高效)

如果项目中已经使用OkHttp,或者希望更简洁的代码,可以用这种方式。

第一步:添加OkHttp依赖

在Module级别的build.gradle(或build.gradle.kts)中添加依赖:

implementation("com.squareup.okhttp3:okhttp:4.12.0")

第二步:实现读取逻辑

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import okhttp3.Request

class MainActivity : AppCompatActivity() {
    private val okHttpClient = OkHttpClient()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        GlobalScope.launch(Dispatchers.Main) {
            val textContent = fetchTextWithOkHttp("https://mysite.com/thefile.txt")
            // 更新UI逻辑
        }
    }

    private suspend fun fetchTextWithOkHttp(urlString: String): String? {
        return withContext(Dispatchers.IO) {
            val request = Request.Builder()
                .url(urlString)
                .build()
            try {
                // use函数自动关闭response资源
                okHttpClient.newCall(request).execute().use { response ->
                    if (response.isSuccessful) {
                        return@withContext response.body?.string()
                    } else {
                        return@withContext null
                    }
                }
            } catch (e: Exception) {
                e.printStackTrace()
                return@withContext null
            }
        }
    }
}

关键注意事项

  • 线程切换:必须将网络请求放在Dispatchers.IO调度器执行,更新UI时切回Dispatchers.Main
  • 避免内存泄漏:实际项目中推荐使用viewModelScope(ViewModel中)或lifecycleScope(Activity/Fragment中)替代GlobalScope
  • URL格式:必须包含http://或https://协议头,否则会抛出URL格式异常

内容的提问来源于stack exchange,提问作者GraduatedImposterSynd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 14:30:58