Eugen Pechanec Eugen Pechanec - 2 months ago 18
Android Question

VerifyError when using Instant Run

A

VerifyError
is thrown when
XpInsetDrawable.create(Drawable, int)
(code below) is reached. This does not happen when not using Instant Run.

I'm using Android Studio 2.0.0 and gradle build plugin 2.0.0. Tested on SDK 22. When run on SDK 19 emulator the whole emulator restarts.

I'm looking for a solution other than "disable Instant Run".

Exception (whole stack trace is unrelated)

Caused by: java.lang.VerifyError:
Verifier rejected class net.xpece.android.support.preference.XpInsetDrawable due to bad method
java.lang.Object net.xpece.android.support.preference.XpInsetDrawable.access$super(
net.xpece.android.support.preference.XpInsetDrawable,
java.lang.String,
java.lang.Object[])
(declaration of 'net.xpece.android.support.preference.XpInsetDrawable'
appears in /data/data/net.xpece.android.support.preference.sample/files/instant-run/dex/slice-slice_7-classe


Class source code

final class XpInsetDrawable extends InsetDrawable {
private static final boolean NEEDS_FIXING = Build.VERSION.SDK_INT < 21;

private final Rect mInset = new Rect();

public static InsetDrawable create(final Drawable drawable, final int insetLeft, final int insetTop, final int insetRight, final int insetBottom) {
if (NEEDS_FIXING) {
return new XpInsetDrawable(drawable, insetLeft, insetTop, insetRight, insetBottom);
} else {
return new InsetDrawable(drawable, insetLeft, insetTop, insetRight, insetBottom);
}
}

public static InsetDrawable create(final Drawable drawable, final int inset) {
if (NEEDS_FIXING) {
return new XpInsetDrawable(drawable, inset);
} else {
return new InsetDrawable(drawable, inset);
}
}

XpInsetDrawable(final Drawable drawable, final int inset) {
super(drawable, inset);
mInset.set(inset, inset, inset, inset);
}

XpInsetDrawable(final Drawable drawable, final int insetLeft, final int insetTop, final int insetRight, final int insetBottom) {
super(drawable, insetLeft, insetTop, insetRight, insetBottom);
mInset.set(insetLeft, insetTop, insetRight, insetBottom);
}

@Override
public int getIntrinsicHeight() {
return super.getIntrinsicHeight() + mInset.top + mInset.bottom;
}

@Override
public int getIntrinsicWidth() {
return super.getIntrinsicWidth() + mInset.left + mInset.right;
}
}

Answer

UPDATE 2016-08-25: Fix released in Android Studio 2.2-beta3.


UPDATE 2016-07-15: Target release for fix is now Android Studio 2.3.


I filed a bug with Android and here's what dev j...@google.com had to say about it:

Interesting !

The XpInsetDrawable is a subclass of InsetDrawable which parent has changed in 23. Starting in 23, InsetDrawable subclasses DrawableWrapper which was added in 23. The app is compiled with CompileSdkVersion 23 so we generate method accesses for the DrawableWrapper methods.

now when running on <23, these methods do no exist, in fact the class does not exist so we blow up.

workaround for now is to have compileSdkVersion set to a lower version or run the application on 23 when in InstantRun mode.

and

potential fix is to instrument against the targeted device API level android.jar rather than the compileSdkVersion one. This is too involving for 2.1, targeted to 2.2.

Source: https://code.google.com/p/android/issues/detail?id=206746


This means that I can't subclass InsetDrawable and use Instant Run at the same time until Android Studio 2.2 is released.

I'll look into copying SDK 22 InsetDrawable directly into my project.