Sobes.tech
Middle

Ako správne preniesť veľké množstvo údajov, napríklad obrázok, medzi aktivitami v Android?

sobes.tech AI

Odpoveď od AI

Prenos veľkého objemu dát, ako je obrázok, priamo cez Intent sa neodporúča kvôli obmedzeniu veľkosti dát prenášaných pri serializácii (zvyčajne niekoľko stoviek kilobajtov alebo megabajtov). Prenos príliš veľkých dát môže viesť k TransactionTooLargeException.

Správne prístupy:

  1. Uložiť dáta do súboru a odovzdať cestu k súboru v Intent.

    • Uložíme obrázok do dočasného súboru.
    • Odovzdáme URI alebo cestu k súboru v Extra intentu.
    • Prijímajúca aktivita načíta súbor podľa získanej cesty.
    // Uloženie v prvej aktivite
    val imageUri: Uri = saveImageToFile(bitmap) // Funkcia na uloženie Bitmap do súboru a vrátenie Uri
    val intent = Intent(this, SecondActivity::class.java)
    intent.putExtra("image_uri", imageUri.toString())
    startActivity(intent)
    
    // Čítanie v druhej aktivite
    val imageUriString = intent.getStringExtra("image_uri")
    if (imageUriString != null) {
        val imageUri = Uri.parse(imageUriString)
        val bitmap = loadImageFromFile(imageUri) // Funkcia na načítanie Bitmap z Uri
        imageView.setImageBitmap(bitmap)
    }
    
  2. Použiť Singleton alebo globálne úložisko dát.

    • Uložíme dáta do Singleton-objektu alebo samostatnej triedy, ktorá je dostupná z ktorejkoľvek časti aplikácie.
    • Pri prenose medzi aktivitami nie je potrebné nič odovzdávať, stačí sa odvolať na Singleton na získanie dát.
    // Globálny objekt, napríklad v triede Application alebo samostatný singleton
    object DataHolder {
        var bitmap: Bitmap? = null
    }
    
    // V prvej aktivite
    DataHolder.bitmap = bitmap
    
    // V druhej aktivite
    val bitmap = DataHolder.bitmap
    imageView.setImageBitmap(bitmap)
    DataHolder.bitmap = null // Vyčistenie po použití, ak je potrebné
    

    Je potrebné brať do úvahy životný cyklus aplikácie a aktivitu, ktorá môže byť znovu vytvorená.

  3. Použiť databázu (Room) alebo úložisko dát (napríklad SharedPreferences, hoci pre obrázky nie je ideálne).

    • Uložiť obrázok (možno vo forme byte poľa) do databázy.
    • Odovzdať identifikátor záznamu v databáze cez Intent.
    • Prijímajúca aktivita načíta obrázok z databázy podľa identifikátora.
    // Uloženie v prvej aktivite (pseudokód pre 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)
    
    // Čítanie v druhej aktivite (pseudokód pre 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. Použiť Shared ViewModel v Navigation Component.

    • Ak sa používa komponent navigácie (Navigation Component), môžete použiť spoločnú ViewModel, ktorá je viazaná na navigačný graf alebo aktivitu.
    • Dáta sa ukladajú do ViewModel jednej aktivity a sú dostupné druhej.
    // Vo ViewModel
    class SharedViewModel : ViewModel() {
        val imageBitmap = MutableLiveData<Bitmap>()
    }
    
    // V prvej aktivite (pri použití Navigation Component)
    private val sharedViewModel: SharedViewModel by activityViewModels() // alebo by navGraphViewModels(R.id.nav_graph)
    sharedViewModel.imageBitmap.value = bitmap
    
    // V druhej aktivite
    private val sharedViewModel: SharedViewModel by activityViewModels() // alebo by navGraphViewModels(R.id.nav_graph)
    sharedViewModel.imageBitmap.observe(viewLifecycleOwner) { bitmap ->
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap)
        }
    }
    

Výber metódy závisí od scenára použitia, veľkosti dát a zložitosti aplikácie. Pre obrázky je najčastejšie vhodné uloženie do súboru (a odovzdanie URI) alebo použitie Singleton/ViewModel, ktoré sú najefektívnejšie riešenia.