Jak uzyskać wynik kamery jako uri w folderze danych?


Tworzę aplikację, w której chcę przechwycić obraz, a następnie chcę wysłać ten obraz w wiadomości e-mail jako załącznik.
Otwieram aparat za pomocą akcji intencyjnej
android.provider.MediaStore.ACTION_IMAGE_CAPTURE
i przekazuję plik Uri jako parametr
EXTRA_OUTPUT
, aby uzyskać obraz z powrotem do pliku. To działa dobrze i mogę uzyskać przechwycony obraz, jeśli używam
zewnętrznej pamięci masowej
, na przykład
EXTRA_OUTPUT
, ale jeśli używam folderu uri danych, nie działa, a aparat nie działa nie zamyka się i wszystkie jego przyciski nie działają.
Oto mój kod do pobrania wyniku w katalogu magazynu zewnętrznego
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);

Ten kod służy do pobierania obrazu w folderze danych
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);

wiedziałem to

folder danych nie jest dostępny dla trzeciej aplikacji

więc może to jest przyczyną problemu, więc muszę utworzyć jednego dostawcę zawartości, aby udostępnić plik.
Oto moje zasoby zapewniające najlepsze w swojej klasie
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); }
}

Dlatego, aby użyć tej zawartości, używam następującego kodu, aby przekazać URI do akcji kamery
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);

Teraz jak przekażę url do innego, nie zewnętrznego katalogu pamięci, to aparat otworzy się ale nie zamknie w emulatorze, ale w urządzeniu aparat się zamknie, ale wyniku nie dostanę.
Zadeklarowałem tę treść w moim pliku manifestu
<provider
android:name=".contentproviders.MyContentProvider"
android:authorities="x.y.z"/>

Również dałem pozwolenie

zapis w pamięci zewnętrznej

jak również

użycie aparatu

.
Mogę przechwycić obraz przy użyciu pamięci zewnętrznej, ale chcę przechowywać obraz w katalogu danych zamiast w pamięci zewnętrznej, ponieważ jeśli nie jest dostępna pamięć zewnętrzna, chcę przechwycić obraz i wysłać pocztę.
Jeśli tworzę treść, mogę również udostępnić mój obraz z załącznikiem do wiadomości e-mail.

Jeśli nie dostarczymy dodatków z intencją kamery, zwróci obraz jako bajt [] w wyniku działania jako dodatkowe dane, ale jest to zrobione dla miniatury, więc nie mogę uzyskać wysokiej rozdzielczości obraz w ten sposób.

Zaproszony:
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Istnieją dwa sposoby rozwiązania tego problemu.

1. zapisz bitmapę otrzymaną z metody

onActivityResult
Możesz uruchomić aparat, chcąc zrobić zdjęcie, używając poniższego kodu
Intent cameraIntent=new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, CAMERA_REQUEST);

Po zrobieniu zdjęcia otrzymasz mapę bitową w metodzie onActivityResult
if (requestCode == CAMERA_REQUEST) { 
Bitmap photo = (Bitmap) data.getExtras().get("data");
}

Teraz możesz po prostu zapisać tę bitmapę w pamięci wewnętrznej

Uwaga: tutaj obiekt bitmapowy składa się z obrazu kciuka, nie będzie miał obrazu w pełnej rozdzielczości


2. Zapisz mapę bitową bezpośrednio w pamięci wewnętrznej za pomocą dostawcy zawartości

Tutaj utworzymy klasę dostawcy treści, aby umożliwić lokalnemu katalogowi pamięci dostęp do aktywności kamery
Przykład takiego dostawcy wg poniżej
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());
}
}

Następnie możesz po prostu użyć URI, aby przejść do aktywności kamery, używając poniższego kodu
Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
i.putExtra(MediaStore.EXTRA_OUTPUT, MyFileContentProvider.CONTENT_URI);
startActivityForResult(i, CAMERA_RESULT);

Jeśli nie chcesz tworzyć własnego dostawcy, możesz użyć

FileProvider
https://developer.android.com/ ... .html
z biblioteki-wsparcia-v4. Aby uzyskać szczegółowe informacje, możesz spojrzeć na

ten post
https://coderoad.ru/10042695/
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Najlepsze rozwiązanie jakie znalazłem to: FileProvider (potrzebujesz support-library-v4)
Wykorzystuje pamięć wewnętrzną!

https:// developer.android.com/link/android/support/v4/content/FileProvider.html
https://developer.android.com/ ... .html
  • Zdefiniuj swój FileProvider w swoim manifeście w elemencie aplikacji:
    <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>
  • Dodawanie uprawnień do elementu głównego manifestu:
    <uses-permission android:name="android.permission.CAMERA"/><uses-feature android:name="android.hardware.camera" android:required="false"/>
  • Zdefiniuj ścieżki do obrazów, na przykład w res/xml/image_path.xml:
    <paths xmlns:android="[url=http://schemas.android.com/apk/res/android">]http://schemas.android.com/apk ... gt%3B[/url]<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 Zamiar przechwytywania:
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);
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Zamiar wezwania do zrobienia zdjęcia
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); 
startActivityForResult(cameraIntent, CAMERA_REQUEST);

Następnie weź Bitmapę w
ActivityResult
if (requestCode == CAMERA_REQUEST) { 
Bitmap photo = (Bitmap) data.getExtras().get("data");
}

Następnie napisz

to jest w pamięci wewnętrznej, zobacz
https://coderoad.ru/4135927/
// 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);

Następnie następnym razem przeczytaj ten plik,
Bitmap bitmap = BitmapFactory.decodeFile(file);
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Najpierw zapisz zdjęcie w pamięci zewnętrznej i wypróbuj -
@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();
}
}

Następnym celem jest
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);
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Możesz to również zrobić bez korzystania z dostawcy treści, ponieważ nadal będziesz potrzebować karty SD, aby otworzyć intencję przechwytywania kamery. Możesz oczywiście zhakować obecność karty SD, ale nie z zamiarem przechwytywania przez kamerę .... Więc sprawdzasz obecność pamięci zewnętrznej, ale w tej chwili jej potrzebujesz .... Do Twojej wiadomości powinieneś także sprawdź bibliotekę kadrowania, taką jak crop -image, zamiast używać natywnej, ponieważ nie jest dobrze obsługiwana na różnych urządzeniach.
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");
}}

w swoim możesz wziąć kod pozycji:
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));
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Po zbadaniu tego błędu przez jakiś czas zauważyłem, że akcja, która wyzwoliła intencję aparatu, uruchamia się ponownie tylko wtedy, gdy w telefonie zabraknie pamięci.
w ten sposób, po ponownym uruchomieniu działania, obiekt zawierający ścieżkę lub Uri do przechwyconego obrazu jest aktualizowany (anulowany)
więc sugeruję, abyś złapał/wykrył obiekt zerowy w onActivityResult i poprosił użytkownika o zwolnienie miejsca na urządzeniu lub ponowne uruchomienie telefonu w celu szybkiej tymczasowej naprawy.

Aby odpowiedzieć na pytania, Zaloguj się lub Zarejestruj się