Sebelum KitKat (atau sebelum Galeri baru), Intent.ACTION_GET_CONTENT
URI yang dikembalikan seperti ini
konten: // media / eksternal / gambar / media / 3951.
Menggunakan ContentResolver
dan quering untuk
MediaStore.Images.Media.DATA
mengembalikan URL file.
Namun di KitKat Galeri mengembalikan URI (via "Terakhir") seperti ini:
konten: //com.android.providers.media.documents/document/image: 3951
Bagaimana saya menangani ini?
android
android-intent
android-gallery
android-contentresolver
Michael Greifeneder
sumber
sumber
Uri
harus dapat dibuka sebagai aliran melaluiContentResolver
. Saya sudah lama gugup dengan aplikasi yang menganggap bahwacontent://
Uri
yang mewakili file selalu dapat dikonversi menjadiFile
.InputStream
padaContentResolver
ke tempat yang telah ditentukan sebelumnya sehingga memiliki nama file yang dikenal. Namun, ini terdengar boros bagi saya. Ada saran lain?InputStream
lebih dari JNI? Sayangnya, tidak banyak opsi untuk Anda.InputStream
bukan file (yang hebat). Hanya pembacaan tag EXIF yang sedikit rumit dan memerlukan pustaka Drew Noakes . Terima kasih banyak untuk komentar Anda.Jawaban:
Coba ini:
Mungkin butuh
untuk
sumber
Ini tidak memerlukan izin khusus, dan berfungsi dengan Kerangka Akses Penyimpanan, serta
ContentProvider
pola tidak resmi (jalur file di_data
lapangan).Lihat versi terbaru dari metode ini di sini .
sumber
Authority: com.google.android.apps.docs.storage
danSegments: [document, acc=1;doc=667]
. Saya tidak yakin, tetapi anggap bahwadoc
nilainya adalahUri
ID yang dapat Anda tolak. Anda mungkin perlu izin untuk diatur sebagaimana terinci dalam "Otorisasi aplikasi Anda di Android" di sini: developers.google.com/drive/integrate-android-ui . Harap perbarui di sini jika Anda mengetahuinya._data
tidak akan berfungsi ketika ContentProvider tidak mendukungnya. Disarankan untuk mengikuti instruksi @CommonsWare dan tidak menggunakan path file lengkap lagi, karena itu bisa berupa file di Dropbox cloud, bukan file nyata.Punya masalah yang sama, mencoba solusi di atas tetapi meskipun itu bekerja secara umum, untuk beberapa alasan saya mendapatkan penolakan izin pada penyedia konten Uri untuk beberapa gambar meskipun saya memiliki
android.permission.MANAGE_DOCUMENTS
izin yang ditambahkan dengan benar.Pokoknya menemukan solusi lain yang memaksa membuka galeri gambar bukannya tampilan dokumen KITKAT dengan:
dan kemudian memuat gambar:
EDIT
ACTION_OPEN_DOCUMENT
mungkin mengharuskan Anda untuk tetap menggunakan flag izin dll dan umumnya menghasilkan Pengecualian Keamanan ...Solusi lain adalah dengan menggunakan
ACTION_GET_CONTENT
kombinasic.getContentResolver().openInputStream(selectedImageURI)
yang akan bekerja pada pra-KK dan KK. Kitkat akan menggunakan tampilan dokumen baru kemudian dan solusi ini akan bekerja dengan semua aplikasi seperti Foto, Galeri, File Explorer, Dropbox, Google Drive dll ...) tetapi ingat bahwa ketika menggunakan solusi ini Anda harus membuat gambar dionActivityResult()
dan menyimpannya di Kartu SD misalnya. Menciptakan gambar ini dari uri yang disimpan pada peluncuran aplikasi berikutnya akan membuat Pengecualian Keamanan pada penyelesai konten bahkan ketika Anda menambahkan bendera izin seperti yang dijelaskan dalam dokumen Google API (itulah yang terjadi ketika saya melakukan beberapa pengujian)Selain itu, Panduan API Pengembang Android menyarankan:
sumber
Intent.ACTION_GET_CONTENT
. Pokoknya saya menyimpanIntent.createChooser()
pembungkus pada yang baruIntent
, untuk membiarkan pengguna memilih aplikasi untuk browsing, dan bekerja seperti yang diharapkan. Adakah yang bisa melihat kekurangan untuk solusi ini?Seperti yang disebutkan Commonsware, Anda tidak boleh berasumsi, bahwa aliran yang Anda dapatkan dapat
ContentResolver
dikonversi menjadi file.Apa yang benar-benar harus Anda lakukan adalah membuka
InputStream
dariContentProvider
, lalu membuat Bitmap darinya. Dan itu bekerja pada versi 4.4 dan sebelumnya juga, tidak perlu refleksi.Tentu saja jika Anda menangani gambar besar, Anda harus memuatnya dengan tepat
inSampleSize
: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html . Tapi itu topik lain.sumber
Saya percaya tanggapan yang sudah diposting harus membuat orang pergi ke arah yang benar. Namun di sini adalah apa yang saya lakukan yang masuk akal untuk kode warisan yang saya perbarui. Kode lama menggunakan URI dari galeri untuk mengubah dan kemudian menyimpan gambar.
Sebelum 4.4 (dan google drive), URI akan terlihat seperti ini: konten: // media / eksternal / gambar / media / 41
Seperti yang dinyatakan dalam pertanyaan, mereka lebih sering terlihat seperti ini: content: //com.android.providers.media.documents/document/image: 3951
Karena saya membutuhkan kemampuan untuk menyimpan gambar dan tidak mengganggu kode yang sudah ada, saya hanya menyalin URI dari galeri ke folder data aplikasi. Kemudian berasal URI baru dari file gambar yang disimpan di folder data.
Inilah idenya:
Catatan - copyAndClose () hanya file I / O untuk menyalin InputStream ke FileOutputStream. Kode tidak diposkan.
sumber
Hanya ingin mengatakan bahwa jawaban ini brilian dan saya menggunakannya untuk waktu yang lama tanpa masalah. Tetapi beberapa waktu yang lalu saya menemukan masalah ketika DownloadsProvider mengembalikan URI dalam format
content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fdoc.pdf
dan karenanya aplikasi macetNumberFormatException
karena tidak mungkin untuk menguraikan segmen uri selama. Tetapiraw:
segmen mengandung uri langsung yang dapat digunakan untuk mengambil file yang direferensikan. Jadi saya telah memperbaikinya dengan menggantiisDownloadsDocument(uri)
if
konten dengan yang berikut:sumber
Saya telah menggabungkan beberapa jawaban menjadi satu solusi kerja yang dihasilkan dengan path file
Jenis mime tidak relevan untuk tujuan contoh.
Hasil penanganan
FilePickUtils
sumber
Pertanyaan
Cara mendapatkan jalur file aktual dari URI
Menjawab
Sepengetahuan saya, kita tidak perlu mendapatkan path file dari URI karena untuk sebagian besar kasus kita dapat langsung menggunakan URI untuk menyelesaikan pekerjaan kita (seperti 1. mendapatkan bitmap 2. Mengirim file ke server, dll. .)
1. Mengirim ke server
Kami dapat langsung mengirim file ke server hanya menggunakan URI.
Menggunakan URI kita bisa mendapatkan InputStream, yang dapat kita kirim langsung ke server menggunakan MultiPartEntity.
Contoh
2. Mendapatkan BitMap dari URI
Jika URI menunjuk ke gambar maka kita akan mendapatkan bitmap, kalau tidak null:
Komentar
Referensi
sumber
Pustaka Android ini menangani perubahan kasus dalam KitKat (termasuk versi yang lama - 2.1+):
https://github.com/iPaulPro/aFileChooser
Gunakan
String path = FileUtils.getPath(context, uri)
untuk mengonversi Uri yang dikembalikan ke string jalur yang dapat digunakan pada semua versi OS. Lihat lebih lanjut di sini: https://stackoverflow.com/a/20559175/860488sumber
Bagi mereka yang masih menggunakan kode @Paul Burke dengan Android SDK versi 23 dan lebih tinggi, jika proyek Anda menemui kesalahan dengan mengatakan bahwa Anda kehilangan EXTERNAL_PERMISSION, dan Anda sangat yakin telah menambahkan izin pengguna dalam file AndroidManifest.xml Anda. Itu karena Anda mungkin di Android API 23 atau lebih tinggi dan Google membuatnya perlu untuk menjamin izin lagi saat Anda melakukan tindakan untuk mengakses file dalam runtime.
Itu berarti: Jika versi SDK Anda adalah 23 atau di atas, Anda diminta izin BACA & MENULIS saat Anda memilih file gambar dan ingin tahu URI dari itu.
Dan berikut ini adalah kode saya, di samping solusi Paul Burke. Saya menambahkan kode ini dan proyek saya mulai berfungsi dengan baik.
Dan di aktivitas & fragmen tempat Anda meminta URI:
Dalam kasus saya, CompatUtils.java adalah tempat saya mendefinisikan metode memverifikasiStoragePermissions (sebagai tipe statis sehingga saya dapat memanggilnya dalam aktivitas lain).
Juga harus lebih masuk akal jika Anda membuat status if terlebih dahulu untuk melihat apakah versi SDK saat ini di atas 23 atau tidak sebelum Anda memanggil metode verifikasiStoragePermissions.
sumber
Jawaban ini dari m3n0R pada pertanyaan android dapatkan jalur nyata oleh Uri.getPath () dan saya mengklaim tidak ada kredit. Saya hanya berpikir bahwa orang yang belum menyelesaikan masalah ini belum dapat menggunakan ini.
sumber
cursor.getString(idx);
Silakan coba untuk menghindari menggunakan metode takePersistableUriPermission karena itu menimbulkan pengecualian runtime untuk saya. / ** * Pilih dari galeri. * /
OnActivity untuk hasil menangani data gambar:
@Override void yang dilindungi onActivityResult (int requestCode, int resultCode, Intent data) {
sumber
Jika ada yang tertarik, saya membuat versi Kotlin yang berfungsi untuk
ACTION_GET_CONTENT
:sumber
Saya sudah mencoba beberapa jawaban di sini, dan saya pikir saya punya solusi yang akan bekerja setiap waktu dan mengelola izin juga.
Ini didasarkan pada solusi pintar dari LEO. Posting ini harus berisi semua kode yang Anda perlukan untuk membuat ini berfungsi, dan itu harus bekerja pada ponsel dan versi Android apa pun;)
Untuk memiliki kemampuan untuk mengambil file dari kartu SD, Anda akan memerlukan ini di manifes Anda:
Konstanta:
Periksa izin dan luncurkanImagePick jika memungkinkan
Respons izin
Kelola respons izin
Luncurkan pengambilan gambar
Kelola respons Pilihan gambar
Itu semua orang; ini berfungsi untuk saya di semua telepon yang saya miliki.
sumber
Ini adalah retasan total, tapi inilah yang saya lakukan ...
Jadi saat bermain dengan menyiapkan DocumentsProvider , saya perhatikan bahwa kode sampel (dalam
getDocIdForFile
, sekitar baris 450) menghasilkan id unik untuk dokumen yang dipilih berdasarkan jalur (unik) file relatif terhadap akar yang ditentukan yang Anda berikan (yaitu, apa yang Anda setelmBaseDir
pada saluran 96).Jadi URI akhirnya terlihat seperti:
content://com.example.provider/document/root:path/to/the/file
Seperti yang dikatakan oleh docs, itu mengasumsikan hanya satu root (dalam kasus saya itu
Environment.getExternalStorageDirectory()
tetapi Anda dapat menggunakan tempat lain ... kemudian mengambil path file, mulai dari root, dan menjadikannya ID unik, mengawali "root:
". Jadi saya dapat menentukan lintasan dengan menghilangkan bagian"/document/root:
"dari uri.getPath (), membuat lintasan file yang sebenarnya dengan melakukan sesuatu seperti ini:Aku tahu. Ini memalukan, tetapi berhasil. Sekali lagi, ini bergantung pada Anda menggunakan penyedia dokumen Anda sendiri di aplikasi Anda untuk menghasilkan ID dokumen.
(Juga, ada cara yang lebih baik untuk membangun jalan yang tidak menganggap "/" adalah pemisah jalur, dll. Tapi Anda mendapatkan ide.)
sumber
file://
maksud dari pemetik file eksternal, Anda juga dapat memeriksa otoritas, seperti pada contoh di atas untuk memastikannya dari penyedia kustom Anda, dan jika demikian Anda bisa juga gunakan jalur untuk "memalsukan"file://
maksud baru menggunakan jalur yang Anda ekstrak, laluStartActivity()
dan biarkan aplikasi Anda mengambilnya. Saya tahu, mengerikan.Ini bekerja dengan baik untuk saya:
sumber
Membangun berdasarkan jawaban Paul Burke Saya menghadapi banyak masalah dalam menyelesaikan jalur URI kartu SD eksternal karena sebagian besar fungsi "built-in" yang disarankan mengembalikan jalur yang tidak dapat diselesaikan ke file.
Namun, ini adalah pendekatan saya tentang // TODO-nya menangani volume non-primer .
Catatan itu tergantung pada hierarki yang mungkin berbeda pada setiap produsen ponsel - Saya belum menguji semuanya (sejauh ini berfungsi dengan baik pada Xperia Z3 API 23 dan Samsung Galaxy A3 API 23).
Harap konfirmasi jika tidak berkinerja baik di tempat lain.
sumber
@paul burke jawaban berfungsi dengan baik untuk gambar kamera dan galeri untuk API level 19 ke atas, tetapi tidak berfungsi jika SDK minimum proyek Android Anda diatur di bawah 19, dan beberapa jawaban yang merujuk di atas tidak berfungsi untuk galeri dan kamera. Baiklah, saya telah memodifikasi kode @paul burke yang berfungsi untuk level API di bawah 19. Di bawah ini adalah kodenya.
sumber
Jawaban atas pertanyaan Anda adalah Anda harus memiliki izin. Ketikkan kode berikut dalam file manifes.xml Anda:
Itu bekerja untuk saya ...
sumber