向HTTP提交XML失败:Android NetworkOnMainThreadException问题求助
问题分析与解决方案
首先看你日志里的核心错误:android.os.NetworkOnMainThreadException,这是Android开发里非常常见的问题——你直接在Activity的onCreate方法里调用了postXML(),也就是把网络请求放在了**主线程(UI线程)**里执行。
从Android 3.0(API 11)开始,系统严格禁止在主线程中进行网络操作,因为网络请求是耗时操作,会阻塞UI线程,导致界面卡顿甚至出现ANR(应用无响应)弹窗。
解决步骤:
1. 把网络请求移到子线程执行
你可以用AsyncTask(适合简单场景)或者直接创建新线程处理网络操作。这里给你修改后的实现,用AsyncTask封装更贴合你当前的代码结构:
private class PostXmlTask extends AsyncTask<Void, Void, Boolean> { @Override protected Boolean doInBackground(Void... voids) { HttpURLConnection conn = null; try { URL url = new URL(URLchanges); conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(10000); conn.setConnectTimeout(15000); conn.setRequestMethod("POST"); // 关键:设置请求头,告诉服务器我们发送的是XML格式 conn.setRequestProperty("Content-Type", "application/xml; charset=UTF-8"); conn.setDoInput(true); conn.setDoOutput(true); // 修正XML字符串:Java字符串里不需要转义<和>,直接写正常标签即可 String xmlContent = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<Devices>" + "<Device>" + "<ID>EZR010A49</ID>" + "<DATETIME>2014-01-20T11:40:00</DATETIME>" + "</Device>" + "</Devices>"; OutputStream output = new BufferedOutputStream(conn.getOutputStream()); output.write(xmlContent.getBytes(StandardCharsets.UTF_8)); // 指定编码避免乱码 output.flush(); output.close(); // 检查响应码,确认请求是否真的成功 int responseCode = conn.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { Log.d("posted", "请求成功,响应码:" + responseCode); return true; } else { Log.d("posted", "请求失败,响应码:" + responseCode); return false; } } catch (Exception e) { e.printStackTrace(); Log.d("ERROR", "网络请求出错:" + e.getMessage()); return false; } finally { if (conn != null) { conn.disconnect(); // 确保conn不为null再关闭,避免空指针异常 } } } @Override protected void onPostExecute(Boolean success) { super.onPostExecute(success); // 这里可以更新UI,比如用Toast提示请求结果 if (success) { Toast.makeText(MainActivity.this, "XML发送成功", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(MainActivity.this, "XML发送失败", Toast.LENGTH_SHORT).show(); } } }
然后在onCreate里替换原来的postXML()调用:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); URLchanges = "http://192.168.178.37/data/changes.xml"; URLstats = "http://192.168.178.37/data/static.xml"; // 启动异步任务执行网络请求 new PostXmlTask().execute(); }
2. 补充必要的网络权限
在你的AndroidManifest.xml里必须添加网络权限,否则所有网络请求都会失败:
<uses-permission android:name="android.permission.INTERNET" />
3. 其他细节优化
- 你原来的XML字符串用了
<和>,这是HTML/XML文档里的转义字符,但在Java字符串中直接写<和>就可以,转义后服务器收到的XML会是错误格式,可能导致解析失败。 - 发送数据时指定UTF-8编码,避免出现乱码问题。
- 不要只靠日志判断请求成功,一定要检查服务器返回的响应码,比如
HTTP_OK(200)才代表请求正常完成。
额外建议(针对新版本Android)
如果你的项目基于API 26+,更推荐使用**Coroutines(协程)**处理网络请求,代码更简洁且能避免AsyncTask的潜在内存泄漏问题:
// 在onCreate里调用 lifecycleScope.launch { val success = postXmlCoroutine() Toast.makeText(MainActivity.this, success ? "发送成功" : "发送失败", Toast.LENGTH_SHORT).show(); } // 协程版网络请求方法 private suspend fun postXmlCoroutine(): Boolean { return withContext(Dispatchers.IO) { // 这里写和AsyncTask中doInBackground一致的网络请求逻辑即可 // ... } }
内容的提问来源于stack exchange,提问作者user9216568
相关产品推荐
相关产品推荐

