Daniel Iroka
Daniel Iroka

Reputation: 143

How to Parcelize a MutableList in kotlin?

I have an App that lets users drag and draw boxes on a custom view. I want to persist the state of these boxes(list of boxes) across orientation change using onSavedInstanceState(): Parcelable and onRestoreInstanceState(state: Parcelable). However, I don't know how to store a MutableList because the only available function is putParcelableArrayList. Please how do I parcelize a Mutable List to persist the boxes across rotation? I know the docs said its possible but I don't know how to. Here is the code.

@Parcelize
class Box(private val start: PointF) : Parcelable {

    // When a user touches BoxDrawingView, a new box will be created and added to the list of existing boxes.
    var end: PointF = start

    val left: Float
        get() = start.x.coerceAtMost(end.x)

    val right: Float
        get() = start.x.coerceAtLeast(end.x)

    val top: Float
        get() = start.y.coerceAtMost(end.y)

    val bottom: Float
        get() = start.y.coerceAtLeast(end.y)

}

My custom View

import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.PointF
import android.os.Bundle
import android.os.Parcelable
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View

/** This Class is where we setup our custom View and write the Implementation for listening to touch events from the USER and draw boxes on the Screen.**/

private const val TAG = "BoxDrawingView"
private const val BOX_STATE = "box"
private const val VIEW_STATE = "view"

class BoxDrawingView(context: Context, attrs: AttributeSet? = null) :
        View(context, attrs) {

    private var currentBox: Box? = null
    private var boxen = mutableListOf<Box>()  // list of boxes to be drawn out on the screen

    private val boxPaint = Paint().apply {
        color = 0x22ff0000
    }
    private val backGroundPaint = Paint().apply {
        color = 0xfff8efe0.toInt()
    }

    init {
        isSaveEnabled = true
    }

    override fun onSaveInstanceState(): Parcelable {
        val bundle = Bundle()
        bundle.putParcelableArrayList(BOX_STATE, boxen)  // type mismatch error because of mutableList passed to ArrayList
        bundle.putParcelable(VIEW_STATE, super.onSaveInstanceState())

        return bundle
    }

    override fun onRestoreInstanceState(state: Parcelable?) {
        var viewState = state
        if (viewState is Bundle) {
            boxen = viewState.getParcelableArrayList<Box>(BOX_STATE)?.toMutableList() ?: mutableListOf()
            viewState = viewState.getParcelable(VIEW_STATE)
        }
        super.onRestoreInstanceState(state)
    }


    override fun onDraw(canvas: Canvas) {
        // Fill in the background
        canvas.drawPaint(backGroundPaint)

        boxen.forEach { box ->
            canvas.drawRect(box.left, box.top, box.right, box.bottom, boxPaint)
        }
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        val current = PointF(event.x, event.y)
        var action = ""

        when(event.action) {
            MotionEvent.ACTION_DOWN -> {
                action = "ACTION_DOWN"
                // Reset drawing state
                currentBox = Box(current).also {
                    boxen.add(it)
                }
            }
            MotionEvent.ACTION_MOVE -> {
                action = "ACTION_MOVE"
                // update the currentBox.end as the user moves his/her finger around the screen
                updateCurrentBox(current)
            }
            MotionEvent.ACTION_UP -> {
                action = "ACTION_UP"
                // tells the last report of the currentBox as the user's finger leaves the screen
                updateCurrentBox(current)
                currentBox = null
            }
            MotionEvent.ACTION_CANCEL -> {
                action = "ACTION_CANCEL"
                currentBox = null
            }
        }

        // this is a log message for each of the 4 Event actions
        Log.i(TAG, "$action at x=${current.x}, y=${current.y}")

        return true
    }

Upvotes: 1

Views: 1137

Answers (1)

Daniel Iroka
Daniel Iroka

Reputation: 143

Changing the boxen type to arrayList() worked. Turns out arrayList works as a mutable list under the hood. Also David wasser's answer in the comments also worked.

Upvotes: 0

Related Questions