Как получить результат камеры как uri в папке с данными?

Я создаю приложение, в котором я хочу захватить изображение, а затем я хочу отправить это изображение в электронное письмо как вложение.

Я открываю камеру, используя действие android.provider.MediaStore.ACTION_IMAGE_CAPTURE и я передаю Uri файла как параметр EXTRA_OUTPUT чтобы вернуть изображение в файл. Это работает отлично, и я могу получить захваченное изображение, если я использую external storage uri как EXTRA_OUTPUT но если я использую папку данных uri, она не работает, и камера не закрывается, и все ее кнопки не работают.

Вот мой код для получения результата во внешнем каталоге хранилища

 Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); File out = Environment.getExternalStorageDirectory(); out = new File(out, imagename); i.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(out)); startActivityForResult(i, CAMERA_RESULT); 

И этот код предназначен для получения изображения в папке с данными

 Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); File out = getFilesDir(); out = new File(out, MyPharmacyOptions.PRESCRIPTION_IMAGE_NAME); i.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(out)); startActivityForResult(i, CAMERA_RESULT); 

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

Вот мой контент, предоставляющий class

 public class MyContentProvider extends ContentProvider { private static final String Tag = RingtonContentProvider.class.getName(); public static final Uri CONTENT_URI = Uri .parse("content://xyz/"); private static final HashMap MIME_TYPES = new HashMap(); static { MIME_TYPES.put(".mp3", "audio/mp3"); MIME_TYPES.put(".wav", "audio/mp3"); MIME_TYPES.put(".jpg", "image/jpeg"); } @Override public boolean onCreate() { return true; } @Override public String getType(Uri uri) { String path = uri.toString(); for (String extension : MIME_TYPES.keySet()) { if (path.endsWith(extension)) { return (MIME_TYPES.get(extension)); } } return (null); } @Override public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { File f = new File(getContext().getFilesDir(), uri.getPath()); if (f.exists()) { return (ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY)); } throw new FileNotFoundException(uri.getPath()); } @Override public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs, String sort) { throw new RuntimeException("Operation not supported"); } @Override public Uri insert(Uri uri, ContentValues initialValues) { File file = new File(getContext().getFilesDir(), uri.getPath()); if(file.exists()) file.delete(); try { file.createNewFile(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return Uri.fromFile(file); } @Override public int update(Uri uri, ContentValues values, String where, String[] whereArgs) { throw new RuntimeException("Operation not supported"); } @Override public int delete(Uri uri, String where, String[] whereArgs) { File f = new File(getContext().getFilesDir(), "image1.jpg"); if(f.exists()) f.delete(); f = new File(getContext().getFilesDir(), "image2.jpg"); if(f.exists()) f.delete(); getContext().getContentResolver().notifyChange(CONTENT_URI, null); } } 

Поэтому, чтобы использовать этот контент, я использую следующий код, чтобы передать uri активности камеры

 Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); Uri uri = MyContentProvider.CONTENT_URI; uri = Uri.withAppendedPath(uri, imagename); getContentResolver().insert(uri, null); getContentResolver().notifyChange(RingtonContentProvider.CONTENT_URI, null); Log.d(Tag, uri.toString()); i.putExtra(MediaStore.EXTRA_OUTPUT, uri); startActivityForResult(i, CAMERA_RESULT); 

Теперь, если я передаю URL-адрес другого внешнего каталога хранения, который открывается камерой, но он не закрывается в эмуляторе, а в устройстве камера закрывается, но я не получаю результат.

Я объявил, что это содержимое содержится в файле манифеста

  

Также я дал разрешение на запись внешнего хранилища, а также для использования камеры .

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

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

Если мы не предоставим дополнительные функции с намерением камеры, она вернет изображение в виде байта [] в результате действия в качестве дополнительных данных, но это предназначено для миниатюры, поэтому я не могу получить изображение с высоким разрешением, используя этот способ ,

Существует два способа решить эту проблему.

1. Сохраните bitmap, которое вы получили от метода onActivityResult

Вы можете запустить камеру с помощью намерения сделать снимок с помощью кода ниже

 Intent cameraIntent=new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(cameraIntent, CAMERA_REQUEST); 

После съемки фотографии вы получите bitmap в методе onActivityResult

 if (requestCode == CAMERA_REQUEST) { Bitmap photo = (Bitmap) data.getExtras().get("data"); } 

Теперь вы можете просто сохранить это bitmap во внутреннем хранилище

Примечание. Здесь растровый объект состоит из изображения большого пальца, он не будет иметь изображение с полным разрешением

2. Сохранить bitmap непосредственно во внутреннем хранилище с помощью поставщика контента

Здесь мы создадим class провайдера контента, чтобы разрешить разрешение локального каталога хранилища на активность камеры

Пример примера поставщика, как показано ниже

 public class MyFileContentProvider extends ContentProvider { public static final Uri CONTENT_URI = Uri.parse ("content://com.example.camerademo/"); private static final HashMap MIME_TYPES = new HashMap(); static { MIME_TYPES.put(".jpg", "image/jpeg"); MIME_TYPES.put(".jpeg", "image/jpeg"); } @Override public boolean onCreate() { try { File mFile = new File(getContext().getFilesDir(), "newImage.jpg"); if(!mFile.exists()) { mFile.createNewFile(); } getContext().getContentResolver().notifyChange(CONTENT_URI, null); return (true); } catch (Exception e) { e.printStackTrace(); return false; } } @Override public String getType(Uri uri) { String path = uri.toString(); for (String extension : MIME_TYPES.keySet()) { if (path.endsWith(extension)) { return (MIME_TYPES.get(extension)); } } return (null); } @Override public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { File f = new File(getContext().getFilesDir(), "newImage.jpg"); if (f.exists()) { return (ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_WRITE)); } throw new FileNotFoundException(uri.getPath()); } } 

После этого вы можете просто использовать URI для перехода к активности камеры, используя приведенный ниже код

 Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); i.putExtra(MediaStore.EXTRA_OUTPUT, MyFileContentProvider.CONTENT_URI); startActivityForResult(i, CAMERA_RESULT); 

Если вы не хотите создавать своего собственного провайдера, вы можете использовать FileProvider из support-library-v4. Для получения подробной справки вы можете изучить этот пост

Лучшее решение, которое я нашел, это: FileProvider (нуждается в поддержке-library-v4) Он использует внутреннее хранилище! https://developer.android.com/reference/android/support/v4/content/FileProvider.html

  1. Определите свой FileProvider в манифесте в элементе приложения:

        
  2. Добавить разрешения в явном корневом элементе:

       
  3. Определите пути изображения, например, res / xml / image_path.xml:

        
  4. Ява:

     private static final int IMAGE_REQUEST_CODE = 1; // your authority, must be the same as in your manifest file private static final String CAPTURE_IMAGE_FILE_PROVIDER = "your.package.name.fileprovider"; 

4.1. Удержание захвата:

  File path = new File(activity.getFilesDir(), "your/path"); if (!path.exists()) path.mkdirs(); File image = new File(path, "image.jpg"); Uri imageUri = FileProvider.getUriForFile(activity, CAPTURE_IMAGE_FILE_PROVIDER, image); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); startActivityForResult(intent, IMAGE_REQUEST_CODE); 

4.2 onActivityResult ():

  @Override public void onActivityResult(int requestCode, int resultCode, Intent intent) { if (requestCode == IMAGE_REQUEST_CODE) { if (resultCode == Activity.RESULT_OK) { File path = new File(getFilesDir(), "your/path"); if (!path.exists()) path.mkdirs(); File imageFile = new File(path, "image.jpg"); // use imageFile to open your image } } super.onActivityResult(requestCode, resultCode, intent); } 

Намерение вызвать фотосъемку,

 Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(cameraIntent, CAMERA_REQUEST); 

Затем выполните битмап в ActivityResult

  if (requestCode == CAMERA_REQUEST) { Bitmap photo = (Bitmap) data.getExtras().get("data"); } 

Затем запишите это во внутреннюю память, см. Это

 // The openfileOutput() method creates a file on the phone/internal storage in the context of your application final FileOutputStream fos = openFileOutput("my_new_image.jpg", Context.MODE_PRIVATE); // Use the compress method on the BitMap object to write image to the OutputStream bm.compress(CompressFormat.JPEG, 90, fos); 

Затем в следующий раз, чтобы прочитать этот файл,

 Bitmap bitmap = BitmapFactory.decodeFile(file); 

Сначала сохранить фотографию в вашем внешнем хранилище и попробовать –

 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); this.imageView = (ImageView)this.findViewById(R.id.imageView1); Button photoButton = (Button) this.findViewById(R.id.button1); photoButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(cameraIntent, CAMERA_REQUEST); } }); } protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == CAMERA_REQUEST) { Bitmap bmp = intent.getExtras().get("data"); ByteArrayOutputStream stream = new ByteArrayOutputStream(); bmp.compress(Bitmap.CompressFormat.PNG, 100, stream); byte[] byteArray = stream.toByteArray(); // convert camera photo to byte array // save it in your external storage. FileOutputStream fo = new FileOutputStream(new File(Environment.getExternalStorageDirectory() + "/_camera.png")); fo.write(byteArray); fo.flush(); fo.close(); } } 

Следующая цель –

 File cameraFile = new File(Environment.getExternalStorageDirectory() + "/_camera.png"); startActivityForResult(Intent.createChooser(new Intent(Intent.ACTION_SEND) .setType("image/jpg") .putExtra(Intent.EXTRA_SUBJECT, "Subject") .putExtra(Intent.EXTRA_STREAM, Uri.fromFile(cameraFile)) .putExtra(Intent.EXTRA_TEXT, textBody), "Send your message using"), Constant.EMAIL); 

Вы также можете сделать это, не требуя поставщика контента, так как вам понадобится SD-карта, чтобы в любом случае открыть цель захвата изображения. Конечно, вы можете взломать присутствие SD-карты, но не с захватом камеры. Поэтому вы проверяете внешнее хранилище, но нуждаетесь в этом в этот момент …. FYI вы также должны проверить библиотеку урожая, например crop-образ вместо использования native, так как он не поддерживается всеми устройствами.

 File mediaStorageDir; String photoFileName = "photo.jpg"; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // page = getArguments().getInt("someInt", 0); // title = getArguments().getString("someTitle"); // Get safe storage directory for photos mediaStorageDir = new File( Environment .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), APP_TAG); // Create the storage directory if it does not exist if (!mediaStorageDir.exists() && !mediaStorageDir.mkdirs()) { Log.d(APP_TAG, "Directory exists: " + mediaStorageDir.isDirectory()); Log.d(APP_TAG, "Directory exists: " + mediaStorageDir.getPath()); Log.d(APP_TAG, "Directory exists: " + Environment.getExternalStorageState()); Log.d(APP_TAG, "failed to create directory"); } } 

в коде «взять код»:

  Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, getPhotoFileUri(photoFileName)); 

 public Uri getPhotoFileUri(String fileName) { return Uri.fromFile(new File(mediaStorageDir.getPath() + File.separator + fileName)); } 

Изучив эту ошибку в течение некоторого времени, я заметил, что активность, называемая намерением камеры, перезапускается только тогда, когда на телефоне заканчивается память. поэтому, поскольку активность перезапускается, объект, удерживающий путь, или Uri для захваченного изображения обновляется (нулевается)

поэтому я предлагаю вам поймать / обнаружить нулевой объект в onActivityResult и попросить пользователя освободить место на своем устройстве или перезапустить свой телефон для быстрого временного исправления.

  • Активность kill / onCreate вызвана после съемки с помощью намерения
  • как установить ориентацию изображения камеры?
  • Как захватить изображение и сохранить его с помощью встроенной камеры Android
  • Android: BroadcastReceiver намерен обнаружить фотокамеру камеры?
  • Неисправность работы с камерой в onActivityResult
  • Давайте будем гением компьютера.