Android Studio开发App获取本地服务器数据时偶发崩溃求助
问题:Android App访问本地服务器崩溃,偶尔正常的原因及解决办法
我正在使用Android Studio开发我的第一款App,尝试从本地Web服务器获取数据。代码如下:
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContentView(R.layout.activity_main) ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) insets } val textView = findViewById<TextView>(R.id.xml_text_view) val client = OkHttpClient() val url = "http://192.168.43.41" val request = Request.Builder().url(url).build() client.newCall(request).enqueue(object : Callback { override fun onFailure(call: Call, e: IOException) { textView.text = e.toString() e.printStackTrace() } override fun onResponse(call: Call, response: Response) { if (response.isSuccessful) { runOnUiThread { textView.text = response.body!!.string() } } } }) } }
现象:
- 打开App时会崩溃,尝试3-4次后又能正常显示数据;
- 将URL更换为公网地址(如https://reqres.in/api/users?page=2)时可正常运行;
- 当ESP8266服务器离线时,App也能正常打开。
崩溃日志:
AndroidRuntime com.example.test1 E FATAL EXCEPTION: main Process: com.example.test1, PID: 8062 android.os.NetworkOnMainThreadException at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1565) at java.net.SocketInputStream.read(SocketInputStream.java:175) at java.net.SocketInputStream.read(SocketInputStream.java:144) at okio.InputStreamSource.read(JvmOkio.kt:93) at okio.AsyncTimeout$source$1.read(AsyncTimeout.kt:128) at okio.RealBufferedSource.read(RealBufferedSource.kt:192) at okhttp3.internal.http1.Http1ExchangeCodec$AbstractSource.read(Http1ExchangeCodec.kt:339) at okhttp3.internal.http1.Http1ExchangeCodec$UnknownLengthSource.read(Http1ExchangeCodec.kt:475) at okhttp3.internal.connection.Exchange$ResponseBodySource.read(Exchange.kt:281) at okio.Buffer.writeAll(Buffer.kt:1303) at okio.RealBufferedSource.readString(RealBufferedSource.kt:96) at okhttp3.ResponseBody.string(ResponseBody.kt:187) at com.example.test1.MainActivity$onCreate$2.onResponse$lambda$0(MainActivity.kt:42) at com.example.test1.MainActivity$onCreate$2.$r8$lambda$wwUQooT56XlASn_Q0N96Hr51lHo(Unknown Source:0) at com.example.test1.MainActivity$onCreate$2$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0) at android.os.Handler.handleCallback(Handler.java:900) at android.os.Handler.dispatchMessage(Handler.java:103) at android.os.Looper.loop(Looper.java:219) at android.app.ActivityThread.main(ActivityThread.java:8668) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1109)
原因分析
崩溃根本原因
日志中的NetworkOnMainThreadException明确指出问题:你在主线程中执行了网络IO操作。具体是在runOnUiThread代码块里调用了response.body!!.string()——这个方法并非单纯读取内存数据,当响应流未完全加载到本地时,它会触发实际的网络读取操作,而Android的StrictMode机制会禁止主线程做这类耗时网络操作,直接抛出异常。
特殊现象解释
- 偶尔正常:当本地服务器响应速度极快,响应流已经完全加载到OkHttp的缓存内存中,此时
string()只是读取内存数据,不会触发网络IO,因此不会触发异常。 - 公网地址正常:公网服务器的响应通常经过CDN优化或OkHttp内部缓存处理,响应流提前完成加载,主线程调用
string()时无实际网络操作。 - 服务器离线正常:此时请求直接走到
onFailure回调,仅在主线程更新文本,未涉及ResponseBody的读取操作,因此无异常。
解决方案
核心修复:子线程读取响应体,主线程更新UI
将response.body?.string()的调用移到Callback的子线程中完成,再把读取到的结果传到主线程更新UI,避免主线程处理网络IO:
client.newCall(request).enqueue(object : Callback { override fun onFailure(call: Call, e: IOException) { // 更新UI必须在主线程 runOnUiThread { textView.text = e.toString() } e.printStackTrace() } override fun onResponse(call: Call, response: Response) { if (response.isSuccessful) { // 在子线程读取响应内容,避免主线程网络操作 val responseContent = response.body?.string() ?: "Empty response" // 切换到主线程更新UI runOnUiThread { textView.text = responseContent } } else { runOnUiThread { textView.text = "Request failed: ${response.code}" } } } })
额外注意事项
- 永远不要在主线程执行任何网络相关的IO操作(包括读取响应体、发起同步请求等)。
- 避免使用
!!强制非空,改用?:处理空值,防止空指针异常。 - 确认
AndroidManifest.xml中已添加网络权限:
<uses-permission android:name="android.permission.INTERNET" />
内容的提问来源于stack exchange,提问作者user28783786
相关产品推荐
相关产品推荐

