si android.hardware.Camera
est obsolète et que vous ne pouvez pas utiliser la variable Camera
, quelle serait l'alternative à cela?
si android.hardware.Camera
est obsolète et que vous ne pouvez pas utiliser la variable Camera
, quelle serait l'alternative à cela?
Réponses:
Selon le guide des développeurs Android pour android.hardware.Camera
, ils déclarent:
Nous vous recommandons d'utiliser la nouvelle API android.hardware.camera2 pour les nouvelles applications.
Sur la page d'informations sur android.hardware.camera2
, (lien ci-dessus), il est indiqué:
Le package android.hardware.camera2 fournit une interface aux appareils photo individuels connectés à un appareil Android. Il remplace la classe Camera obsolète.
Lorsque vous consultez cette documentation, vous constaterez que l'implémentation de ces 2 API de caméra est très différente.
Par exemple, activer l'orientation de la caméra android.hardware.camera
@Override
public int getOrientation(final int cameraId) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
return info.orientation;
}
Contre 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;
}
}
Cela rend difficile le passage de l'un à l'autre et l'écriture de code capable de gérer les deux implémentations.
Notez que dans cet exemple de code unique, j'ai déjà dû contourner le fait que l'ancienne API de caméra fonctionne avec des int
primitives pour les ID de caméra tandis que la nouvelle fonctionne avecString
objets. Pour cet exemple, j'ai rapidement corrigé cela en utilisant int comme index dans la nouvelle API. Si la caméra renvoyée n'est pas toujours dans le même ordre, cela entraînera déjà des problèmes. Une autre approche consiste à travailler avec des objets String et une représentation String des anciens ID caméra int, ce qui est probablement plus sûr.
Maintenant, pour contourner cette énorme différence, vous pouvez d'abord implémenter une interface et référencer cette interface dans votre code.
Ici, je vais énumérer du code pour cette interface et les 2 implémentations. Vous pouvez limiter la mise en œuvre à ce que vous utilisez réellement de l'API de la caméra pour limiter la quantité de travail.
Dans la section suivante, j'expliquerai rapidement comment charger l'un ou l'autre.
L'interface englobe tout ce dont vous avez besoin, pour limiter cet exemple, je n'ai que 2 méthodes ici.
public interface CameraSupport {
CameraSupport open(int cameraId);
int getOrientation(int cameraId);
}
Maintenant, ayez une classe pour l'ancienne API matérielle de la caméra:
@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;
}
}
Et un autre pour la nouvelle API matérielle:
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;
}
}
}
Maintenant, pour charger votre classe CameraOld
ou votre CameraNew
classe, vous devrez vérifier le niveau de l'API car il CameraNew
n'est disponible qu'à partir du niveau 21 de l'API .
Si vous avez déjà configuré l'injection de dépendances, vous pouvez le faire dans votre module lors de la fourniture de l' CameraSupport
implémentation. Exemple:
@Module public class CameraModule {
@Provides
CameraSupport provideCameraSupport(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return new CameraNew(context);
} else {
return new CameraOld();
}
}
}
Si vous n'utilisez pas DI, vous pouvez simplement créer un utilitaire ou utiliser le modèle Factory pour créer le bon. La partie importante est que le niveau d'API est vérifié.
@SuppressWarnings
dans ce QA stackoverflow.com/questions/7397996
Face au même problème , prendre en charge les appareils plus anciens via l'API de caméra obsolète et avoir besoin de la nouvelle API Camera2 pour les appareils actuels et pour l'avenir; J'ai rencontré les mêmes problèmes - et je n'ai pas trouvé de bibliothèque tierce qui relie les 2 API, probablement parce qu'elles sont très différentes, je me suis tourné vers les principes de base de la POO .
Les 2 API sont nettement différentes, ce qui rend leur échange problématique pour les objets clients qui attendent les interfaces présentées dans l'ancienne API. La nouvelle API a différents objets avec différentes méthodes, construits en utilisant une architecture différente. J'ai de l'amour pour Google, mais ragnabbit! c'est frustrant.
J'ai donc créé une interface se concentrant uniquement sur la fonctionnalité de la caméra dont mon application a besoin et créé un wrapper simple pour les deux API qui implémente cette interface. De cette façon, mon activité de caméra n'a pas à se soucier de la plate-forme sur laquelle elle s'exécute ...
J'ai également mis en place un Singleton pour gérer les API; instancier le wrapper de l'ancienne API avec mon interface pour les anciens appareils Android OS et la nouvelle classe de wrapper de l'API pour les nouveaux appareils utilisant la nouvelle API. Le singleton a un code typique pour obtenir le niveau d'API, puis installe l'objet correct.
La même interface est utilisée par les deux classes de wrapper , donc peu importe si l'application s'exécute sur Jellybean ou Marshmallow - tant que l'interface fournit à mon application ce dont elle a besoin de l'une ou l'autre API Camera, en utilisant les mêmes signatures de méthode; la caméra fonctionne dans l'application de la même manière pour les versions plus récentes et plus anciennes d'Android.
Le Singleton peut également faire certaines choses liées non liées aux API - comme détecter qu'il y a effectivement une caméra sur l'appareil et enregistrer dans la bibliothèque multimédia.
J'espère que l'idée vous aide.
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(); } }
Puis une méthode pour le retourner ...
camera2
? Je suis vraiment confus ... J'ai juste besoin de la enableAutofocus
méthode pour ouvrir la caméra et définir son objectif: stackoverflow.com/questions/19076316/…
Maintenant, nous devons utiliser android.hardware.camera2 car android.hardware.Camera est obsolète et ne fonctionnera que sur 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;
}
}
});
}
}
Les réponses fournies ici selon lesquelles l'API d'appareil photo à utiliser sont incorrectes. Ou mieux dire qu'ils sont insuffisants.
Certains téléphones (par exemple le Samsung Galaxy S6) peuvent être au-dessus du niveau 21 de l'API mais peuvent ne pas prendre en charge 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 de Camera2Api a une méthode pour lire les caractéristiques de la caméra. Vous devez vérifier si le périphérique matériel prend en charge Camera2 Api ou non.
Mais il y a plus de problèmes à gérer si vous voulez vraiment le faire fonctionner pour une application sérieuse: comme, l'option de flash automatique peut ne pas fonctionner pour certains appareils ou le niveau de la batterie du téléphone peut créer une exception RuntimeException sur l'appareil photo ou le téléphone peut renvoyer un invalide identifiant de la caméra et etc.
La meilleure approche est donc d'avoir un mécanisme de secours car, pour une raison quelconque, Camera2 ne démarre pas, vous pouvez essayer Camera1 et si cela échoue également, vous pouvez appeler Android pour ouvrir la caméra par défaut pour vous.
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