3

I need to pass a Bitmap between activities without write the image in the internal/external memory.

An Intent can't carry that size so the best option that I found is to use a Singleton Bitmap or extend Livedata and use it as singleton. (I'm not that good with architecture so if you have a better solution...)

I'm trying to implement the LiveData option since the livedata observer will be useful and I'm following the official documentation:

class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
private val stockManager: StockManager = StockManager(symbol)

private val listener = { price: BigDecimal ->
    value = price
}

override fun onActive() {
    stockManager.requestPriceUpdates(listener)
}

override fun onInactive() {
    stockManager.removeUpdates(listener)
}

companion object {
    private lateinit var sInstance: StockLiveData

    @MainThread
    fun get(symbol: String): StockLiveData {
        sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol)
        return sInstance
    }
}

}

But I really don't understand the logic:

  • What's the listener will be used for?
  • What's the class StockManager?
  • If I need it only for a Bitmap do I need to use onActive() and onInactive() too?

I couldn't find a different implementation example anywhere, how can I implement that only for a Bitmap?

------------ UPDATE for the Sanlok Lee answer ----------------

I tried to implement your class BitmapCache example:

In my first activity I attach the observer

    companion object {
         val myCache = BitmapCache()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.mylayout)

        myCache.getCachedBitmap().observe(this, Observer<Bitmap> { selfie: Bitmap? ->
        Log.i(TAG, "TRIGGERED")
    })

And in my second Activity I set the value like that:

    companion object {
        val myCache = BitmapCache()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.mylayout)

        val bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.android)

        Handler().postDelayed({
            myCache.cacheBitmap(bitmap)
        }, 3000)
}

But the observer is never triggered, are you sure I can create a Live data singleton like that? Thank you!

GMX
  • 950
  • 1
  • 14
  • 29

1 Answers1

2

StockManager in the example is just a random custom class they made just for example purpose.

Just to give you a simpler example that uses a more familiar component, let's imagine that you need to create a custom LiveData that count (and emit the count) the number of user button press while the LiveData is active. It can look like this:

class ButtonClickLiveData(val button: Button) : LiveData<Int>() {

    var clickCount = 0

    private val listener = { v: View ->
        clickCount++
        value = clickCount
    }

    override fun onActive() {
        // Set the click listener when LiveData is not active.
        button.setOnClickListener(listener)
    }

    override fun onInactive() {
        // Remove the click listener when LiveData is not active.
        button.setOnClickListener(null)
    }
}

And to explain your question

  • What's the listener will be used for?

That listener will be attached to the StockManager. When there is any change in StockManager, StockManager class is responsible for invoking this listener, and when the listener is invoked, it will update LiveData value.

  • What's the class StockManager?

Just an example class.

  • If I need it only for a Bitmap do I need to use onActive() and onInactive() too?

No. In fact I am guessing you would not need LiveData for transporting large object. Just as you pointed out, a simple singleton cache class is all you need. LiveData would make sense if you have a stream of Bitmap and you want the activities to automatically react to the stream. For example:

class BitmapCache {  // This can be a singleton class.

   private val bitmapLiveData = MutableLiveData<Bitmap>()

   fun cacheBitmap(bmp: Bitmap) {
       bitmapLiveData.value = bmp
   }

   fun getCachedBitmap(): LiveData<Bitmap> = bitmapLiveData as LiveData<Bitmap>
}



Edit: Here's the singleton version of the class:

object BitmapCache {

    private val bitmapLiveData = MutableLiveData<Bitmap>()

    fun cacheBitmap(bmp: Bitmap) {
        bitmapLiveData.value = bmp
    }

    fun getCachedBitmap(): LiveData<Bitmap> = bitmapLiveData as LiveData<Bitmap>
}

and it can be used like this:

// Activity A
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.mylayout)

        BitmapCache.getCachedBitmap().observe(this, Observer<Bitmap> { selfie: Bitmap? ->
        Log.i(TAG, "TRIGGERED")
    })

// Activity B
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.mylayout)

        val bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.android)

        Handler().postDelayed({
            BitmapCache.cacheBitmap(bitmap)
        }, 3000)
   }


Sanlok Lee
  • 3,404
  • 2
  • 15
  • 25
  • Thank you for the answer, let me test that, I'll do it asap! – GMX Sep 15 '19 at 09:50
  • I tried to implement your answer but the observer is never triggered, I updated the question explaining how I implemented you answer. – GMX Sep 16 '19 at 10:18
  • I don't think your BitmapCache is a working Livedata singleton, the doc explicitly say that you have to extend livedata for do that. – GMX Sep 16 '19 at 11:29
  • @GMX Please check if you have correctly implemented singleton class. The `BitmapCache` class example I provided you omitted singleton implementation for simplicity. You must provide the same instance of `BitmapCache` class to all activities. – Sanlok Lee Sep 17 '19 at 18:17