Câu hỏi Máy ảnh Android android.hardware.Camera không được dùng nữa


nếu android.hardware.Camera không được dùng nữa và bạn không thể sử dụng biến Camerathì điều gì sẽ là sự thay thế cho điều này?


76
2018-01-21 11:18


gốc


android.hardware.camera2 - ozbek
Tôi đã gặp vấn đề này với một ứng dụng và thấy điều này rất hữu ích. Nếu bạn sử dụng ý định, bạn bị giới hạn. Vì vậy, hướng dẫn này giải thích một sự thay thế: developer.android.com/guide/topics/media/… - Ronaldo Bahia


Các câu trả lời:


Tài liệu API

Theo Hướng dẫn dành cho nhà phát triển Android cho android.hardware.Camera, họ nói:

Chúng tôi khuyên bạn nên sử dụng android.hardware.camera2 API cho các ứng dụng mới.

Trên trang thông tin về android.hardware.camera2, (liên kết ở trên), nó được nêu:

Gói android.hardware.camera2 cung cấp giao diện cho các thiết bị máy ảnh riêng lẻ được kết nối với thiết bị Android. Nó thay thế lớp Camera bị phản đối.

Vấn đề

Khi bạn kiểm tra tài liệu đó, bạn sẽ thấy rằng việc triển khai 2 API máy ảnh này rất khác nhau.

Ví dụ: định hướng máy ảnh trên android.hardware.camera

@Override
public int getOrientation(final int cameraId) {
    Camera.CameraInfo info = new Camera.CameraInfo();
    Camera.getCameraInfo(cameraId, info);
    return info.orientation;
}

Đấu với android.hardware.camera2 

@Override
public int getOrientation(final int cameraId) {
    try {
        CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
        String[] cameraIds = manager.getCameraIdList();
        CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraIds[cameraId]);
        return characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
    } catch (CameraAccessException e) {
        // TODO handle error properly or pass it on
        return 0;
    }
}

Điều này làm cho nó khó chuyển đổi từ cái này sang cái khác và viết mã có thể xử lý cả hai việc triển khai.

Lưu ý rằng trong ví dụ mã đơn này, tôi đã phải làm việc xung quanh thực tế rằng API camera cũ sẽ hoạt động với int nguyên thủy cho ID máy ảnh trong khi ID mới hoạt động với String các đối tượng. Đối với ví dụ này, tôi đã nhanh chóng khắc phục điều đó bằng cách sử dụng int làm chỉ mục trong API mới. Nếu máy ảnh được trả về không phải lúc nào cũng theo thứ tự như vậy, điều này đã gây ra sự cố. Cách tiếp cận thay thế là làm việc với các đối tượng String và biểu diễn chuỗi của các máy ảnh int cũ có thể an toàn hơn.

Một xung quanh

Bây giờ để làm việc xung quanh sự khác biệt lớn này, bạn có thể thực hiện một giao diện đầu tiên và tham chiếu giao diện đó trong mã của bạn.

Ở đây tôi sẽ liệt kê một số mã cho giao diện đó và 2 triển khai. Bạn có thể giới hạn việc triển khai đối với những gì bạn thực sự sử dụng API máy ảnh để hạn chế số lượng công việc.

Trong phần tiếp theo, tôi sẽ giải thích nhanh cách tải cái này hay cái khác.

Giao diện gói tất cả những gì bạn cần, để giới hạn ví dụ này, tôi chỉ có 2 phương thức ở đây.

public interface CameraSupport {
    CameraSupport open(int cameraId);
    int getOrientation(int cameraId);
}

Bây giờ có một lớp cho api phần cứng máy ảnh cũ:

@SuppressWarnings("deprecation")
public class CameraOld implements CameraSupport {

    private Camera camera;

    @Override
    public CameraSupport open(final int cameraId) {
        this.camera = Camera.open(cameraId);
        return this;
    }

    @Override
    public int getOrientation(final int cameraId) {
       Camera.CameraInfo info = new Camera.CameraInfo();
       Camera.getCameraInfo(cameraId, info);
       return info.orientation;
    }
}

Và một số khác cho api phần cứng mới:

public class CameraNew implements CameraSupport {

    private CameraDevice camera;
    private CameraManager manager;

    public CameraNew(final Context context) {
        this.manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
    }

    @Override
    public CameraSupport open(final int cameraId) {
        try {
            String[] cameraIds = manager.getCameraIdList();
            manager.openCamera(cameraIds[cameraId], new CameraDevice.StateCallback() {
                @Override
                public void onOpened(CameraDevice camera) {
                    CameraNew.this.camera = camera;
                }

                @Override
                public void onDisconnected(CameraDevice camera) {
                    CameraNew.this.camera = camera;
                    // TODO handle
                }

                @Override
                public void onError(CameraDevice camera, int error) {
                    CameraNew.this.camera = camera;
                    // TODO handle
                }
            }, null);
        } catch (Exception e) {
            // TODO handle
        }
        return this;
    }

    @Override
    public int getOrientation(final int cameraId) {
        try {
            String[] cameraIds = manager.getCameraIdList();
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraIds[cameraId]);
            return characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
        } catch (CameraAccessException e) {
            // TODO handle
            return 0;
        }
    }
}

Đang tải API thích hợp

Bây giờ để tải một trong hai của bạn CameraOld hoặc là CameraNew bạn sẽ phải kiểm tra cấp API từ CameraNew chỉ có ở cấp api 21.

Nếu bạn đã thiết lập tiêm phụ thuộc thì bạn có thể làm như vậy trong mô-đun của mình khi cung cấp CameraSupport thực hiện. Thí dụ:

@Module public class CameraModule {

    @Provides
    CameraSupport provideCameraSupport(){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            return new CameraNew(context);
        } else {
            return new CameraOld();
        }
    } 
}

Nếu bạn không sử dụng DI, bạn chỉ có thể tạo một tiện ích hoặc sử dụng mẫu Nhà máy để tạo mẫu phù hợp. Phần quan trọng là mức API được chọn.


78
2018-01-21 11:26



Điều gì sẽ xảy ra nếu tôi cần hỗ trợ cấp API Android dưới 21? - niveuseverto
@Angelius có lẽ tài liệu này sẽ trợ giúp developer.android.com/guide/topics/media/camera.html  - nhưng đó có thể là một câu hỏi riêng hoặc tìm kiếm các câu hỏi về việc phải sử dụng các biến không được chấp nhận.
@Angelius đây là một số thông tin về @SuppressWarnings trong QA này stackoverflow.com/questions/7397996/…
Tôi đang nghĩ đến việc không chỉ sử dụng các lớp @deprecated, mà còn làm cho ứng dụng có khả năng tương thích ngược? bất kỳ sự trợ giúp chính thức nào về điều này? Tôi có ý tưởng về điều này: giao diện ICamera, được hỗ trợ với đối tượng Camera tương ứng trên phiên bản điện thoại hiện tại, nhưng đây là một chút về phía trước và khó duy trì ... - niveuseverto
Xin lỗi nhưng không. Đã không quản lý để tạo ra một phiên bản thanh lịch ... - niveuseverto


Đối mặt với cùng một vấn đề, hỗ trợ các thiết bị cũ hơn thông qua API máy ảnh không dùng nữa và cần API Camera2 mới cho cả hai thiết bị hiện tại và di chuyển trong tương lai; Tôi đã gặp phải các vấn đề tương tự - và có không phải đã tìm thấy thư viện của bên thứ ba có 2 API, có thể vì chúng rất khác nhau, Tôi đã chuyển sang hiệu trưởng OOP cơ bản.

2 API là khác nhau rõ rệt làm cho việc trao đổi chúng có vấn đề đối với các đối tượng khách hàng mong đợi các giao diện được trình bày trong API cũ. API mới có các đối tượng khác nhau với các phương thức khác nhau, được xây dựng bằng cách sử dụng một kiến ​​trúc khác. Có tình yêu dành cho Google, nhưng ragnabbit! thật là bực mình.

Vì vậy, tôi đã tạo một giao diện tập trung vào chỉ chức năng máy ảnh mà ứng dụng của tôi cần và tạo một trình bao bọc đơn giản cho cả hai API triển khai giao diện đó. Bằng cách đó hoạt động máy ảnh của tôi không phải quan tâm đến nền tảng nào đang chạy trên ...

Tôi cũng thiết lập Singleton để quản lý (các) API; hỗ trợ trình bao bọc API cũ hơn với giao diện của tôi cho các thiết bị Android OS cũ hơn và lớp trình bao bọc API mới cho các thiết bị mới sử dụng API mới. Singleton có mã điển hình để có được mức API và sau đó thể hiện đối tượng chính xác.

Cùng một giao diện được sử dụng bởi cả hai lớp wrapper, vì vậy nó không quan trọng nếu ứng dụng chạy trên Jellybean hoặc Marshmallow - miễn là giao diện cung cấp ứng dụng của tôi với ứng dụng cần thiết từ API Camera, sử dụng cùng chữ ký phương thức; máy ảnh chạy trong ứng dụng theo cùng một cách cho cả phiên bản Android cũ hơn và mới hơn.

Singleton cũng có thể thực hiện một số thứ liên quan không liên quan đến các API - như phát hiện ra rằng thực sự có một camera trên thiết bị và lưu vào thư viện phương tiện.

Tôi hy vọng ý tưởng này sẽ giúp bạn.


5
2018-06-16 18:25



Ví dụ: public interface AllCameraInterface { void open(); boolean setDirection(); Bitmap preview(); Bitmap takePhoto(); void close(); } - Robert Sherman
ví dụ: public interface AllCameraInterface { void open(); Bitmap takePhoto(); void close(); etc... }  public class NCamera implements AllCameraInterface...  public class OCamera implements AllCameraInterface...  public class AllCamera { private static AllCamera ourInstance = new AllCamera(); public static AllCamera getInstance() {...} private AllCameraInterface camera; private AllCamera() { if (android.os.Build.VERSION.SDK_INT <= 20) { camera = new OCamera(); } else { camera = new NCamera(); } } Sau đó, một phương pháp để trả lại ... - Robert Sherman
dường như không có ngắt dòng cho phép trong bình luận ;-) nhưng nó thực sự hoạt động. - Robert Sherman
tại sao không thêm mã trong các nhận xét trực tiếp vào Câu trả lời? - Angel Koh
@ Robert Rossman Hi Robert, Bạn có thể vui lòng giúp tôi viết lại đoạn trích nhỏ bé này cho camera2? Tôi thực sự bối rối ... Tôi chỉ cần enableAutofocus phương pháp để mở máy ảnh và đặt trọng tâm của nó: stackoverflow.com/questions/19076316/… - Joshua


Bây giờ chúng ta phải sử dụng android.hardware.camera2 như android.hardware.Camera không được dùng nữa sẽ chỉ hoạt động trên API> 23 FlashLight

   public class MainActivity extends AppCompatActivity {

     Button button;

     Boolean light=true;

     CameraDevice cameraDevice;

     private CameraManager cameraManager;

     private CameraCharacteristics cameraCharacteristics;

     String cameraId;

     @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button=(Button)findViewById(R.id.button);
        cameraManager = (CameraManager) 
        getSystemService(Context.CAMERA_SERVICE);
        try {
          cameraId = cameraManager.getCameraIdList()[0];
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(light){
                    try {

                        cameraManager.setTorchMode(cameraId,true);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }

                    light=false;}
                    else {

                    try {

                      cameraManager.setTorchMode(cameraId,false);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }


                    light=true;
                    }


            }
        });
    }
}

0
2018-06-20 13:47