Страницы

Поиск по вопросам

четверг, 25 октября 2018 г.

Ошибка при загрузке фотографий через камеру (Android)

Встретился с такой проблемой:
При загрузке картинки с галереи или фотографии с приложения камеры в приложение, сохраняется путь до этой картинки и производится её отображение в приложении.
Но, если версия андроид - 4.4.4 или 5, приложение вылетает именно после того, как я открыл приложение камеры и сделал фото, чтобы оно пошло в приложение. Эта ошибка наблюдается на 4х версиях андроид и на некоторых 5х(на Nexus5 - 6.0.1, SGS3 Cyanogen11 наблюдается ошибка, на LG G2 -5.0.2, sony z3c - 6.0.1, HTC - 4.3 не наблюдается). При выборе картинки с галереи (повторюсь) всё работает нормально.
Вызов интента:
boolean hasPermission = false; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { hasPermission = (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED); } if (hasPermission) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { ActivityCompat.requestPermissions((AppCompatActivity)getContext(), new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1); } }else { ((CategoryGoodsActivity) getContext()).startActivityForResult(Utils.getPickImageIntent(getContext()), Integer.parseInt(v.getTag().toString()) ); }
Генерация интента:
public static Intent getPickImageIntent(Context context) { Intent chooserIntent = null;
List intentList = new ArrayList<>(); Intent pickIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); takePhotoIntent.putExtra("return-data", true);
intentList = addIntentsToList(context, intentList, pickIntent); intentList = addIntentsToList(context, intentList, takePhotoIntent);
if (intentList.size() > 0) { chooserIntent = Intent.createChooser(intentList.remove(intentList.size() - 1), "Выберите"); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentList.toArray(new Parcelable[]{})); }
return chooserIntent; }
Получение картинки:
public void onActivityResult(int requestCode, int resultCode, Intent data) { Log.e("sds", "requestCode="+requestCode+ "
resultCode="+resultCode); if (resultCode == Activity.RESULT_OK && data != null) {
String path = getPathFromCameraData(data, this);
if (path != null) { Toast.makeText(getApplicationContext(), path, Toast.LENGTH_SHORT).show(); Log.e("sds", path); switch (requestCode){ case 1: itemsComments.get(0).image1 = path; break; case 2: itemsComments.get(0).image2 = path; break; case 3: itemsComments.get(0).image3 = path; break; } adapterComments.notifyDataSetChanged(); } } }
public String getPathFromCameraData(Intent data, Context context) { Uri selectedImage = data.getData(); String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = context.getContentResolver().query(selectedImage, filePathColumn, null, null, null);
if(cursor != null) { cursor.moveToFirst(); int columnIndex = cursor.getColumnIndex(filePathColumn[0]); String picturePath = cursor.getString(columnIndex); cursor.close(); return picturePath; }else{ return selectedImage.getPath(); } }
Лог при сбое:
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=Intent { act=inline-data (has extras) }} to activity {ru.diit.lefood/ru.diit.lefood.screens.food.CategoryGoodsActivity}: java.lang.NullPointerException at android.app.ActivityThread.deliverResults(ActivityThread.java:3389) at android.app.ActivityThread.handleSendResult(ActivityThread.java:3432) at android.app.ActivityThread.access$1300(ActivityThread.java:144) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1253) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:5146) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:732) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:566) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.NullPointerException at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1420) at android.content.ContentResolver.query(ContentResolver.java:445) at android.content.ContentResolver.query(ContentResolver.java:404) at ru.diit.lefood.screens.food.CategoryGoodsActivity.getPathFromCameraData(CategoryGoodsActivity.java:293) at ru.diit.lefood.screens.food.CategoryGoodsActivity.onActivityResult(CategoryGoodsActivity.java:268) at android.app.Activity.dispatchActivityResult(Activity.java:5423) at android.app.ActivityThread.deliverResults(ActivityThread.java:3385) at android.app.ActivityThread.handleSendResult(ActivityThread.java:3432)  at android.app.ActivityThread.access$1300(ActivityThread.java:144)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1253)  at android.os.Handler.dispatchMessage(Handler.java:102)  at android.os.Looper.loop(Looper.java:136)  at android.app.ActivityThread.main(ActivityThread.java:5146)  at java.lang.reflect.Method.invokeNative(Native Method)  at java.lang.reflect.Method.invoke(Method.java:515)  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:732)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:566)  at dalvik.system.NativeStart.main(Native Method) 
Скрины того, что я делаю:
По нажатию на скрепку выходят 2 пункта

Выбрали камеру и сделали снимок

При нажатии на кнопку принятия изображения вылетает

В общем, жалуется в логе на эту строчку:
Cursor cursor = context.getContentResolver().query(selectedImage, filePathColumn, null, null, null);
которая находится в методе getPathFromCameraData
public String getPathFromCameraData(Intent data, Context context) { Uri selectedImage = data.getData(); String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = context.getContentResolver().query(selectedImage, filePathColumn, null, null, null);
if(cursor != null) { cursor.moveToFirst(); int columnIndex = cursor.getColumnIndex(filePathColumn[0]); String picturePath = cursor.getString(columnIndex); cursor.close(); return picturePath; }else{ return selectedImage.getPath(); } }
Ругается, что переменная selectedImage нулевая. Делал дебаг этой строчки Uri selectedImage = data.getData(); и data не пустая, думаю, что присвоение не работает или адрес на фото с камеры где-то теряется.
Не хочется извращаться, создавая пустой файл и позже присваивая ему фотографию, так как это работает с единичной фотографией, хотелось бы найти более простое решение.
В методе как раз закомментил извращенство с созданием файла:
public static Intent getPickImageIntent(Context context) { Intent chooserIntent = null;
List intentList = new ArrayList<>();
//String imageFilePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/picture.jpg"; //File imageFile = new File(imageFilePath); //Uri picUri = Uri.fromFile(imageFile); // convert path to Uri
Intent pickIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); takePhotoIntent.putExtra("return-data", true); //takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, picUri); intentList = addIntentsToList(context, intentList, pickIntent); intentList = addIntentsToList(context, intentList, takePhotoIntent);
if (intentList.size() > 0) { chooserIntent = Intent.createChooser(intentList.remove(intentList.size() - 1), "Выберите"); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentList.toArray(new Parcelable[]{})); }
return chooserIntent; }
Манифест имеет:


Ответ

1) То что data.getData() возвращает null - это абсолютно нормально. Это означает лишь то,- что файл с полноразмерной фотографией небыл создан (нигде). Обычно в таких случаях система возвращает thumbnail. Обработать это можно например так:
if(data.getData()==null){ bitmap = (Bitmap)data.getExtras().get("data"); }else{ bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), data.getData()); }
2) Для того чтобы получить полноразмерное фото обязятельно нужно указывать EXTRA_OUTPUT. Об этом явно сказано в документации в разделе "Taking Photos Simply" -> "Save the Full-size Photo"
Итого: нужно просто раскомментировать строчку с EXTRA_OUTPUT :)
UPD 14.09.2016 Создание временного файл. Для создания публичного файла в который может писать любое приложение (включая камеру) используйте:
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); path.mkdirs(); File file = new File(path, "DemoPicture.jpg");

Комментариев нет:

Отправить комментарий