Fotocamera Android android.hardware.Camera deprecata


97

se android.hardware.Cameraè deprecato e non è possibile utilizzare la variabile Camera, quale sarebbe l'alternativa a questo?



1
Ho avuto questo problema con un'app e l'ho trovato molto utile. Se usi l'intento, sei limitato. Quindi questo tutorial spiega un'alternativa: developer.android.com/guide/topics/media/…
Ronaldo Bahia

Risposte:


102

Documentazione API

Secondo la guida per sviluppatori Android per android.hardware.Camera, affermano:

Si consiglia di utilizzare la nuova API android.hardware.camera2 per nuove applicazioni.

Nella pagina informativa su android.hardware.camera2, (linkato sopra), si afferma:

Il pacchetto android.hardware.camera2 fornisce un'interfaccia ai singoli dispositivi della fotocamera collegati a un dispositivo Android. Sostituisce la classe Camera deprecata.

Il problema

Quando controlli quella documentazione, scoprirai che l'implementazione di queste 2 API della fotocamera è molto diversa.

Ad esempio, attivare l'orientamento della fotocamera android.hardware.camera

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

Contro 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;
    }
}

Ciò rende difficile passare da uno all'altro e scrivere codice in grado di gestire entrambe le implementazioni.

Si noti che in questo esempio di codice singolo ho già dovuto aggirare il fatto che l'API della vecchia fotocamera funziona con le intprimitive per gli ID della fotocamera mentre quella nuova funziona con gli Stringoggetti. Per questo esempio ho risolto rapidamente il problema utilizzando int come indice nella nuova API. Se la fotocamera restituita non è sempre nello stesso ordine, ciò causerà già problemi. Un approccio alternativo consiste nel lavorare con gli oggetti String e la rappresentazione String dei vecchi int cameraID che è probabilmente più sicuro.

Uno in giro

Ora per aggirare questa enorme differenza puoi prima implementare un'interfaccia e fare riferimento a tale interfaccia nel tuo codice.

Qui elencherò un po 'di codice per quell'interfaccia e le 2 implementazioni. Puoi limitare l'implementazione a ciò che usi effettivamente dell'API della fotocamera per limitare la quantità di lavoro.

Nella prossima sezione spiegherò rapidamente come caricare l'uno o l'altro.

L'interfaccia racchiude tutto ciò di cui hai bisogno, per limitare questo esempio ho solo 2 metodi qui.

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

Ora disponi di una classe per la vecchia API hardware della fotocamera:

@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;
    }
}

E un altro per la nuova API hardware:

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

Caricamento dell'API corretta

Ora per caricare la tua classe CameraOldo CameraNewdovrai controllare il livello API poiché CameraNewè disponibile solo dal livello API 21.

Se hai già impostato l'inserimento delle dipendenze, puoi farlo nel modulo quando fornisci l' CameraSupportimplementazione. Esempio:

@Module public class CameraModule {

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

Se non usi DI, puoi semplicemente creare un'utilità o utilizzare il pattern Factory per creare quello corretto. La parte importante è che il livello API è controllato.


25
Cosa succede se devo supportare il livello API Android inferiore a 21?
niveuseverto

1
@Angelius forse questa documentazione sarebbe di aiuto developer.android.com/guide/topics/media/camera.html - ma questa potrebbe essere una domanda a parte, o cercare domande sull'utilizzo di variabili deprecate.

@Angelius ecco alcune informazioni su @SuppressWarningsin questo QA stackoverflow.com/questions/7397996/...

5
Sto pensando non solo di usare le classi @deprecated, ma come creare un'app con compatibilità con le versioni precedenti? qualche aiuto ufficiale su questo? Ne ho un'idea: l'interfaccia ICamera, supportata dall'oggetto Camera corrispondente alla versione corrente del telefono, ma è un po 'semplice e difficile da mantenere ...
niveuseverto

@Angelius quello che stai descrivendo potrebbe essere una domanda a parte (controlla prima se è stato chiesto prima).

5

Ha affrontato lo stesso problema , supportando i dispositivi meno recenti tramite l'API della fotocamera deprecata e necessitando della nuova API Camera2 sia per i dispositivi attuali che per il futuro; Ho riscontrato gli stessi problemi e non ho trovato una libreria di terze parti che colleghi le 2 API, probabilmente perché sono molto diverse, mi sono rivolto ai principali OOP di base .

Le 2 API sono notevolmente diverse, rendendo problematico il loro scambio per gli oggetti client che si aspettano le interfacce presentate nella vecchia API. La nuova API ha diversi oggetti con metodi diversi, costruiti utilizzando un'architettura diversa. Ho amore per Google, ma ragnabbit! è frustrante.

Quindi ho creato un'interfaccia focalizzata solo sulla funzionalità della fotocamera di cui la mia app ha bisogno e ho creato un semplice wrapper per entrambe le API che implementano quell'interfaccia. In questo modo l'attività della mia videocamera non deve preoccuparsi di quale piattaforma gira ...

Ho anche impostato un Singleton per gestire le API; istanziazione del wrapper dell'API precedente con la mia interfaccia per i dispositivi con sistema operativo Android meno recente e della nuova classe wrapper dell'API per i dispositivi più recenti che utilizzano la nuova API. Il singleton ha un codice tipico per ottenere il livello API e quindi istanza l'oggetto corretto.

La stessa interfaccia viene utilizzata da entrambe le classi wrapper , quindi non importa se l'app viene eseguita su Jellybean o Marshmallow, purché l'interfaccia fornisca alla mia app ciò di cui ha bisogno da entrambe le API della fotocamera, utilizzando le stesse firme del metodo; la fotocamera funziona nell'app allo stesso modo sia per le versioni più recenti che per quelle precedenti di Android.

Il Singleton può anche fare alcune cose correlate non legate alle API, come rilevare che c'è effettivamente una fotocamera sul dispositivo e salvare nella libreria multimediale.

Spero che l'idea ti aiuti.


Ad esempio:public interface AllCameraInterface { void open(); boolean setDirection(); Bitmap preview(); Bitmap takePhoto(); void close(); }
Robert Sherman

ex: 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(); } }Quindi un metodo per restituirlo ...
Robert Sherman

apparentemente non sono consentite interruzioni di riga nei commenti ;-) ma funziona davvero.
Robert Sherman

4
perché non aggiungere i codici nei commenti direttamente nella risposta?
Angel Koh

@RobertSherman Ciao Robert, puoi aiutarmi a riscrivere questo piccolo frammento per il nuovo camera2? Sono davvero confuso ... ho solo bisogno il enableAutofocusmetodo per aprire la fotocamera e impostare la sua attenzione: stackoverflow.com/questions/19076316/...

0

Ora dobbiamo usare android.hardware.camera2 come android.hardware.Camera è deprecato e funziona solo su 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

Le risposte fornite qui come l'API della fotocamera da utilizzare sono sbagliate. O meglio dire che sono insufficienti.

Alcuni telefoni (ad esempio Samsung Galaxy S6) potrebbero essere al di sopra del livello 21 api ma potrebbero comunque non supportare l'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;
}

La classe CameraManager in Camera2Api ha un metodo per leggere le caratteristiche della fotocamera. Dovresti controllare se il dispositivo hardware supporta o meno Camera2 Api.

Ma ci sono più problemi da gestire se vuoi davvero farlo funzionare per un'applicazione seria: come, l'opzione di flash automatico potrebbe non funzionare per alcuni dispositivi o il livello della batteria del telefono potrebbe creare una RuntimeException sulla fotocamera o il telefono potrebbe restituire un valore non valido ID fotocamera e così via

Quindi l'approccio migliore è avere un meccanismo di fallback poiché per qualche motivo Camera2 non si avvia, puoi provare Camera1 e se anche questo fallisce puoi fare una chiamata ad Android per aprire la fotocamera predefinita per te.


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


 }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.