Sobes.tech
Middle

Como transmitir corretamente uma grande quantidade de dados, como uma imagem, entre atividades no Android?

sobes.tech IA

Resposta da IA

Não é recomendado transferir grandes volumes de dados, como imagens, diretamente através de Intent devido à limitação no tamanho dos dados transmitidos durante a serialização (normalmente alguns centenas de quilobytes ou megabytes). A transferência de dados demasiado grandes pode levar a uma TransactionTooLargeException.

Abordagens corretas:

  1. Guardar os dados num ficheiro e passar o caminho do ficheiro no Intent.

    • Guardar a imagem num ficheiro temporário.
    • Passar o URI ou caminho do ficheiro no Extra do intent.
    • A atividade receptora lê o ficheiro a partir do caminho recebido.
    // Guardar na primeira atividade
    val imageUri: Uri = saveImageToFile(bitmap) // Função para guardar o Bitmap num ficheiro e devolver Uri
    val intent = Intent(this, SecondActivity::class.java)
    intent.putExtra("image_uri", imageUri.toString())
    startActivity(intent)
    
    // Ler na segunda atividade
    val imageUriString = intent.getStringExtra("image_uri")
    if (imageUriString != null) {
        val imageUri = Uri.parse(imageUriString)
        val bitmap = loadImageFromFile(imageUri) // Função para carregar o Bitmap a partir do Uri
        imageView.setImageBitmap(bitmap)
    }
    
  2. Usar Singleton ou armazenamento global de dados.

    • Colocar os dados num objeto Singleton ou numa classe separada acessível de qualquer parte da aplicação.
    • Não é necessário passar nada entre atividades, basta aceder ao Singleton para obter os dados.
    // Objeto global, por exemplo, na classe Application ou num singleton separado
    object DataHolder {
        var bitmap: Bitmap? = null
    }
    
    // Na primeira atividade
    DataHolder.bitmap = bitmap
    
    // Na segunda atividade
    val bitmap = DataHolder.bitmap
    imageView.setImageBitmap(bitmap)
    DataHolder.bitmap = null // Limpeza após uso, se necessário
    

    É importante considerar o ciclo de vida da aplicação e da atividade, que pode ser recriada.

  3. Usar base de dados (Room) ou armazenamento de dados (por exemplo, SharedPreferences, embora não seja ideal para imagens).

    • Guardar a imagem (possivelmente em forma de array de bytes) na base de dados.
    • Passar o identificador do registo na base de dados através de Intent.
    • A atividade receptora lê a imagem da base de dados usando o identificador.
    // Guardar na primeira atividade (pseudocódigo para 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)
    
    // Ler na segunda atividade (pseudocódigo para 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. Usar ViewModel compartilhado no Navigation Component.

    • Se estiver usando o componente de navegação, pode usar um ViewModel comum ligado ao grafo de navegação ou à atividade.
    • Os dados são colocados no ViewModel de uma atividade e acessíveis em outra.
    // No ViewModel
    class SharedViewModel : ViewModel() {
        val imageBitmap = MutableLiveData<Bitmap>()
    }
    
    // Na primeira atividade (usando Navigation Component)
    private val sharedViewModel: SharedViewModel by activityViewModels() // ou por navGraphViewModels(R.id.nav_graph)
    sharedViewModel.imageBitmap.value = bitmap
    
    // Na segunda atividade
    private val sharedViewModel: SharedViewModel by activityViewModels() // ou por navGraphViewModels(R.id.nav_graph)
    sharedViewModel.imageBitmap.observe(viewLifecycleOwner) { bitmap ->
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap)
        }
    }
    

A escolha do método depende do cenário de uso, do tamanho dos dados e da complexidade da aplicação. Para imagens, guardar em ficheiro (e passar o URI) ou usar Singleton/ViewModel costuma ser as soluções mais adequadas e eficientes.