在主執行緒中直接執行 HttpDelete 網路請求,導致 NetworkOnMainThreadException 崩潰,且異常處理不當造成後續空指標。
public void onCreate(Bundle savedInstanceState) {
// ...
txt.setText(getInputStreamFromUrl("https://192.168.37.241:8080/kyaw/k")); // 主執行緒網路請求
}
public static String getInputStreamFromUrl(String url) {
// ...
try {
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpDelete delete = new HttpDelete(url);
// 錯誤:put 未定義,應為 delete
put.setHeader("Content-Type","application/vnd.org.snia.cdmi.container");
response = httpclient.execute(delete); // 主執行緒阻塞
// ...
} catch (Exception e) {
Log.e("[DELETE REQUEST]", "Network exception");
}
// 崩潰點:若 catch 區塊執行,response 為 null
String result = response.getStatusLine().toString() + "\n" + response.getHeaders(url);
return result;
}
put.setHeader 應為 delete.setHeadercatch 區塊未返回值,導致後續使用 response 為 null 拋出 NPEDefaultHttpClient 在 Android 6.0+ 已移除private class DeleteTask extends AsyncTask {
@Override
protected String doInBackground(String... urls) {
String url = urls[0];
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpDelete delete = new HttpDelete(url);
delete.setHeader("Content-Type", "application/vnd.org.snia.cdmi.container");
try (CloseableHttpResponse response = httpClient.execute(delete)) {
int statusCode = response.getStatusLine().getStatusCode();
String responseBody = EntityUtils.toString(response.getEntity());
return "Status: " + statusCode + "\nBody: " + responseBody;
}
} catch (IOException e) {
Log.e("DELETE REQUEST", "Network error", e);
return "Error: " + e.getMessage();
}
}
@Override
protected void onPostExecute(String result) {
txt.setText(result);
}
}
// 呼叫方式
new DeleteTask().execute("https://192.168.37.241:8080/kyaw/k");
添加依賴:implementation "com.squareup.okhttp3:okhttp:4.12.0"
private void performDeleteRequest(String url) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(url)
.delete()
.addHeader("Content-Type", "application/vnd.org.snia.cdmi.container")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
runOnUiThread(() -> txt.setText("Error: " + e.getMessage()));
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
String result = "Status: " + response.code() + "\nBody: " + response.body().string();
runOnUiThread(() -> txt.setText(result));
}
});
}
private class DeleteTask extends AsyncTask {
@Override
protected String doInBackground(String... urls) {
HttpURLConnection conn = null;
try {
URL url = new URL(urls[0]);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("DELETE");
conn.setRequestProperty("Content-Type", "application/vnd.org.snia.cdmi.container");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
int responseCode = conn.getResponseCode();
BufferedReader reader = new BufferedReader(
new InputStreamReader(responseCode < 400 ? conn.getInputStream() : conn.getErrorStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) sb.append(line);
return "Status: " + responseCode + "\n" + sb.toString();
} catch (Exception e) {
return "Error: " + e.getMessage();
} finally {
if (conn != null) conn.disconnect();
}
}
@Override
protected void onPostExecute(String result) {
txt.setText(result);
}
}
| 問題 | 修正 |
|---|---|
| 主執行緒網路請求 | 移至背景執行緒 |
| put/delete 變數錯誤 | 統一使用 delete 物件 |
| catch 區塊無返回 | 確保所有路徑有返回值 |
| DefaultHttpClient 過時 | 改用 OkHttp 或 HttpURLConnection |
| 資源未關閉 | 使用 try-with-resources 或 finally 關閉 |
Android 網路請求必須在背景執行緒執行,且應棄用 DefaultHttpClient 改用現代網路庫。正確的異常處理與資源管理能避免崩潰與記憶體洩漏。