jeśli android.hardware.Camera
jest przestarzała i nie możesz użyć zmiennej Camera
, jaka byłaby alternatywa dla tego?
jeśli android.hardware.Camera
jest przestarzała i nie możesz użyć zmiennej Camera
, jaka byłaby alternatywa dla tego?
Odpowiedzi:
Według przewodnika dla programistów Androida dla android.hardware.Camera
, stwierdzają:
W przypadku nowych aplikacji zalecamy korzystanie z nowego interfejsu API android.hardware.camera2 .
Na stronie informacyjnej na temat android.hardware.camera2
(link powyżej) znajduje się:
Pakiet android.hardware.camera2 zapewnia interfejs do poszczególnych kamer podłączonych do urządzenia z systemem Android. Zastępuje wycofaną klasę Camera.
Po sprawdzeniu tej dokumentacji przekonasz się, że implementacja tych dwóch interfejsów API aparatu jest bardzo różna.
Na przykład włączenie orientacji aparatu android.hardware.camera
@Override
public int getOrientation(final int cameraId) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
return info.orientation;
}
Przeciw 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;
}
}
Utrudnia to przełączanie się z jednej aplikacji na drugą i pisanie kodu, który obsługuje obie implementacje.
Zwróć uwagę, że w tym pojedynczym przykładzie kodu musiałem już obejść fakt, że stary interfejs API kamery działa z int
prymitywami dla identyfikatorów kamer, podczas gdy nowy działa z String
obiektami. W tym przykładzie szybko to naprawiłem, używając int jako indeksu w nowym API. Jeśli zwrócona kamera nie zawsze jest w tej samej kolejności, spowoduje to już problemy. Alternatywnym podejściem jest praca z obiektami String i reprezentacją String starych int cameraIDs, co jest prawdopodobnie bezpieczniejsze.
Teraz, aby obejść tę ogromną różnicę, możesz najpierw zaimplementować interfejs i odwołać się do tego interfejsu w swoim kodzie.
Tutaj wymienię kod dla tego interfejsu i dwie implementacje. Możesz ograniczyć implementację do tego, z czego faktycznie korzystasz z interfejsu API aparatu, aby ograniczyć ilość pracy.
W następnej sekcji szybko wyjaśnię, jak załadować jeden lub drugi.
Interfejs opakowujący wszystko, czego potrzebujesz, aby ograniczyć ten przykład, mam tutaj tylko 2 metody.
public interface CameraSupport {
CameraSupport open(int cameraId);
int getOrientation(int cameraId);
}
Teraz mamy klasę dla starego interfejsu API sprzętowego aparatu:
@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;
}
}
I jeszcze jeden dla nowego interfejsu API sprzętowego:
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;
}
}
}
Teraz, aby załadować swoją klasę CameraOld
lub CameraNew
klasę, musisz sprawdzić poziom interfejsu API, ponieważ CameraNew
jest dostępny tylko od poziomu API 21.
Jeśli masz już skonfigurowaną iniekcję zależności, możesz to zrobić w swoim module podczas dostarczania CameraSupport
implementacji. Przykład:
@Module public class CameraModule {
@Provides
CameraSupport provideCameraSupport(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return new CameraNew(context);
} else {
return new CameraOld();
}
}
}
Jeśli nie używasz DI, możesz po prostu stworzyć narzędzie lub użyć wzorca Factory, aby stworzyć właściwy. Ważną częścią jest sprawdzenie poziomu API.
@SuppressWarnings
tego stackoverflow
W obliczu tego samego problemu , obsługując starsze urządzenia przez przestarzały interfejs API aparatu i potrzebując nowego interfejsu API Camera2 zarówno dla obecnych urządzeń, jak i dla przyszłych; Natknąłem się na te same problemy - i nie znalazłem biblioteki innej firmy, która łączyłaby 2 interfejsy API, prawdopodobnie dlatego, że są one bardzo różne, zwróciłem się do podstawowych zasad OOP .
Te dwa interfejsy API są znacząco różne, co sprawia, że ich wymiana jest problematyczna dla obiektów klientów oczekujących interfejsów prezentowanych w starym API. Nowe API ma różne obiekty z różnymi metodami, zbudowane przy użyciu innej architektury. Uwielbiam Google, ale ragnabbit! to frustrujące.
Dlatego stworzyłem interfejs skupiający się tylko na funkcjach aparatu, których potrzebuje moja aplikacja, i stworzyłem proste opakowanie dla obu interfejsów API, które implementują ten interfejs. W ten sposób moja aktywność kamery nie musi przejmować się tym, na której platformie działa ...
Założyłem również Singletona do zarządzania API (-ami); tworzenie instancji opakowania starszego interfejsu API z moim interfejsem dla starszych urządzeń z systemem Android oraz klasy opakowania nowego interfejsu API dla nowszych urządzeń korzystających z nowego interfejsu API. Singleton ma typowy kod, który pobiera poziom interfejsu API, a następnie instanuje poprawny obiekt.
Ten sam interfejs jest używany przez obie klasy opakowujące , więc nie ma znaczenia, czy aplikacja działa na Jellybean czy Marshmallow - o ile interfejs dostarcza mojej aplikacji to, czego potrzebuje z dowolnego interfejsu API aparatu, używając tych samych sygnatur metod; kamera działa w aplikacji w ten sam sposób zarówno w nowszych, jak i starszych wersjach Androida.
Singleton może również wykonywać pewne czynności niezwiązane z interfejsami API - takie jak wykrywanie, że na urządzeniu rzeczywiście znajduje się kamera, i zapisywanie w bibliotece multimediów.
Mam nadzieję, że ten pomysł ci pomoże.
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(); } }
metoda zwrotu ...
camera2
? Jestem naprawdę zdezorientowany ... Potrzebuję tylko enableAutofocus
metody, aby otworzyć kamerę i ustawić jej ostrość: stackoverflow.com/questions/19076316/ ...
Teraz musimy używać android.hardware.camera2 jako android.hardware.Camera jest przestarzała, która będzie działać tylko z 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;
}
}
});
}
}
Podane tutaj odpowiedzi dotyczące tego, którego interfejsu API aparatu należy użyć, są nieprawidłowe. Albo lepiej powiedzieć, że są niewystarczające.
Niektóre telefony (na przykład Samsung Galaxy S6) mogą być powyżej poziomu API 21, ale nadal mogą nie obsługiwać interfejsu 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;
}
CameraManager w Camera2Api zawiera metodę odczytywania charakterystyk aparatu. Powinieneś sprawdzić, czy mądre urządzenie obsługuje Camera2 Api, czy nie.
Ale jest więcej problemów do rozwiązania, jeśli naprawdę chcesz, aby działał w poważnej aplikacji: na przykład opcja automatycznego flashowania może nie działać w przypadku niektórych urządzeń lub poziom naładowania baterii telefonu może stworzyć wyjątek Runtime w aparacie lub telefonie może zwrócić nieprawidłowy identyfikator aparatu itp.
Najlepszym rozwiązaniem jest więc posiadanie mechanizmu awaryjnego, ponieważ z jakiegoś powodu Camera2 nie uruchamia się, możesz wypróbować Camera1, a jeśli to również się nie powiedzie, możesz zadzwonić do Androida, aby otworzyć domyślną kamerę.
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