android - programacion - ¿Cómo obtener el resultado de la cámara como un uri en la carpeta de datos?
manual de android en pdf (6)
Estoy creando una aplicación en la que quiero capturar una imagen y luego deseo enviar esa imagen en el correo electrónico como un archivo adjunto.
Estoy abriendo una cámara con android.provider.MediaStore.ACTION_IMAGE_CAPTURE
acción de intención y estoy pasando el Uri del archivo como un parámetro EXTRA_OUTPUT
para devolver la imagen al archivo. Esto funciona perfectamente y puedo obtener la imagen capturada si utilizo el external storage uri
como EXTRA_OUTPUT
pero si utilizo la carpeta de datos uri no está funcionando y la cámara no se está cerrando y sus botones no funcionan.
Aquí está mi código para obtener el resultado en el directorio de almacenamiento externo
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);
Y este código es para obtener la imagen en la carpeta de datos
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);
Sabía que la tercera aplicación no puede acceder a la carpeta de datos, por lo que puede haber un problema así que tengo que crear un proveedor de contenido para compartir el archivo.
Aquí está mi contenido proporcionar clase
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);
}
}
Entonces, para usar este contenido, estoy usando el siguiente código para pasar el uri a la actividad de la cámara
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);
Ahora si paso la url otro directorio de almacenamiento externo la cámara se está abriendo pero no se está cerrando en el emulador pero en el dispositivo la cámara se cerrará pero no obtendré el resultado.
He declarado este contenido en el archivo de manifiesto
<provider
android:name=".contentproviders.MyContentProvider"
android:authorities="x.y.z" />
También he dado permiso para escribir el almacenamiento externo y también para usar la cámara .
Puedo capturar la imagen usando el almacenamiento externo, pero quiero almacenar la imagen en el directorio de datos en lugar de almacenamiento externo porque si el almacenamiento externo no está disponible, quiero capturar la imagen y enviar mensajes.
Si creo contenido, también puedo compartir mi imagen en la aplicación de correo electrónico.
Si no proporcionamos los extras con la intención de la cámara, devolverá la imagen como un byte [] en el resultado de la actividad como un extra de datos, pero esto es para la miniatura, por lo que no puedo obtener la imagen de alta resolución de esta manera. .
Al principio, guarde la foto en su almacenamiento externo y pruébelo.
@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();
}
}
Siguiente objetivo -
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);
Después de investigar este error por un tiempo, me di cuenta de que la actividad que llamaba la intención de la cámara solo se reinicia cuando el teléfono se está quedando sin memoria. así que debido a que la actividad se reinicia, el objeto que contiene la ruta o Uri a la imagen capturada se actualiza (nulled)
por lo que le sugiero que capture / detecte el objeto nulo en onActivityResult, y le pida al usuario que libere espacio en su dispositivo o que reinicie su teléfono para una solución temporal rápida.
Hay dos formas de resolver este problema.
1. Guarde el mapa de bits que recibió del método OnActivityResult
Puede iniciar la cámara a través de la intención de capturar fotos usando el código siguiente
Intent cameraIntent=new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, CAMERA_REQUEST);
Después de la foto de captura, obtendrás un mapa de bits en el método de respuesta de actividad
if (requestCode == CAMERA_REQUEST) {
Bitmap photo = (Bitmap) data.getExtras().get("data");
}
Ahora puedes simplemente guardar este mapa de bits en el almacenamiento interno
Nota: Aquí el objeto de mapa de bits consiste en una imagen de pulgar, no tendrá una imagen de resolución completa
2. Guarde el mapa de bits directamente en el almacenamiento interno usando el proveedor de contenido
Aquí crearemos una clase de proveedor de contenido para permitir el permiso del directorio de almacenamiento local a la actividad de la cámara
Ejemplo de proveedor de muestra como por debajo
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());
}
}
Después de eso, simplemente puede usar el URI para pasar a la actividad de la cámara utilizando el siguiente código
Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
i.putExtra(MediaStore.EXTRA_OUTPUT, MyFileContentProvider.CONTENT_URI);
startActivityForResult(i, CAMERA_RESULT);
Si no desea crear su propio proveedor, puede usar FileProvider desde support-library-v4. Para obtener ayuda detallada, puede consultar esta publicación
Intención de llamar para capturar una foto,
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, CAMERA_REQUEST);
A continuación, tome Bitmap en ActivityResult
if (requestCode == CAMERA_REQUEST) {
Bitmap photo = (Bitmap) data.getExtras().get("data");
}
Luego, escribe eso en la memoria interna, mira esto
// 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);
Luego, la próxima vez para leer ese archivo,
Bitmap bitmap = BitmapFactory.decodeFile(file);
La mejor solución que encontré es: FileProvider (necesita soporte-biblioteca-v4) ¡Utiliza el almacenamiento interno! FileProvider
Defina su FileProvider en Manifiesto en el elemento Aplicación:
<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>
Agregar permisos en el elemento raíz del manifiesto:
<uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" android:required="false" />
Defina sus rutas de imagen en, por ejemplo, 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 intento de captura:
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);
}
También puede hacer esto sin necesidad de un proveedor de contenido ya que necesitará la tarjeta sd para abrir el intento de captura de imagen de la cámara de todos modos. Por supuesto, puede piratear la presencia de la tarjeta sd pero no con la captura de la intención de la cámara ... Por lo tanto, está buscando almacenamiento externo pero lo necesita en este punto ... FYI también debería consultar una biblioteca de cultivos como crop-image en lugar de utilizar native, ya que no es compatible con todos los dispositivos.
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");
}
}
en su código ''tomar la foto'':
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));
}