Как получить результат камеры в виде 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);
и этот код используется для получения изображения в папку data
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);
Я знал, что папка данных недоступна для третьего приложения так может быть это вызывает проблему, поэтому я должен создать один контент-провайдер, чтобы поделиться файлом.
вот мой контент предоставить класс
public class MyContentProvider extends ContentProvider {
private static final String Tag = RingtonContentProvider.class.getName();
public static final Uri CONTENT_URI = Uri
.parse("content://x.y.z/");
private static final HashMap<String, String> MIME_TYPES = new HashMap<String, String>();
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-адрес другой, чем внешний каталог хранения, камера открывается, но она не закрывается в эмуляторе, но в устройстве камера будет закрыта, но я не получаю результат.
я объявил этот контент предоставить в файле манифеста
<provider
android:name=".contentproviders.MyContentProvider"
android:authorities="x.y.z" />
также я дал разрешение запишите внешнее хранилище, а также ибо использование камеры.
Я могу захватить изображение с помощью внешнего хранилища, но я хочу сохранить изображение в каталоге данных вместо внешнего хранилища, потому что если внешнее хранилище недоступно, я хочу захватить изображение и хочу отправить почту.
если я создаю контент, то я также могу поделиться своим изображением с приложением электронной почты.
если мы не предоставляем дополнительные услуги с намерением камеры он вернет изображение в виде байта[] в результате действия в качестве дополнительных данных, но это для целей миниатюры, поэтому я не могу получить изображение с высоким разрешением, используя этот способ.
6 ответов:
есть два способа решить эту проблему.
1. Сохранить растровое изображение, которое вы получили от метода onActivityResult
вы можете запустить камеру через намерение, чтобы захватить фотографию, используя ниже код
Intent cameraIntent=new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(cameraIntent, CAMERA_REQUEST);
после захвата фото, вы получите растровое изображение в методе onActivityResult
if (requestCode == CAMERA_REQUEST) { Bitmap photo = (Bitmap) data.getExtras().get("data"); }
теперь вы можете просто сохранить это растровое изображение во внутренней памяти
Примечание: здесь растровый объект состоит из изображения пальца, он будет не имеют полного разрешения изображения
2. Сохраните растровое изображение непосредственно во внутреннюю память с помощью content provider
здесь мы создадим класс контент-провайдера, чтобы разрешить разрешение локального каталога хранения на активность камеры
пример поставщика пример согласно ниже
public class MyFileContentProvider extends ContentProvider { public static final Uri CONTENT_URI = Uri.parse ("content://com.example.camerademo/"); private static final HashMap<String, String> MIME_TYPES = new HashMap<String, String>(); 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 (требуется поддержка-библиотека-v4) Он использует внутреннюю память! https://developer.android.com/reference/android/support/v4/content/FileProvider.html
Определите ваш FileProvider в манифесте в элементе приложения:
<provider android:name="android.support.v4.content.FileProvider" android:authorities="your.package.name.fileprovider" android:exported="false" android:grantUriPermissions="true" > <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/image_path" /> </provider>
добавить разрешения в корневой элемент манифеста:
<uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" android:required="false" />
определите ваши пути изображения в например res / xml / image_path.XML-код:
<paths xmlns:android="http://schemas.android.com/apk/res/android"> <files-path name="captured_image" path="your/path/"/> </paths>
Java:
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-карты, но не с намерением камеры capture....So вы проверяете наличие внешнего хранилища, но он нужен на данный момент.... FYI вы также должны проверить библиотеку культур, такую как crop-image, вместо использования 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 и предложить пользователю освободить место на своем устройстве или перезагрузить телефон для быстрого временного исправления.