Discuz! BBS

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 56|回复: 0

Android 协程,防止android.os.NetworkOnMainThreadException

[复制链接]

313

主题

449

帖子

2824

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2824
发表于 2025-6-25 10:15:55 | 显示全部楼层 |阅读模式
在Android开发中,android.os.NetworkOnMainThreadException异常通常发生在主线程(UI线程)上执行网络操作时。为了避免这个异常,我们应该在后台线程中执行网络请求或其他耗时操作。在Kotlin协程(Coroutine)的帮助下,我们可以轻松地在后台线程中执行这些任务,而不会阻塞主线程,并在任务完成后安全地更新UI。
下面是一个使用Kotlin协程来执行网络请求并避免NetworkOnMainThreadException的示例:
1. 添加依赖
首先,确保你的build.gradle文件中包含了Kotlin协程的依赖:
  1. dependencies {
  2.     implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:x.y.z" // 使用最新版本
  3.     implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:x.y.z" // 通常也会包含核心库
  4.     // 其他依赖...
  5. }
复制代码
2. 创建网络请求函数
创建一个封装了网络请求的函数。这个函数应该使用协程的withContext函数来在IO调度器上执行网络操作。

  1. import kotlinx.coroutines.withContext
  2. import kotlinx.coroutines.Dispatchers
  3. import kotlin.coroutines.CoroutineContext

  4. suspend fun fetchDataFromNetwork(url: String, context: CoroutineContext = Dispatchers.Main): String {
  5.     return withContext(Dispatchers.IO) { // 切换到IO调度器
  6.         // 这里应该是实际的网络请求代码,比如使用OkHttp或Retrofit
  7.         // 但为了简单起见,我们模拟一个网络请求
  8.         delay(2000) // 模拟网络延迟
  9.         "Data from $url" // 假设这是从网络获取的数据
  10.     }
  11. }
复制代码
注意:在实际应用中,你应该使用像Retrofit这样的网络库来处理HTTP请求,而不是使用delay函数。
3. 在ViewModel中使用协程
在你的ViewModel中,使用viewModelScope来启动一个协程,并调用你的网络请求函数。

  1. import androidx.lifecycle.LiveData
  2. import androidx.lifecycle.MutableLiveData
  3. import androidx.lifecycle.ViewModel
  4. import kotlinx.coroutines.launch

  5. class MyViewModel : ViewModel() {
  6.     private val _networkData = MutableLiveData<String?>()
  7.     val networkData: LiveData<String?> get() = _networkData

  8.     fun loadDataFromNetwork(url: String) {
  9.         viewModelScope.launch { // 使用viewModelScope来启动协程
  10.             try {
  11.                 val data = fetchDataFromNetwork(url) // 调用网络请求函数
  12.                 _networkData.value = data // 更新LiveData
  13.             } catch (e: Exception) {
  14.                 // 处理异常,比如显示错误消息
  15.                 _networkData.value = "Error: ${e.message}"
  16.             }
  17.         }
  18.     }
  19. }
复制代码
4. 在Activity或Fragment中观察LiveData
在你的Activity或Fragment中,观察ViewModel中的LiveData,并在数据变化时更新UI。

  1. import androidx.activity.viewModels
  2. import androidx.fragment.app.Fragment
  3. import androidx.lifecycle.Observer
  4. import android.os.Bundle
  5. import android.view.LayoutInflater
  6. import android.view.View
  7. import android.view.ViewGroup
  8. import android.widget.TextView

  9. class MyFragment : Fragment() {
  10.     private val myViewModel: MyViewModel by viewModels()

  11.     override fun onCreateView(
  12.         inflater: LayoutInflater, container: ViewGroup?,
  13.         savedInstanceState: Bundle?
  14.     ): View? {
  15.         val view = inflater.inflate(R.layout.fragment_my, container, false)
  16.         val textView: TextView = view.findViewById(R.id.textViewNetworkData)

  17.         // 观察LiveData
  18.         myViewModel.networkData.observe(viewLifecycleOwner, Observer { newData ->
  19.             textView.text = newData
  20.         })

  21.         // 加载数据
  22.         myViewModel.loadDataFromNetwork("https://example.com/data")

  23.         return view
  24.     }
  25. }
复制代码
在这个例子中,网络请求是在协程的IO调度器上执行的,因此不会阻塞主线程,从而避免了NetworkOnMainThreadException。当数据加载完成时,ViewModel通过LiveData将结果发布给UI层,UI层观察这个LiveData并在数据变化时更新界面。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|DiscuzX

GMT+8, 2025-7-7 14:25 , Processed in 0.012809 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表