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

Android 調用系統相冊點擊圖片閃退問題排查指南

     編輯:程式設計綜合問答

問題現象

Activity 中啟動系統圖片選擇器:

Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, PHOTO_REQUEST_HEADER);

現象:打開相冊、點擊圖片後閃退回原 Activity。初期正常,代碼量增加後出現,懷疑生命周期或內存問題。

核心排查思路

「這個要看代碼或 LOG 來分析,只從描述的現象很難找到原因。原因肯定是代碼的問題。實在找不到,就將代碼一步步重建、或者還原,看看是哪一步出了問題。」

關鍵檢查點清單

1. AndroidManifest.xml 配置

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- Android 10+ 可能需要 -->
<application android:requestLegacyExternalStorage="true" ... >

2. onActivityResult 正確處理結果

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == PHOTO_REQUEST_HEADER && resultCode == RESULT_OK && data != null) {
        Uri selectedImage = data.getData();
        // 關鍵:在單獨線程中處理耗時操作 (獲取路徑、壓縮、上傳等)
        // 不要在主線程做 I/O 或複雜計算!
        new Thread(() -> processImage(selectedImage)).start();
    }
}

3. 生命周期導致的 Activity 重建

  • 啟動相冊後,系統可能因內存不足殺死你的 Activity。
  • 返回時 Activity 重新創建,若 onCreate 中未正確恢復狀態,或 onActivityResult 邏輯有誤,會導致閃退/異常。
  • 解決:在 onSaveInstanceState 保存必要狀態,onCreate / onRestoreInstanceState 恢復。

4. 大圖片導致 OOM (OutOfMemoryError)

相冊返回的圖片可能很大(如 4000×3000),直接 `BitmapFactory.decodeStream` 會爆內存。

private Bitmap decodeSampledBitmap(Uri uri, int reqWidth, int reqHeight) {
    // 1. 先只解碼邊緣獲取尺寸
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
    
    // 2. 計算采樣率
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
    
    // 3. 真正解碼
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
}

5. Uri 處理兼容性 (FileProvider / ContentProvider)

Android 7.0+ (API 24) 禁止 `file://` Uri 跨應用傳遞,必須用 `FileProvider` 生成 `content://` Uri。若你的代碼中有拍照/裁剪/保存臨時文件邏輯,檢查 Uri 生成方式。

6. 查看 Logcat 具體異常堆棧

最直接的方法:連接設備/模擬器,過濾標籤 `Error` 或你的包名,捕獲閃退時的紅色異常信息:

  • `NullPointerException`:`data.getData()` 為空?
  • `SecurityException`:權限缺失或 Uri 暴露?
  • `OutOfMemoryError`:圖片過大?
  • `ActivityNotFoundException`:無應用響應 `ACTION_PICK`?

最小化復現與二分法定位

  1. 新建空項目,只放相冊調用代碼 → 確認基礎流程通。
  2. 逐步遷移原項目代碼(工具類、基類、第三方庫初始化等),每遷移一塊測試一次。
  3. 定位到具體哪個類/方法/初始化導致問題。

現代替代方案:Activity Result API (AndroidX)


// 在 Activity/Fragment 中註冊
private ActivityResultLauncher<Intent> pickImageLauncher = registerForActivityResult(
    new ActivityResultContracts.StartActivityForResult(),
    result -> {
        if (result.getResultCode() == RESULT_OK && result.getData() != null) {
            Uri uri = result.getData().getData();
            // 處理圖片
        }
    }
);

// 啟動
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
pickImageLauncher.launch(intent);

優勢:生命周期感知、類型安全、避免 requestCode 衝突、自動處理 Activity 重建。

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