首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android HttpDelete 請求崩潰問題排查與修正

     編輯:程式設計綜合問答

問題現象

在主執行緒中直接執行 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;
}

主要問題

  1. 主執行緒網路請求:Android 3.0+ 嚴禁在 UI 執行緒進行網路操作
  2. 變數名稱錯誤:put.setHeader 應為 delete.setHeader
  3. 異常處理缺陷:catch 區塊未返回值,導致後續使用 response 為 null 拋出 NPE
  4. 使用過時 API:DefaultHttpClient 在 Android 6.0+ 已移除

修正方案一:使用 AsyncTask(舊版專案相容)

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");

修正方案二:使用 OkHttp(現代推薦)

添加依賴: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));
        }
    });
}

修正方案三:使用 HttpURLConnection(無第三方依賴)

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 改用現代網路庫。正確的異常處理與資源管理能避免崩潰與記憶體洩漏。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved