Sobes.tech
Middle

Comment transmettre correctement une grande quantité de données, comme une image, entre les activités dans Android?

sobes.tech IA

Réponse de l'IA

Il n’est pas recommandé de transférer directement de grandes volumes de données, comme des images, via Intent en raison de la limite de taille des données sérialisées (généralement quelques centaines de kilo-octets ou mégaoctets). Le transfert de données trop volumineuses peut entraîner une TransactionTooLargeException.

Approches correctes :

  1. Enregistrer les données dans un fichier et transmettre le chemin du fichier dans Intent.

    • Enregistrer l’image dans un fichier temporaire.
    • Transmettre l’URI ou le chemin du fichier dans l’Extra de l’intent.
    • L’activité réceptrice lit le fichier à partir du chemin reçu.
    // Enregistrer dans la première activité
    val imageUri: Uri = saveImageToFile(bitmap) // Fonction pour sauvegarder le Bitmap dans un fichier et retourner l’Uri
    val intent = Intent(this, SecondActivity::class.java)
    intent.putExtra("image_uri", imageUri.toString())
    startActivity(intent)
    
    // Lire dans la deuxième activité
    val imageUriString = intent.getStringExtra("image_uri")
    if (imageUriString != null) {
        val imageUri = Uri.parse(imageUriString)
        val bitmap = loadImageFromFile(imageUri) // Fonction pour charger le Bitmap depuis l’Uri
        imageView.setImageBitmap(bitmap)
    }
    
  2. Utiliser un Singleton ou un stockage global de données.

    • Placer les données dans un objet Singleton ou dans une classe séparée accessible depuis n’importe quelle partie de l’application.
    • Il n’est pas nécessaire de passer quoi que ce soit entre les activités, il suffit d’accéder au Singleton pour obtenir les données.
    // Objet global, par exemple dans la classe Application ou dans un singleton séparé
    object DataHolder {
        var bitmap: Bitmap? = null
    }
    
    // Dans la première activité
    DataHolder.bitmap = bitmap
    
    // Dans la deuxième activité
    val bitmap = DataHolder.bitmap
    imageView.setImageBitmap(bitmap)
    DataHolder.bitmap = null // Nettoyage après utilisation, si nécessaire
    

    Il faut prendre en compte le cycle de vie de l’application et de l’activité, qui peut être recréée.

  3. Utiliser une base de données (Room) ou un stockage de données (par exemple, SharedPreferences, bien que ce ne soit pas idéal pour les images).

    • Enregistrer l’image (peut-être sous forme de tableau d’octets) dans la base de données.
    • Transmettre l’identifiant de l’enregistrement dans la base de données via Intent.
    • L’activité réceptrice lit l’image depuis la base de données en utilisant l’identifiant.
    // Enregistrement dans la première activité (pseudocode pour Room)
    val imageEntity = ImageEntity(imageData = bitmapToByteArray(bitmap))
    val imageId = imageDatabase.imageDao().insertImage(imageEntity)
    val intent = Intent(this, SecondActivity::class.java)
    intent.putExtra("image_id", imageId)
    startActivity(intent)
    
    // Lecture dans la deuxième activité (pseudocode pour Room)
    val imageId = intent.getLongExtra("image_id", -1)
    if (imageId != -1L) {
        val imageEntity = imageDatabase.imageDao().getImageById(imageId)
        if (imageEntity != null) {
            val bitmap = byteArrayToBitmap(imageEntity.imageData)
            imageView.setImageBitmap(bitmap)
        }
    }
    
  4. Utiliser un ViewModel partagé dans le composant de navigation.

    • Si le composant de navigation est utilisé, on peut utiliser un ViewModel commun lié au graphe de navigation ou à l’activité.
    • Les données sont placées dans le ViewModel d’une activité et accessibles dans une autre.
    // Dans le ViewModel
    class SharedViewModel : ViewModel() {
        val imageBitmap = MutableLiveData<Bitmap>()
    }
    
    // Dans la première activité (avec Navigation Component)
    private val sharedViewModel: SharedViewModel by activityViewModels() // ou par navGraphViewModels(R.id.nav_graph)
    sharedViewModel.imageBitmap.value = bitmap
    
    // Dans la deuxième activité
    private val sharedViewModel: SharedViewModel by activityViewModels() // ou par navGraphViewModels(R.id.nav_graph)
    sharedViewModel.imageBitmap.observe(viewLifecycleOwner) { bitmap ->
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap)
        }
    }
    

Le choix de la méthode dépend du scénario d’utilisation, de la taille des données et de la complexité de l’application. Pour les images, l’enregistrement dans un fichier (et la transmission de l’URI) ou l’utilisation d’un Singleton/ViewModel sont généralement les solutions les plus appropriées et efficaces.