API камеры не работает на KITKAT

У меня действительно странная проблема. Следующий код, который я использую, используется для создания снимка при нажатии кнопки. Он работает правильно на телефонах Jelly Bean, но не на Kitkat:

MainActivity.java :

package com.example.takepic; import android.app.Activity; import android.content.pm.PackageManager; import android.hardware.Camera; import android.hardware.Camera.CameraInfo; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.Toast; public class MainActivity extends Activity { private final static String DEBUG_TAG = "MakePhotoActivity"; private Camera camera; private Button capture = null; private int cameraId = 0; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); capture = (Button)findViewById(R.id.captureBack); capture.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub camera.startPreview(); //After this, nothing gets printed, and picture does not get taken System.out.println("Camera preview has started."); camera.takePicture(null, null, new PhotoHandler(getApplicationContext())); } }); // do we have a camera? if (!getPackageManager() .hasSystemFeature(PackageManager.FEATURE_CAMERA)) { Toast.makeText(this, "No camera on this device", Toast.LENGTH_LONG) .show(); } else { cameraId = findBackFacingCamera(); if (cameraId < 0) { Toast.makeText(this, "No back facing camera found.", Toast.LENGTH_LONG).show(); } else { camera = Camera.open(cameraId); } } } private int findBackFacingCamera() { int cameraId = -1; // Search for the front facing camera int numberOfCameras = Camera.getNumberOfCameras(); for (int i = 0; i < numberOfCameras; i++) { CameraInfo info = new CameraInfo(); Camera.getCameraInfo(i, info); if (info.facing == CameraInfo.CAMERA_FACING_BACK) { Log.d(DEBUG_TAG, "Camera found"); cameraId = i; break; } } return cameraId; } @Override protected void onPause() { if (camera != null) { camera.release(); camera = null; } super.onPause(); } } 

PhotoHandler.java :

 package com.example.takepic; import java.io.File; import java.io.FileOutputStream; import java.text.SimpleDateFormat; import java.util.Date; import android.content.Context; import android.hardware.Camera; import android.hardware.Camera.PictureCallback; import android.os.Environment; import android.util.Log; import android.widget.Toast; public class PhotoHandler implements PictureCallback { private final Context context; public PhotoHandler(Context context) { this.context = context; } @Override public void onPictureTaken(byte[] data, Camera camera) { File pictureFileDir = getDir(); Toast.makeText(context, "Entered onPictureTaken", Toast.LENGTH_LONG).show(); if (!pictureFileDir.exists() && !pictureFileDir.mkdirs()) { Log.d("Directory error", "Can't create directory to save image."); Toast.makeText(context, "Can't create directory to save image.", Toast.LENGTH_LONG).show(); return; } SimpleDateFormat dateFormat = new SimpleDateFormat("yyyymmddhhmmss"); String date = dateFormat.format(new Date()); String photoFile = "Picture_" + date + ".jpg"; String filename = pictureFileDir.getPath() + File.separator + photoFile; File pictureFile = new File(filename); try { FileOutputStream fos = new FileOutputStream(pictureFile); fos.write(data); fos.close(); Toast.makeText(context, "New Image saved:" + photoFile, Toast.LENGTH_LONG).show(); } catch (Exception error) { Log.d("File saving error", "File" + filename + "not saved: " + error.getMessage()); Toast.makeText(context, "Image could not be saved.", Toast.LENGTH_LONG).show(); } } private File getDir() { // File sdDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); File sdDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath()); Toast.makeText(context, ("Path : "+sdDir.getAbsolutePath()), Toast.LENGTH_LONG).show(); return sdDir; } } 

Файл манифеста:

 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.takepic" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="15" /> <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.takepic.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> 

Я поставил довольно много тостов сообщений и распечаток для целей отладки. Я не размещал logcat здесь, потому что, когда я запускаю это на телефоне KitKat, я ничего не вижу в logcat . Никаких исключений или предупреждений.

Когда я запускаю это на телефоне jellybean , он работает правильно, отображает все тосты и отпечатки и делает снимок.

Когда я запускаю это в Kitkat , я не получаю отладочных сообщений после

 camera.startPreview(); System.out.println("Camera preview has started."); 

Я подозреваю, что проблема связана с API-интерфейсом takePicture, но я не могу его отладить.

Пожалуйста, помогите мне решить эту проблему.

EDIT: После дальнейшего анализа я нашел причину проблемы. Объект PhotoHandler запускается успешно, но метод onPictureTaken не вызывается, возможно, потому, что он не получил информацию, которую камера нажала на камеру. Я не знаю, почему. Пожалуйста, помогите мне исправить эту проблему.

Я заметил, что вы не назначаете камеру на поверхность. Важное значение имеет предоставление поверхности предварительного просмотра.

Согласно документам здесь:

http://developer.android.com/guide/topics/media/camera.html

Следуйте коду, предложенному документом. Съемка без предварительного просмотра – серьезная проблема безопасности. Парни Android, возможно, исправили это в kitkat.

Возможно, вы пропустили эту часть кода при вставке сюда, так как дополнительная проблема также проверяет, что вы выполняете код 'camera.takePicture (null, null, callback)' внутри метода обратного вызова 'onSurfaceCreated' от SurfaceHolder.

Вы можете получить весь соответствующий код по вышеупомянутой ссылке.

Коллекция мусора KitKat работает иначе, чем предыдущие API.

Я предполагаю, что объект PhotoHandler который вы передаете takePicture() получает сбор мусора, прежде чем onPictureTaken может быть вызван.

Попробуйте сделать объект PhotoHandler как в переменной экземпляра в вашем MainActivity .

В верхней части класса:

 PhotoHandler photoHandler; 

Затем в onCreate()

 photoHandler = new PhotoHandler(getApplicationContext()); 

Затем, когда вы вызываете takePicture() :

 camera.takePicture(null, null, photoHandler); 

Добавьте в файл манифеста uses-feature :

 <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" /> 

И проверьте эту ссылку . Это может помочь вам.