ถ้าandroid.hardware.Camera
เลิกใช้แล้วและคุณไม่สามารถใช้ตัวแปรCamera
ได้ทางเลือกนี้จะเป็นอย่างไร?
ถ้าandroid.hardware.Camera
เลิกใช้แล้วและคุณไม่สามารถใช้ตัวแปรCamera
ได้ทางเลือกนี้จะเป็นอย่างไร?
คำตอบ:
ตามคู่มือสำหรับนักพัฒนา Androidandroid.hardware.Camera
ระบุว่า:
เราขอแนะนำให้ใช้android.hardware.camera2 API ใหม่สำหรับแอปพลิเคชันใหม่
ในหน้าข้อมูลเกี่ยวกับandroid.hardware.camera2
(ลิงก์ด้านบน) ระบุไว้:
แพ็คเกจ android.hardware.camera2 มีอินเทอร์เฟซสำหรับอุปกรณ์กล้องแต่ละตัวที่เชื่อมต่อกับอุปกรณ์ Android แทนที่คลาสกล้องที่เลิกใช้แล้ว
เมื่อคุณตรวจสอบเอกสารดังกล่าวคุณจะพบว่าการใช้งาน Camera API ทั้ง 2 นี้แตกต่างกันมาก
ตัวอย่างเช่นการวางแนวกล้อง android.hardware.camera
@Override
public int getOrientation(final int cameraId) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
return info.orientation;
}
เทียบกับ 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;
}
}
ทำให้ยากที่จะเปลี่ยนจากที่อื่นและเขียนโค้ดที่สามารถจัดการการใช้งานทั้งสองแบบได้
โปรดทราบว่าในตัวอย่างรหัสเดียวนี้ฉันต้องหลีกเลี่ยงความจริงที่ว่า API ของกล้องรุ่นเก่าทำงานร่วมกับint
รหัสดั้งเดิมสำหรับรหัสกล้องในขณะที่อันใหม่ทำงานกับString
วัตถุ สำหรับตัวอย่างนี้ฉันแก้ไขอย่างรวดเร็วโดยใช้ int เป็นดัชนีใน API ใหม่ หากการส่งคืนกล้องไม่ได้อยู่ในลำดับเดียวกันเสมอไปสิ่งนี้จะทำให้เกิดปัญหาได้ ทางเลือกอื่นคือการทำงานกับวัตถุ String และการแสดงสตริงของ int cameraIDs แบบเก่าซึ่งน่าจะปลอดภัยกว่า
ตอนนี้เพื่อหลีกเลี่ยงความแตกต่างที่ยิ่งใหญ่นี้คุณสามารถติดตั้งอินเทอร์เฟซก่อนและอ้างอิงอินเทอร์เฟซนั้นในโค้ดของคุณ
ที่นี่ฉันจะแสดงโค้ดสำหรับอินเทอร์เฟซนั้นและการใช้งาน 2 รายการ คุณสามารถ จำกัด การใช้งานเฉพาะสิ่งที่คุณใช้จริงของ API กล้องเพื่อ จำกัด ปริมาณงาน
ในส่วนถัดไปฉันจะอธิบายวิธีการโหลดอย่างรวดเร็ว
อินเทอร์เฟซตัดสิ่งที่คุณต้องการเพื่อ จำกัด ตัวอย่างนี้ฉันมีเพียง 2 วิธีที่นี่
public interface CameraSupport {
CameraSupport open(int cameraId);
int getOrientation(int cameraId);
}
ตอนนี้มีคลาสสำหรับ API ฮาร์ดแวร์กล้องเก่า:
@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;
}
}
และอีกอันหนึ่งสำหรับ API ฮาร์ดแวร์ใหม่:
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;
}
}
}
ตอนนี้ในการโหลดทั้งของคุณCameraOld
หรือCameraNew
คลาสคุณจะต้องตรวจสอบระดับ API เนื่องจากCameraNew
มีให้ใช้งานจาก api ระดับ 21 เท่านั้น
หากคุณมีการตั้งค่าการฉีดการพึ่งพาไว้แล้วคุณสามารถทำได้ในโมดูลของคุณเมื่อให้การCameraSupport
ใช้งาน ตัวอย่าง:
@Module public class CameraModule {
@Provides
CameraSupport provideCameraSupport(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return new CameraNew(context);
} else {
return new CameraOld();
}
}
}
หากคุณไม่ใช้ DI คุณสามารถสร้างยูทิลิตี้หรือใช้รูปแบบโรงงานเพื่อสร้างรูปแบบที่เหมาะสม ส่วนสำคัญคือการตรวจสอบระดับ API
@SuppressWarnings
QA stackoverflow.com/questions/7397996/…
ประสบปัญหาเดียวกันรองรับอุปกรณ์รุ่นเก่าผ่าน API กล้องที่เลิกใช้แล้วและต้องการ Camera2 API ใหม่สำหรับทั้งอุปกรณ์ปัจจุบันและกำลังก้าวไปสู่อนาคต ฉันวิ่งเข้าไปในปัญหาเดียวกัน - และไม่พบห้องสมุดบุคคลที่ 3 ที่สะพาน 2 APIs, อาจเป็นเพราะพวกเขามีความแตกต่างกันมากผมหันไปว่าจ้าง OOP พื้นฐาน
API 2 ตัวมีความแตกต่างกันอย่างเห็นได้ชัดทำให้การแลกเปลี่ยนระหว่างกันเป็นปัญหาสำหรับอ็อบเจ็กต์ไคลเอ็นต์ที่คาดว่าอินเทอร์เฟซที่แสดงใน API เก่า API ใหม่มีออบเจ็กต์ที่แตกต่างกันด้วยวิธีการที่แตกต่างกันซึ่งสร้างขึ้นโดยใช้สถาปัตยกรรมที่แตกต่างกัน มีใจรัก Google แต่ ragnabbit! ที่น่าผิดหวัง
ดังนั้นฉันจึงสร้างอินเทอร์เฟซโดยเน้นเฉพาะการทำงานของกล้องที่แอปของฉันต้องการและสร้าง Wrapper อย่างง่ายสำหรับทั้งสอง API ที่ใช้อินเทอร์เฟซนั้น ด้วยวิธีนี้กิจกรรมกล้องของฉันไม่ต้องสนใจว่ามันทำงานบนแพลตฟอร์มใด ...
ฉันยังตั้งค่า Singleton เพื่อจัดการ API สร้าง Wrapper ของ API รุ่นเก่ากับอินเทอร์เฟซของฉันสำหรับอุปกรณ์ Android OS รุ่นเก่าและคลาส Wrapper ของ API ใหม่สำหรับอุปกรณ์รุ่นใหม่โดยใช้ API ใหม่ ซิงเกิลตันมีโค้ดทั่วไปเพื่อรับระดับ API จากนั้นอินสแตนซ์อ็อบเจ็กต์ที่ถูกต้อง
ทั้งสองคลาส Wrapper ใช้อินเทอร์เฟซเดียวกันดังนั้นจึงไม่สำคัญว่าแอปจะทำงานบน Jellybean หรือ Marshmallow ตราบใดที่อินเทอร์เฟซให้แอปของฉันพร้อมสิ่งที่ต้องการจาก Camera API โดยใช้ลายเซ็นวิธีเดียวกัน กล้องจะทำงานในแอพในลักษณะเดียวกับ Android ทั้งรุ่นใหม่และรุ่นเก่ากว่า
Singleton ยังสามารถทำสิ่งที่เกี่ยวข้องบางอย่างที่ไม่เชื่อมโยงกับ API ได้เช่นการตรวจจับว่ามีกล้องอยู่ในอุปกรณ์และบันทึกลงในไลบรารีสื่อ
ฉันหวังว่าแนวคิดนี้จะช่วยคุณได้
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(); } }
วิธีการส่งคืน ...
camera2
ไหม ฉันสับสนจริงๆ ... ฉันแค่ต้องการenableAutofocus
วิธีเปิดกล้องและตั้งโฟกัส: stackoverflow.com/questions/19076316/…
ตอนนี้เราต้องใช้ android.hardware.camera2 เป็น android.hardware.Camera เลิกใช้งานแล้วซึ่งจะใช้ได้เฉพาะกับ 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;
}
}
});
}
}
คำตอบที่ให้ไว้ที่นี่เนื่องจาก API ของกล้องที่จะใช้ไม่ถูกต้อง หรือดีกว่าที่จะบอกว่าพวกเขาไม่เพียงพอ
โทรศัพท์บางรุ่น (เช่น Samsung Galaxy S6) อาจสูงกว่าระดับ api 21 แต่อาจยังไม่รองรับ Camera2 api
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;
}
คลาส CameraManager ใน Camera2Api มีวิธีการอ่านลักษณะของกล้อง คุณควรตรวจสอบว่าอุปกรณ์ฮาร์ดแวร์ที่ชาญฉลาดรองรับ Camera2 Api หรือไม่
แต่มีปัญหาอื่น ๆ ที่ต้องจัดการหากคุณต้องการให้มันใช้งานได้จริงสำหรับแอปพลิเคชันที่จริงจัง: เช่นเดียวกับตัวเลือกแฟลชอัตโนมัติอาจไม่ทำงานกับอุปกรณ์บางอย่างหรือระดับแบตเตอรี่ของโทรศัพท์อาจสร้าง RuntimeException บนกล้องหรือโทรศัพท์อาจส่งคืนไม่ถูกต้อง รหัสกล้องและอื่น ๆ
แนวทางที่ดีที่สุดคือการมีกลไกสำรองเนื่องจากเหตุผลบางอย่าง Camera2 ไม่สามารถเริ่มต้นได้คุณสามารถลองใช้ Camera1 และหากล้มเหลวเช่นกันคุณสามารถโทรไปยัง Android เพื่อเปิดกล้องเริ่มต้นให้คุณได้
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