Reputation: 83
I am developing an android application. I use a custom camera in a Fragment of a ViewPager. I have a problem of compatibility, my app works on android 4.2.2 , 4.4.4, 5.0.1 . But if i try with an android version 5.1.0 or 5.1.1 , the app crash . I have this log :
12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: FATAL EXCEPTION: main 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: Process: fr.jumaxdev.lekeen, PID: 1999 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: java.lang.NullPointerException: Attempt to read from field 'int android.hardware.Camera$Size.width' on a null object reference 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: at fr.jumaxdev.lekeen.Fragment_Photo.initPreview(Fragment_Photo.java:200) 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: at fr.jumaxdev.lekeen.Fragment_Photo.access$200(Fragment_Photo.java:35) 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: at fr.jumaxdev.lekeen.Fragment_Photo$5.surfaceChanged(Fragment_Photo.java:267) 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: at android.view.SurfaceView.updateWindow(SurfaceView.java:699) 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:200) 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:1018) 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2301) 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1300) 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7017) 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: at android.view.Choreographer$CallbackRecord.run(Choreographer.java:777) 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: at android.view.Choreographer.doCallbacks(Choreographer.java:590) 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: at android.view.Choreographer.doFrame(Choreographer.java:560) 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:763) 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:739) 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:95) 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: at android.os.Looper.loop(Looper.java:145) 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:6891) 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: at java.lang.reflect.Method.invoke(Method.java:372) 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404) 12-17 11:13:20.081 1999-1999/fr.jumaxdev.lekeen E/AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)
So the problem is "java.lang.NullPointerException: Attempt to read from field 'int android.hardware.Camera$Size.width' on a null object reference" , the camera size is null ..
Here are some codes :
@Override
public void onResume() {
super.onResume();
camera = getCamera("back");
currentCamera = 1;
startPreview();
}
@Override
public void onPause() {
if (inPreview) {
camera.stopPreview();
}
camera.release();
camera = null;
inPreview = false;
super.onPause();
}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int width, int height)
{
// Source: http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
Camera.Size optimalSize = null;
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) height / width;
// Try to find a size match which suits the whole screen minus the menu on the left.
for (Camera.Size size : sizes){
if (size.height != width) continue;
double ratio = (double) size.width / size.height;
if (ratio <= targetRatio + ASPECT_TOLERANCE && ratio >= targetRatio - ASPECT_TOLERANCE){
optimalSize = size;
}
}
// If we cannot find the one that matches the aspect ratio, ignore the requirement.
if (optimalSize == null) {
// TODO : Backup in case we don't get a size.
}
return optimalSize;
}
private void initPreview(int width, int height) {
if (camera != null && cameraPreviewHolder.getSurface() != null) {
try {
camera.setPreviewDisplay(cameraPreviewHolder);
} catch (Throwable t) {
}
if (!cameraConfigured) {
Camera.Parameters parameters = camera.getParameters();
if (camera.getParameters().getSupportedPreviewSizes() != null){
Camera.Size previewSize = getOptimalPreviewSize(camera.getParameters().getSupportedPreviewSizes(), width, height);;
parameters.setPreviewSize(previewSize.width, previewSize.height);
}
camera.setParameters(parameters);
cameraConfigured = true;
}
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void startPreview() {
if (cameraConfigured && camera != null) {
camera.startPreview();
inPreview = true;
camera.setDisplayOrientation(90);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
camera.enableShutterSound(false);
}
}
}
To resume, if the android version in > 5.0.1, the app crash. But why is it depending on the android version ...?
If someone can solve my problem, i pay him a beer ! Thanks. Attard Julien.
Upvotes: 2
Views: 1796
Reputation: 309
Permissions changed recently.
Use this in the onCreate():
String[] permissions = {"android.permission.CAMERA"};
int permissionRequestCode = 200;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(permissions[0]) != PackageManager.PERMISSION_GRANTED)
{
requestPermissions(permissions, permissionRequestCode);
}
The permissionRequestCode is needed to check if the user actually accepted the permission in the callback: 'onRequestPermissionsResult()'
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case 200: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//Permission Granted
} else {
//Permission Denied
}
return;
//Use other case lines for other requests (with different requestCodes)
}
}
}
Upvotes: 2