se android.hardware.Camera
è deprecato e non è possibile utilizzare la variabile Camera
, quale sarebbe l'alternativa a questo?
se android.hardware.Camera
è deprecato e non è possibile utilizzare la variabile Camera
, quale sarebbe l'alternativa a questo?
Risposte:
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.
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 int
primitive per gli ID della fotocamera mentre quella nuova funziona con gli String
oggetti. 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.
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;
}
}
}
Ora per caricare la tua classe CameraOld
o CameraNew
dovrai 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' CameraSupport
implementazione. 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.
@SuppressWarnings
in questo QA stackoverflow.com/questions/7397996/...
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.
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(); } }
Quindi un metodo per restituirlo ...
camera2
? Sono davvero confuso ... ho solo bisogno il enableAutofocus
metodo per aprire la fotocamera e impostare la sua attenzione: stackoverflow.com/questions/19076316/...
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;
}
}
});
}
}
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.
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