กล้อง Android android.hardware.Camera เลิกใช้แล้ว


97

ถ้าandroid.hardware.Cameraเลิกใช้แล้วและคุณไม่สามารถใช้ตัวแปรCameraได้ทางเลือกนี้จะเป็นอย่างไร?



1
ฉันมีปัญหากับแอพนี้และพบว่าสิ่งนี้มีประโยชน์มาก หากคุณใช้ความตั้งใจคุณจะถูก จำกัด ดังนั้นบทช่วยสอนนี้จะอธิบายทางเลือกอื่น: developer.android.com/guide/topics/media/…
Ronaldo Bahia

คำตอบ:


103

เอกสาร API

ตามคู่มือสำหรับนักพัฒนา 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;
        }
    }
}

กำลังโหลด API ที่เหมาะสม

ตอนนี้ในการโหลดทั้งของคุณ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


25
จะเกิดอะไรขึ้นหากฉันต้องการรองรับ Android API ระดับน้อยกว่า 21
niveuseverto

1
@Angelius เอกสารนี้อาจช่วยให้developer.android.com/guide/topics/media/camera.html แต่อาจเป็นคำถามแยกกันหรือค้นหาคำถามเกี่ยวกับการต้องใช้ตัวแปรที่เลิกใช้แล้ว

@Angelius นี่คือข้อมูลบางส่วนเกี่ยวกับ@SuppressWarningsQA stackoverflow.com/questions/7397996/…

5
ฉันกำลังคิดว่าจะไม่ใช้แค่คลาส @deprecated แต่จะสร้างแอปที่เข้ากันได้แบบย้อนหลังได้อย่างไร ความช่วยเหลืออย่างเป็นทางการเกี่ยวกับเรื่องนี้หรือไม่? ฉันมีความคิดเกี่ยวกับสิ่งนี้: อินเทอร์เฟซ ICamera ซึ่งได้รับการสนับสนุนด้วยวัตถุกล้องที่สอดคล้องกับรุ่นโทรศัพท์ปัจจุบัน แต่นี่เป็นสิ่งที่ตรงไปตรงมาและดูแลรักษายาก ...
niveuseverto

@Angelius สิ่งที่คุณอธิบายอาจเป็นคำถามแยกต่างหาก (ตรวจสอบดูว่ามีการถามก่อนหรือไม่)

5

ประสบปัญหาเดียวกันรองรับอุปกรณ์รุ่นเก่าผ่าน 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(); }
Robert Sherman

เช่น: 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(); } }วิธีการส่งคืน ...
Robert Sherman

เห็นได้ชัดว่าไม่อนุญาตให้มีการแบ่งบรรทัดในความคิดเห็น ;-) แต่มันใช้งานได้จริง
Robert Sherman

4
ทำไมไม่ผนวกรหัสในความคิดเห็นลงในคำตอบโดยตรง?
Angel Koh

@RobertSherman สวัสดี Robert คุณช่วยเขียนตัวอย่างเล็ก ๆ น้อย ๆ นี้ใหม่ได้camera2ไหม ฉันสับสนจริงๆ ... ฉันแค่ต้องการenableAutofocusวิธีเปิดกล้องและตั้งโฟกัส: stackoverflow.com/questions/19076316/…

0

ตอนนี้เราต้องใช้ 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;
                    }


            }
        });
    }
}

0

คำตอบที่ให้ไว้ที่นี่เนื่องจาก 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 เพื่อเปิดกล้องเริ่มต้นให้คุณได้


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();
           }


 }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.