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
相关产品推荐
相关产品推荐

