Home > OS >  Is there an option to override parameters, methods in library?
Is there an option to override parameters, methods in library?

Time:09-07

According to this topic: How to override method in library?

I would like to override some methods and variables from InkView. Is it possible? :)

I have created class:

class MyInkView: InkView {
    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int = 0): super(context, attrs, defStyleAttr)
    constructor(context: Context, attrs: AttributeSet): super(context, attrs)
    constructor(context: Context): super(context)
    // include any other constructors you need based on the ones in the superclass
    var bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)

   override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {

       // clean up existing bitmap
       if (bitmap != null) {
           bitmap.recycle()
       }

       // init bitmap cache
       bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
       canvas = Canvas(bitmap)

       // notify listeners
       for (listener in listeners) {
           listener.onInkClear()
       }

       invalidate()
       isEmpty = true
    }
}

Of course it gives some error of accidental overrides:

Accidental override: The following declarations have the same JVM signature (getBitmap()Landroid/graphics/Bitmap;):

Cannot access 'canvas': it is invisible (private in a supertype) in 'MyInkView'

Cannot access 'listeners': it is invisible (private in a supertype) in 'MyInkView'

Entire InkView https://justpaste.it/27rn0

If I make it empty it doesn't create any bitmap and I have error with this.

java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.graphics.Bitmap.isRecycled()' on a null object reference

1 EDIT:

I make this function:

    fun getBitmap(backgroundColor: Int, lineColor: Int): Bitmap? {
        val currentPaint: Paint = readPrivateField("paint") ?: return null
        val linePaint = Paint(currentPaint)
        linePaint.colorFilter = PorterDuffColorFilter(lineColor, PorterDuff.Mode.SRC_IN)
        val currentBitmap: Bitmap = readPrivateField("bitmap") ?: return null
        val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        val bitmapCanvas = Canvas(bitmap)
        bitmapCanvas.drawColor(backgroundColor)
        bitmapCanvas.drawBitmap(currentBitmap, 0f, 0f, linePaint)
        return bitmap
    }

Previously without custom class view it worked like this in .extension :

fun InkView.getBitmap(backgroundColor: Int, lineColor: Int): Bitmap? {
    val currentPaint: Paint = readPrivateField("paint") ?: return null
    val linePaint = Paint(currentPaint)
    linePaint.colorFilter = PorterDuffColorFilter(lineColor, PorterDuff.Mode.SRC_IN)
    val currentBitmap: Bitmap = readPrivateField("bitmap") ?: return null
    val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
    val bitmapCanvas = Canvas(bitmap)
    bitmapCanvas.drawColor(backgroundColor)
    bitmapCanvas.drawBitmap(currentBitmap, 0f, 0f, linePaint)
    return bitmap
}

Unfortunately it make crash during saving this bitmap.

     Caused by: java.lang.NoSuchFieldException: No field paint in class Lcom/application/core/view/MyInkView; (declaration of 'com.application.core.view.MyInkView' appears in base.apk!classes2.dex)
        at java.lang.Class.getDeclaredField(Native Method)
        at com.application.core.view.MyInkView.getBitmap(MyInkView.kt:50)

That's where this error occurs:

inline fun <T : Any, reified R> T.readPrivateField(name: String): R? {
    val field = javaClass.getDeclaredField(name)   -<<<< CRASH
    field.isAccessible = true
    val result = field.get(this) as? R
    field.isAccessible = false
    return result
}

CodePudding user response:

Here's how I'd attempt what you described in the comments. It disables the clear() function, but allows you to manually clear it by calling forceClear().

class MyInkView: InkView {
    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int = 0): super(context, attrs, defStyleAttr)
    constructor(context: Context, attrs: AttributeSet): super(context, attrs)
    constructor(context: Context): super(context)

    override fun clear() {}

    fun forceClear() = super.clear()
}

However, I suspect you actually need to allow it to clear if the view truly changes size, because otherwise the bitmap will be the wrong size for the view. I would do this instead, exit the function early when the size has not actually changed. Also ignore sizes of 0 in case there's ever a transitionary size 0 state.

class MyInkView: InkView {
    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int = 0): super(context, attrs, defStyleAttr)
    constructor(context: Context, attrs: AttributeSet): super(context, attrs)
    constructor(context: Context): super(context)

    private var lastAcceptedWidth = -1
    private var lastAcceptedHeight = -1
    private var preventClear = false;

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        preventClear = (w == lastAcceptedWidth && h == lastAcceptedHeight) || w == 0 || h == 0
        if (!preventClear) {
            lastAcceptedWidth = w
            lastAcceptedHeight = h
        }
        super.onSizeChanged(w, h, oldw, oldh)
        preventClear = false
    }

    override fun clear() {
        if (!preventClear) super.clear()
    }
}
  • Related