I'm encountering a ClassCastException in my Android application that occurs after the login screen when the app is uploaded to the Play Store. The application works fine in development, but it crashes in production.
Here is the exception I'm getting:
FATAL EXCEPTION: OkHttp ...
Process: , PID: 23630
F3.b: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | java.lang.ClassCastException
at A1.h.l(SourceFile:54)
at U4.b.onResponse(SourceFile:32)
at retrofit2.OkHttpCall$1.onResponse(SourceFile:11)
at F4.l.run(SourceFile:55)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
at java.lang.Thread.run(Thread.java:1012)
Caused by: java.lang.ClassCastException
at r0.a.s(SourceFile:1)
at t3.a.c(SourceFile:1)
at R3.c.b(SourceFile:21)
at D2.h.b(SourceFile:9)
at U4.b.onResponse(SourceFile:20)
at retrofit2.OkHttpCall$1.onResponse(SourceFile:11)
at F4.l.run(SourceFile:55)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
at java.lang.Thread.run(Thread.java:1012)
I have checked the structure of the parsed response to ensure it matches the expected model classes. Additionally, I removed duplicate implementations from the dependencies, but the issue persists.
What I Tried: I attempted to handle the ClassCastException by modifying my login method to include a CompositeDisposable. Here’s the original code:
public static void login(LoginRequest loginRequest, ApiCallback apiCallback) {
RetrofitApiClient.getApiInstance().login(loginRequest)
.subscribe(new DisposableSingleObserver<LoginResponse>() {
@Override
public void onSuccess(@NonNull LoginResponse loginResponse) {
Log.d(TAG,"loginResponse :: "+ loginResponse.isStatus());
if (loginResponse.isStatus()) {
getSharedData().writeData(SharedData.SharedKeys.AUTH_USER, SharedData.SharedType.GSON, loginResponse.getUser());
}
if (apiCallback != null) {
apiCallback.onSuccess(loginResponse);
}
}
@Override
public void onError(@NonNull Throwable e) {
Log.e(TAG, "login onError: ", e);
if (apiCallback != null) {
apiCallback.onError(e);
}
}
});
}
And here’s the modified version using CompositeDisposable:
public static void login(LoginRequest loginRequest, ApiCallback apiCallback, CompositeDisposable compositeDisposable) {
DisposableSingleObserver<LoginResponse> disposable = RetrofitApiClient.getApiInstance().login(loginRequest)
.subscribeWith(new DisposableSingleObserver<LoginResponse>() {
@Override
public void onSuccess(@NonNull LoginResponse loginResponse) {
try {
Log.d(TAG, "loginResponse :: " + loginResponse.isStatus());
if (loginResponse.isStatus()) {
getSharedData().writeData(SharedData.SharedKeys.AUTH_USER, SharedData.SharedType.GSON, loginResponse.getUser());
}
if (apiCallback != null) {
apiCallback.onSuccess(loginResponse);
}
} catch (ClassCastException e) {
Log.e(TAG, "ClassCastException in onSuccess: ", e);
if (apiCallback != null) {
apiCallback.onError(e);
}
}
}
@Override
public void onError(@NonNull Throwable e) {
Log.e(TAG, "login onError: ", e);
if (apiCallback != null) {
apiCallback.onError(e);
}
}
});
// Add disposable to the composite for proper disposal
compositeDisposable.add(disposable);
}
Actual Result: Despite these changes, the app still crashes with a ClassCastException after the login screen when deployed to the Play Store.
Additional Information: I am using Retrofit for API calls. The response structure and model classes have been double-checked. Help Needed: Could anyone provide insights on what might be causing this ClassCastException in production, despite working fine in development? Any suggestions on further debugging or potential fixes would be greatly appreciated.
It's fixed.
I have changed Proguard rule file and build.gradle(app)
buildTypes {
debug {
minifyEnabled false // Keep this false to disable ProGuard in debug
shrinkResources false // No resource shrinking in debug
}
release {
minifyEnabled true // Enable ProGuard in release
shrinkResources true // Shrink resources in release
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}