Máy ảnh Android android.hardware.Camera không được dùng nữa


97

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



1
Tôi đã gặp sự cố 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 giải pháp thay thế: developer.android.com/guide/topics/media/…
Ronaldo Bahia

Câu trả lời:


102

Tài liệu API

Theo hướng dẫn dành cho nhà phát triển Androidandroid.hardware.Camera , họ nêu rõ:

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

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

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 không dùng nữa.

Vấn đề

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

Ví dụ: bật hướng camera 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 gây khó khăn cho việc chuyển đổi từ mã này sang mã khác và viết mã có thể xử lý cả hai cách 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ế là API máy ảnh cũ hoạt động với intcác ID máy ảnh ban đầu trong khi API mới hoạt động với Stringcá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 trả về không phải lúc nào cũng theo thứ tự, điều này sẽ 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 Chuỗi và biểu diễn chuỗi của các cameraID int cũ có lẽ an toàn hơn.

Một đi xung quanh

Bây giờ để khắc phục sự khác biệt lớn này, trước tiên bạn có thể triển khai một giao diệ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 cách 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 của API camera để 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, để hạn chế ví dụ này tôi chỉ có 2 phương pháp ở đâ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 cái 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 lớp của bạn CameraOldhoặc của bạn , CameraNewbạn sẽ phải kiểm tra cấp API vì CameraNewchỉ có sẵn từ api cấp 21.

Nếu bạn đã thiết lập tính năng tiêm phụ thuộc, bạn có thể làm như vậy trong mô-đun của mình khi cung cấp CameraSupporttriển khai. 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 Factory pattern để tạo một kiểu phù hợp. Phần quan trọng là cấp API được kiểm tra.


25
Điều gì xảy ra nếu tôi cần hỗ trợ cấp API android nhỏ hơn 21?
niveuseverto

1
@Angelius có lẽ tài liệu này sẽ hữu ích cho 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 dùng nữa.

@Angelius đây là một số thông tin về @SuppressWarningstrong QA stackoverflow.com/questions/7397996/…

5
Tôi đang nghĩ đến việc không chỉ sử dụng các lớp @deprecated mà còn làm thế nào để tạo ứng dụng có khả năng tương thích ngược? bất kỳ trợ giúp chính thức về điều này? Tôi có ý tưởng về vấn đề này: Giao diện ICamera, mà hậu thuẫn với đối tượng máy ảnh 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 thẳng về phía trước và khó có thể duy trì ...
niveuseverto

@Angelius những gì bạn đang mô tả có thể là một câu hỏi riêng (hãy kiểm tra xem nó đã được hỏi trước chưa).

5

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

2 API có sự khác biệt rõ rệt khiến việc hoán đổi chúng trở nên khó khă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 một kiến ​​trúc khác. Có tình yêu với Google, nhưng ragnabbit! thật là bực bội.

Vì vậy, tôi đã tạo một giao diện chỉ tập trung vào 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 camera của tôi không phải quan tâm đến việc nó đang chạy trên nền tảng nào ...

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

Cả hai lớp trình bao bọc đều sử dụng cùng một giao diện , vì vậy không có vấn đề gì nếu Ứng dụng chạy trên Jellybean hay Marshmallow - miễn là giao diện cung cấp cho ứng dụng của tôi những gì nó cần từ API Camera, sử dụng cùng một 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 mới hơn và cũ hơn.

Singleton cũng có thể thực hiện một số việc liên quan không liên quan đến các API - như phát hiện rằng thực sự có 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 sẽ giúp bạn ra ngoài.


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

rõ ràng là không được phép ngắt dòng trong các bình luận ;-) nhưng nó thực sự hoạt động.
Robert Sherman

4
tại sao không nối các mã trong phần bình luận trực tiếp vào Câu trả lời?
Angel Koh

@RobertSherman Xin chào Robert, Bạn có thể vui lòng giúp tôi viết lại đoạn trích nhỏ nhỏ này cho mới được camera2không? Tôi thực sự bối rối ... Tôi chỉ cần các enableAutofocusphương pháp để mở camera và thiết lập tập trung: stackoverflow.com/questions/19076316/...

0

Bây giờ chúng ta phải sử dụng android.hardware.camera2 làm 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

Các câu trả lời được cung cấp ở đây vì api máy ảnh nào được sử dụng là sai. Hoặc tốt hơn để nói rằng chúng không đủ.

Một số điện thoại (ví dụ như Samsung Galaxy S6) có thể trên api cấp 21 nhưng vẫn có thể không hỗ trợ api Camera2.

CameraCharacteristics mCameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId);
Integer level = mCameraCharacteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
if (level == null || level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
    return false;
}

Lớp CameraManager trong Camera2Api có một phương thức để đọc các đặc điểm của camera. Bạn nên kiểm tra xem thiết bị thông minh phần cứng có hỗ trợ Camera2 Api hay không.

Nhưng có nhiều vấn đề hơn cần xử lý nếu bạn thực sự muốn làm cho nó hoạt động cho một ứng dụng nghiêm trọng: Như, tùy chọn đèn flash tự động có thể không hoạt động đối với một số thiết bị hoặc mức pin của điện thoại có thể tạo ra RuntimeException trên Máy ảnh hoặc điện thoại có thể trả về lỗi không hợp lệ id máy ảnh và v.v.

Vì vậy, cách tốt nhất là có một cơ chế dự phòng vì vì lý do nào đó Camera2 không khởi động được, bạn có thể thử Camera1 và nếu điều này cũng không thành công, bạn có thể gọi Android để mở Camera mặc định cho bạn.


0
 if ( getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)) {

          CameraManager cameraManager=(CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE);


           try {
               String cameraId = cameraManager.getCameraIdList()[0];
               cameraManager.setTorchMode(cameraId,true);
           } catch (CameraAccessException e) {
               e.printStackTrace();
           }


 }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.