I have an interface that inherits from Android's TextWatcher
to only implement afterTextChanged
method. I have enabled Java 8 support in my project, and added source and target compatibility options in build.gradle
file, but even though it works flawless in debug builds, it fails in release builds on every device I tested. I first noticed it in Play Console's pre-launch report, and tested again with the Firebase's Test Lab, still every device throw AbstractMethodError
followed by a crash.
Here's my AfterTextChangedListener
:
import android.text.Editable;
import android.text.TextWatcher;
public interface AfterTextChangedListener extends TextWatcher {
@Override
default void beforeTextChanged(CharSequence s, int start, int count, int after) {
// Do nothing
}
@Override
default void onTextChanged(CharSequence s, int start, int before, int count) {
// Do nothing
}
@Override
void afterTextChanged(Editable s);
}
Here's the portion of the code that uses this interface:
mSomeEditText.addTextChangedListener((AfterTextChangedListener) editable -> {
// Logic using 'editable'.
});
Here's the Logcat output for the crash:
FATAL EXCEPTION: main
Process: my.package.name, PID: 4096
java.lang.AbstractMethodError: abstract method "void android.text.TextWatcher.beforeTextChanged(java.lang.CharSequence, int, int, int)"
at android.widget.TextView.sendBeforeTextChanged(TextView.java:9704)
at android.widget.TextView.setText(TextView.java:5615)
at android.widget.TextView.setText(TextView.java:5571)
at android.widget.EditText.setText(EditText.java:122)
at android.widget.TextView.setText(TextView.java:5528)
at i.a.a.f.c.d1.b(Unknown Source:25)
at i.a.a.f.c.d1.b(Unknown Source:105)
at androidx.fragment.app.Fragment.g(Unknown Source:11)
at androidx.fragment.app.s.a(Unknown Source:35)
at androidx.fragment.app.m.a(Unknown Source:240)
at androidx.fragment.app.m.j(Unknown Source:2)
at androidx.fragment.app.m.i(Unknown Source:58)
at androidx.fragment.app.a.e(Unknown Source:171)
at androidx.fragment.app.m.a(Unknown Source:38)
at androidx.fragment.app.m.b(Unknown Source:120)
at androidx.fragment.app.m.c(Unknown Source:84)
at androidx.fragment.app.m.b(Unknown Source:31)
at androidx.fragment.app.a.c(Unknown Source:6)
at androidx.fragment.app.q.a(Unknown Source:4)
at c.u.a.b.c(Unknown Source:385)
at c.u.a.b.e(Unknown Source:2)
at c.u.a.b.onMeasure(Unknown Source:191)
at android.view.View.measure(View.java:23181)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6749)
at androidx.coordinatorlayout.widget.CoordinatorLayout.a(Unknown Source:0)
at com.google.android.material.appbar.b.a(Unknown Source:93)
at androidx.coordinatorlayout.widget.CoordinatorLayout.onMeasure(Unknown Source:275)
at android.view.View.measure(View.java:23181)
at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:715)
at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:461)
at android.view.View.measure(View.java:23181)
at androidx.drawerlayout.widget.DrawerLayout.onMeasure(Unknown Source:264)
at android.view.View.measure(View.java:23181)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6749)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at androidx.appcompat.widget.ContentFrameLayout.onMeasure(Unknown Source:156)
at android.view.View.measure(View.java:23181)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6749)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1535)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:825)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:704)
at android.view.View.measure(View.java:23181)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6749)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at android.view.View.measure(View.java:23181)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6749)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1535)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:825)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:704)
at android.view.View.measure(View.java:23181)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6749)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at com.android.internal.policy.DecorView.onMeasure(DecorView.java:716)
at android.view.View.measure(View.java:23181)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2727)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1580)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1864)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1468)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7208)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1004)
at android.view.Choreographer.doCallbacks(Choreographer.java:816)
at android.view.Choreographer.doFrame(Choreographer.java:751)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:990)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6694)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Force finishing activity my.package.name/.ui.activities.MainActivity
I don't have any idea why this happens especially considering Android supports default methods in interfaces.
Here's my module-level build.gradle
:
apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
android {
signingConfigs {
release {
// keystore credentials
}
}
compileSdkVersion 29
buildToolsVersion '28.0.3'
defaultConfig {
applicationId "my.package.name"
minSdkVersion 16
targetSdkVersion 29
multiDexEnabled true
versionCode 66
versionName "2020.2b1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
}
}
}
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
// Material
implementation 'com.google.android.material:material:1.2.0-alpha04'
implementation 'androidx.exifinterface:exifinterface:1.1.0'
implementation 'androidx.browser:browser:1.2.0'
// Room components
implementation 'androidx.room:room-runtime:2.2.3'
implementation 'androidx.preference:preference:1.1.0'
annotationProcessor 'androidx.room:room-compiler:2.2.3'
androidTestImplementation 'androidx.room:room-testing:2.2.3'
// SafeRoom
implementation "com.commonsware.cwac:saferoom.x:1.1.3"
// Lifecycle components
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation "androidx.lifecycle:lifecycle-common-java8:2.2.0"
// Firebase
implementation 'com.google.firebase:firebase-core:17.2.2'
implementation 'com.google.firebase:firebase-ads:18.3.0'
implementation 'com.google.firebase:firebase-firestore:21.4.0'
implementation 'com.google.firebase:firebase-inappmessaging-display:19.0.3'
implementation 'com.google.firebase:firebase-messaging:20.1.0'
implementation 'com.google.firebase:firebase-perf:19.0.5'
implementation 'com.google.firebase:firebase-auth:19.2.0'
implementation 'com.google.firebase:firebase-storage:19.1.1'
implementation 'com.google.firebase:firebase-config:19.1.1'
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
//implementation('com.crashlytics.sdk.android:crashlytics:2.7.1@aar') {
// transitive = true
//}
implementation 'com.google.android.gms:play-services-auth:17.0.0'
implementation 'com.github.PhilJay:MPAndroidChart:v3.0.2'
implementation 'com.squareup.picasso:picasso:2.71828'
// implementation 'com.squareup.picasso:picasso:2.5.2'
implementation 'com.hootsuite.android:nachos:1.1.1'
implementation 'com.robertlevonyan.view:MaterialChipView:1.2.4'
implementation 'net.lingala.zip4j:zip4j:1.3.2'
implementation 'net.cachapa.expandablelayout:expandablelayout:2.9.2'
// RoundedImageView
implementation 'com.makeramen:roundedimageview:2.3.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', {
exclude group: 'com.android.support', module: 'support-annotations'
})
testImplementation 'org.json:json:20190722'
implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
// LeakCanary
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.0-beta-3'
}
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.firebase-perf'
apply plugin: 'org.sonarqube'
sonarqube {
sonarqube {
properties {
// Some properties for sonarqube
}
}
}
Here's my project-level build.gradle
:
buildscript {
repositories {
google()
jcenter()
maven {
url 'https://maven.fabric.io/public'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
classpath 'com.google.gms:google-services:4.3.3'
classpath 'io.fabric.tools:gradle:1.26.1'
classpath 'com.google.firebase:perf-plugin:1.3.1'
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7.1"
}
}
allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
maven {
url 'https://maven.google.com/'
}
maven {
url "https://s3.amazonaws.com/repo.commonsware.com"
}
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
Any idea why this happens, and how it can be solved?
default void beforeTextChanged
->public void beforeTextChanged
– Roobbiepublic default void
? No, I haven't, Android Studio says it's redundant, but will try. What does it do? – BushidobeforeTextChanged
andonTextChanged
inTextWatcher
, if I use it, code becomes bloated with empty implementations. – Bushido