Je ne sais pas pourquoi cela se produit, mais je ne parviens pas à sélectionner des images auprès du fournisseur Google Photos. Test sur l'API 27.
Si j'utilise:
2019-03-02 12:04:34.150 13217-13217/? W/ResourceType: For resource 0x7f02036c, entry index(876) is beyond type entryCount(468) 2019-03-02 12:04:34.151 13217-13217/? W/ResourceType: For resource 0x7f02036c, entry index(876) is beyond type entryCount(468) 2019-03-02 12:04:34.229 2907-16891/? W/MediaExtractor: FAILED to autodetect media content. 2019-03-02 12:04:34.569 10839-10839/? W/ResourceType: ResTable_typeSpec entry count inconsistent: given 468, previously 1330
Lorsque j'ouvre le fournisseur de photos et que je navigue dans les dossiers, j'en vois beaucoup:
2019-03-02 12:04:15.164 17641-13395/? W/NetworkManagementSocketTagger: untagSocket(120) failed with errno -22 2019-03-02 12:04:22.528 13217-13217/? E/ResourceType: Style contains key with bad entry: 0x01010586 2019-03-02 12:04:22.535 13217-13217/? W/ResourceType: For resource 0x7f020366, entry index(870) is beyond type entryCount(468)
Lorsque je clique sur l'image, je vois ceux-ci:
val intent = Intent(Intent.ACTION_GET_CONTENT) intent.addCategory(Intent.CATEGORY_OPENABLE) intent.type = "image/*"
Dans ce cas, je ne vois même pas Google Photos dans le tiroir des fournisseurs.
Comment puis-je résoudre ce problème, de préférence avec ACTION_GET_CONTENT?
4 Réponses :
Le ACTION_PICK vous donnera la possibilité de choisir l'image et vous pourrez obtenir le chemin du fichier
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Image.Media.EXTERNAL_CONTENT_URI); intent.setType("image/*"); Intent sIntent = new Intent("com.sec.android.app.myfiles.PICK_DATA"); sIntent.addCategory(Intent.CATEGORY_DEFAULT); sIntent.setType("image/*"); Intent chooserIntent; if (getPackageManager().resolveActivity(sIntent, 0) != null) { // it is device with samsung file manager chooserIntent = Intent.createChooser(sIntent, "Select file"); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[]{intent}); } else { chooserIntent = Intent.createChooser(intent, "Select file"); } try { startActivityForResult(chooserIntent, REQUEST_TAKE_GALLERY_VIDEO); } catch (android.content.ActivityNotFoundException ex) { Toast.makeText(getApplicationContext(), "No suitable File Manager was found.", Toast.LENGTH_SHORT).show(); }
Merci, mais je ne souhaite pas utiliser ACTION_PICK. J'ai besoin d'utiliser l'un des deux (obtenir le contenu / ouvrir le document).
EDIT 2
Je pense avoir trouvé la solution du problème. Il est mentionné dans les documents Google que l'accès à un le fichier partagé vous donnera l ' URI .
L'application serveur renvoie l'URI du contenu du fichier à l'application cliente dans une intention. Cette intention est transmise à l'application cliente dans sa substitution de onActivityResult (). Une fois que l'application cliente a l'URI du contenu du fichier, elle peut accéder au fichier en obtenant son FileDescriptor.
Voici le code mis à jour que j'utilise dans onActivityResult . Assurez-vous d'appeler enfin la méthode super de onActivityResult.
super.onActivityResult (requestCode, resultCode, données)
Code de travail
fun copyInputStreamToFile(`in`: InputStream, file: File) { var out: OutputStream? = null try { out = FileOutputStream(file) val buf = ByteArray(1024) var len: Int = 0 while (`in`.read(buf).apply { len = this } > 0) { out.write(buf, 0, len) } /*while (`in`.read(buf).let { len = it true }) { out.write(buf, 0, len) }*/ /* while ((len = `in`.read(buf)) > 0) { out.write(buf, 0, len) }*/ } catch (e: Exception) { e.printStackTrace() } finally { try { out?.close() } catch (e: Exception) { e.printStackTrace() } try { `in`.close() } catch (e: Exception) { e.printStackTrace() } } }
MODIFIER
Vérifiez également ceci article destackoverflow
Je l'utilise sur Android oreo 8.1.0 (API 27) sur mon téléphone Redmi 6 pro et cela fonctionne très bien.
Vous n'avez pas publié la méthode onActivityResult , c'est peut-être ici vous devez faire quelques modifications. Je l'ai essayé à la fois
Voici mon extrait de code
@Throws(IOException::class) private fun createImageFile(): File { // Create an image file name val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(Date()) val imageFileName = "yesqueen_" + timeStamp + "_" val storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) return File.createTempFile(imageFileName, ".jpg", storageDir) }
et dans onActivityResult je l'analyse comme ceci p>
if (data!!.data != null && data.data != null) { try { // CommonUtilities._Log(TAG, "Data Type " + data.getType()); if (!isFinishing) { val inputStream = contentResolver.openInputStream(data.data!!) val createFile = createImageFile() copyInputStreamToFile(inputStream!!, createFile) // CommonUtilities._Log(TAG, "File Path " + createFile.getAbsolutePath()); selectedImagePath = createFile.absolutePath } } catch (e: IOException) { util._log(TAG, Log.getStackTraceString(e)) } }
Méthode de création d'un nouveau fichier
val pickIntent = Intent(Intent.ACTION_VIEW) pickIntent.type = "image/*" pickIntent.action = Intent.ACTION_GET_CONTENT pickIntent.addCategory(Intent.CATEGORY_OPENABLE) startActivityForResult(pickIntent, SELECT_PICTURE)
Méthode de lecture à partir du flux d'entrée
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { data?.data?.let { util._log(TAG, it.toString()) } if (data!!.data != null && data.data != null) { try { val stream = if (data.data!!.toString().contains("com.google.android.apps.photos.contentprovider")) { val ff = contentResolver.openFileDescriptor(data.data!!, "r") FileInputStream(ff?.fileDescriptor) } else { contentResolver.openInputStream(data.data!!) } val createFile = createImageFile() util.copyInputStreamToFile(stream, createFile) selectedImagePath = createFile.absolutePath } catch (e: Exception) { util._log(TAG, Log.getStackTraceString(e)) } } super.onActivityResult(requestCode, resultCode, data) }
Merci, mais onActivityResult n'est jamais appelé car l'appareil ne retourne même pas à mon application. Il revient au sélecteur d'image système (celui avec le tiroir). Donc: application -> sélecteur système -> sélectionnez Google Photos -> choisissez une image -> retour au sélecteur.
Aviez-vous essayé comme dans ma réponse ??
@natario j'ai également joint un GIF qui montre que cela fonctionne :)
Vous avez utilisé les 3 mêmes lignes que dans ma question - ACTION_GET_CONTENT, CATEGORY_OPENABLE et "image / *", donc oui, j'ai essayé. Je pense aussi que ce sont corrects.
Je l'ai fait avec ce code.
fun bitmap(path : String) : Bitmap{ val image = File(path) val bmOptions = BitmapFactory.Options() return BitmapFactory.decodeFile(image.absolutePath, bmOptions) }
et pour résultat
fun generateBitmap(context: Context, uri: Uri): Bitmap? { var filePath = "" var cursor: Cursor? var columnIndex = 0 try { val column = arrayOf(MediaStore.Images.Media.DATA) val sel = arrayOf(MediaStore.Images.Media._ID + "=?") if (uri.toString().startsWith("content://com.google.android.apps.photos.contentprovider")){ val content = this.contentResolver.openInputStream(uri) ?: return null val pictureBitmap = BitmapFactory.decodeStream(content) return pictureBitmap } else { filePath = "" if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { val wholeID = DocumentsContract.getDocumentId(uri) val id = arrayOf(wholeID.split(":")[1]) cursor = context.contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, column, sel[0], id, null) columnIndex = cursor.getColumnIndex(column[0]) if (cursor.moveToFirst()) { filePath = cursor.getString(columnIndex) } cursor.close() } else { val cursorLoader = CursorLoader(context, uri, column, null, null, null) val cursor = cursorLoader.loadInBackground() if (cursor != null) { var column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA) cursor.moveToFirst() filePath = cursor.getString(column_index) } } //TODO generate bitmap from file path return bitmap(filePath) } } catch (e: Exception) { print(e.message) } return null }
generateBitmap (context, uri)
méthode dans Kotlin
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) when (requestCode) { 100 -> { if (resultCode == Activity.RESULT_OK) { val bitmap = generateBitmap(this,data!!.data) //TODO show bitmap to your View showPicture(bitmap!!) } } } }
pour getBitmap à partir du chemin du fichier J'ai utilisé cette méthode
val intent = Intent(Intent.ACTION_GET_CONTENT) intent.addCategory(Intent.CATEGORY_OPENABLE) intent.type = "image/*" startActivityForResult(intent,100)
@natario J'ai changé une partie de la réponse, j'espère que cela résoudra votre problème
J'ai eu le même problème, je n'ai pas pu obtenir l'URI d'image de Google Photos avec une intention ACTION_GET_CONTENT
. Le problème était lié au launchMode
de mon activité. Je n'ai trouvé aucune référence aux documentations Android. mais de cette façon, le problème est complètement résolu:
Je n'avais qu'une seule application d'activité et mon intention ACTION_GET_CONTENT
ressemblait à ceci:
gallery.setOnClickListener { startActivityForResult( Intent(requireActivity(), ImagePickerActivity::class.java), GALLERY_RESULT ) }
le problème était le mode de lancement singleInstance
dans la définition de l'activité dans AndroidManifest.xml.
class ImagePickerActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val intent = Intent(Intent.ACTION_GET_CONTENT).apply { type = "image/*" } if (intent.resolveActivity(packageManager!!) != null) { startActivityForResult(intent, GALLERY_RESULT) } else { Toast.makeText( this, "No Gallery APP installed", Toast.LENGTH_LONG ).show() finish() } } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) //here data is resulted URI from ACTION_GET_CONTENT //and we pass it to our MainActivy using setResult setResult(resultCode, data) finish() } }
En supprimant la ligne android: launchMode, le problème a été résolu. Si votre activité doit être singleInstance
, créer une activité factice sera une bonne solution. ici, vous pouvez démarrer une activité factice pour le résultat, puis effectuer vos tâches d'intention dans son onCreate
, puis setResult ()
pour votre activité demandée:
<activity android:name=".ui.MainActivity" android:configChanges="orientation" android:launchMode="singleInstance" android:screenOrientation="portrait" android:theme="@style/AppTheme" android:windowSoftInputMode="adjustResize|stateHidden"/>
et voici votre code dans votre MainActivity:
val intent = Intent(Intent.ACTION_GET_CONTENT).apply { type = "image/*" } startActivityForResult(intent, GALLERY_RESULT)
Essayez avec
ACTION_PICK
Merci mais je dois utiliser l'un de ces deux et j'aimerais savoir pourquoi cela ne fonctionne pas.
@natario quel appareil vous utilisez?!
@Rahul Nexus 5X, api 27
@natario Le testez-vous sur un émulateur? ou le vrai appareil
@natario Vérifiez également ce lien
C'est un vrai appareil, un Nexus 5X.
Peut-être que c'est un bug. Mais je l'ai testé sur l'émulateur Nexus 5X API 27. qui est identique à votre appareil. Et le code fonctionne également très bien ici. P.S. Rechercher des mises à jour
@natario vérifie ma réponse mise à jour. et faites-moi savoir si vous avez besoin d'explications.
@Rahul onActivityResult n'est jamais appelé car le flux ne retourne pas dans mon application, il reste dans le sélecteur comme je l'ai dit.
@natario je me demande ce qui fait que cela ne fonctionne pas pour vous sur un appareil réel mais sur un émulateur.
@RahulKhurana J'ai vérifié ce code sur le téléphone avec le même modèle que le vôtre et cela fonctionne sans aucun problème. vous acier avez ce problème.
@Alishatergholi OP est confronté à ce problème. J'essaye juste de le résoudre de toute façon
@RahulKhurana s'il vous plaît vérifier mon code, cela fonctionne bien sur Nexus 5X.
@Alishatergholi Ok. Je vais
Je comprends que cela fonctionne pour vous, mais ce n'est toujours pas le cas pour moi.