nếu android.hardware.Camera
khô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?
nếu android.hardware.Camera
khô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?
Câu trả lời:
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.
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 int
các ID máy ảnh ban đầu trong khi API 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 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.
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;
}
}
}
Bây giờ để tải lớp của bạn CameraOld
hoặc của bạn , CameraNew
bạn sẽ phải kiểm tra cấp API vì CameraNew
chỉ 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 CameraSupport
triể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.
@SuppressWarnings
trong QA stackoverflow.com/questions/7397996/…
Đố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.
public interface AllCameraInterface { void open(); boolean setDirection(); Bitmap preview(); Bitmap takePhoto(); void close(); }
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 ...
camera2
không? Tôi thực sự bối rối ... Tôi chỉ cần các enableAutofocus
phương pháp để mở camera và thiết lập tập trung: stackoverflow.com/questions/19076316/...
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;
}
}
});
}
}
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.
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();
}
}
android.hardware.camera2