How can I pass a Bitmap object from one activity to another

前端 未结 10 920
隐瞒了意图╮
隐瞒了意图╮ 2020-11-22 03:39

In my activity, I create a Bitmap object and then I need to launch another Activity, How can I pass this Bitmap object from the sub-ac

10条回答
  •  礼貌的吻别
    2020-11-22 03:47

    Compress and Send Bitmap

    The accepted answer will crash when the Bitmap is too large. I believe it's a 1MB limit. The Bitmap must be compressed into a different file format such as a JPG represented by a ByteArray, then it can be safely passed via an Intent.

    Implementation

    The function is contained in a separate thread using Kotlin Coroutines because the Bitmap compression is chained after the Bitmap is created from an url String. The Bitmap creation requires a separate thread in order to avoid Application Not Responding (ANR) errors.

    Concepts Used

    • Kotlin Coroutines notes.
    • The Loading, Content, Error (LCE) pattern is used below. If interested you can learn more about it in this talk and video.
    • LiveData is used to return the data. I've compiled my favorite LiveData resource in these notes.
    • In Step 3, toBitmap() is a Kotlin extension function requiring that library to be added to the app dependencies.

    Code

    1. Compress Bitmap to JPG ByteArray after it has been created.

    Repository.kt

    suspend fun bitmapToByteArray(url: String) = withContext(Dispatchers.IO) {
        MutableLiveData>().apply {
            postValue(Lce.Loading())
            postValue(Lce.Content(ContentResult.ContentBitmap(
                ByteArrayOutputStream().apply {
                    try {                     
                        BitmapFactory.decodeStream(URL(url).openConnection().apply {
                            doInput = true
                            connect()
                        }.getInputStream())
                    } catch (e: IOException) {
                       postValue(Lce.Error(ContentResult.ContentBitmap(ByteArray(0), "bitmapToByteArray error or null - ${e.localizedMessage}")))
                       null
                    }?.compress(CompressFormat.JPEG, BITMAP_COMPRESSION_QUALITY, this)
               }.toByteArray(), "")))
            }
        }
    

    ViewModel.kt

    //Calls bitmapToByteArray from the Repository
    private fun bitmapToByteArray(url: String) = liveData {
        emitSource(switchMap(repository.bitmapToByteArray(url)) { lce ->
            when (lce) {
                is Lce.Loading -> liveData {}
                is Lce.Content -> liveData {
                    emit(Event(ContentResult.ContentBitmap(lce.packet.image, lce.packet.errorMessage)))
                }
                is Lce.Error -> liveData {
                    Crashlytics.log(Log.WARN, LOG_TAG,
                            "bitmapToByteArray error or null - ${lce.packet.errorMessage}")
                }
            }
        })
    }
    

    2. Pass image as ByteArray via an Intent.

    In this sample it's passed from a Fragment to a Service. It's the same concept if being shared between two Activities.

    Fragment.kt

    ContextCompat.startForegroundService(
        context!!,
        Intent(context, AudioService::class.java).apply {
            action = CONTENT_SELECTED_ACTION
            putExtra(CONTENT_SELECTED_BITMAP_KEY, contentPlayer.image)
        })
    

    3. Convert ByteArray back to Bitmap.

    Utils.kt

    fun ByteArray.byteArrayToBitmap(context: Context) =
        run {
            BitmapFactory.decodeByteArray(this, BITMAP_OFFSET, size).run {
                if (this != null) this
                // In case the Bitmap loaded was empty or there is an error I have a default Bitmap to return.
                else AppCompatResources.getDrawable(context, ic_coinverse_48dp)?.toBitmap()
            }
        }
    

提交回复
热议问题