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

Android 相機拍照 Fail to connect to camera service 解決方案

     編輯:程式設計綜合問答

問題現象

啟動相機拍照時拋出 Fail to connect to camera service、cannot connect to camera,相機資源被佔用或釋放不當。

常見原因

原因說明
相機未正確釋放前次使用未呼叫 release(),或在 onPause/onStop 未釋放
多處同時存取多個 Activity/Service 同時開啟相機
權限缺失Manifest 缺 CAMERA 權限或 uses-feature
硬體不支援模擬器無相機、裝置相機故障

正確相機使用模板 (Camera API 1 - 舊版但仍通用)


public class CameraActivity extends AppCompatActivity {
    private Camera camera;
    private CameraPreview preview;
    private static final int CAMERA_REQUEST = 1888;
    
    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera);
        
        // 檢查相機硬體
        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
            Toast.makeText(this, "裝置無相機", Toast.LENGTH_LONG).show();
            finish();
            return;
        }
        
        // 方式一:使用系統相機 Intent (推薦,簡單、生命週期由系統管理)
        dispatchTakePictureIntent();
    }
    
    // 系統相機 Intent (最穩健)
    private void dispatchTakePictureIntent() {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
            // 可選:指定輸出檔案路徑
            File photoFile = createImageFile();
            if (photoFile != null) {
                Uri photoUri = FileProvider.getUriForFile(this, 
                    "com.example.fileprovider", photoFile);
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
                takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            }
            startActivityForResult(takePictureIntent, CAMERA_REQUEST);
        }
    }
    
    @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == CAMERA_REQUEST && resultCode == RESULT_OK) {
            // 處理拍照結果 (若指定 EXTRA_OUTPUT,data 可能為 null)
            Bitmap bitmap = BitmapFactory.decodeFile(currentPhotoPath);
            imageView.setImageBitmap(bitmap);
        }
    }
    
    // 建立圖片檔案
    private File createImageFile() throws IOException {
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String imageFileName = "JPEG_" + timeStamp + "_";
        File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        File image = File.createTempFile(imageFileName, ".jpg", storageDir);
        currentPhotoPath = image.getAbsolutePath();
        return image;
    }
    
    // 方式二:直接用 Camera API (需自行管理生命週期)
    @Override protected void onResume() {
        super.onResume();
        if (camera == null) {
            camera = Camera.open(); // 可能拋出 RuntimeException
            preview = new CameraPreview(this, camera);
            previewContainer.addView(preview);
        }
    }
    
    @Override protected void onPause() {
        super.onPause();
        releaseCamera(); // 關鍵:釋放相機資源
    }
    
    private void releaseCamera() {
        if (camera != null) {
            camera.release();
            camera = null;
        }
    }
}

Manifest 必要設定








    
        
    

res/xml/file_paths.xml



    

現代替代:CameraX (Jetpack 推薦)


// build.gradle
implementation "androidx.camera:camera-core:1.3.0"
implementation "androidx.camera:camera-camera2:1.3.0"
implementation "androidx.camera:camera-view:1.3.0"

// 使用
ProcessCameraProvider provider = ProcessCameraProvider.getInstance(this).get();
Preview preview = new Preview.Builder().build();
preview.setSurfaceProvider(viewFinder.getSurfaceProvider());

ImageCapture imageCapture = new ImageCapture.Builder()
    .setTargetRotation(viewFinder.getDisplay().getRotation())
    .build();

CameraSelector selector = CameraSelector.DEFAULT_BACK_CAMERA;
provider.bindToLifecycle(this, selector, preview, imageCapture);

// 拍照
File photoFile = createImageFile();
OutputFileOptions options = new OutputFileOptions.Builder(photoFile).build();
imageCapture.takePicture(options, ContextCompat.getMainExecutor(this), 
    new ImageCapture.OnImageSavedCallback() {
        @Override public void onImageSaved(@NonNull ImageCapture.OutputFileResults results) {
            // 成功
        }
        @Override public void onError(@NonNull ImageCaptureException exception) {
            // 失敗
        }
    });

核心原則

  1. 優先用系統 Intent:避免相機資源管理、權限、生命週期問題
  2. 自行管理 Camera 必須在 onPause/release:camera.release() 且設為 null
  3. FileProvider 處理檔案共享:Android 7.0+ 必須用 content:// URI
  4. 新專案用 CameraX:生命週期感知、統一 API、支援擴展功能
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved