You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

切换至Release变体时ViewModelProvider触发ClassCastException问题求助

问题描述

切换应用构建变体为Release(仅修改端点、凭证等配置文件)时,出现如下崩溃:

FATAL EXCEPTION: main
Process: com.timo.ecocloud.paciente, PID: 15435
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.timo.ecocloud.paciente/com.timo.ecocloudpaciente.ui.login.LoginActivity}: java.lang.ClassCastException
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3635)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3792)
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2210)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loopOnce(Looper.java:201)
    at android.os.Looper.loop(Looper.java:288)
    at android.app.ActivityThread.main(ActivityThread.java:7839)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
Caused by: java.lang.ClassCastException
    at android.support.v4.media.session.b.a(SourceFile:1)
    at j1.a.<init>(SourceFile:1)
    at com.timo.ecocloudpaciente.ui.login.f.a(SourceFile:1)
    at androidx.lifecycle.s.b(SourceFile:1)
    at androidx.lifecycle.s.a(SourceFile:1)
    at com.timo.ecocloudpaciente.ui.login.LoginActivity.onCreate(Unknown Source:68)
    at android.app.Activity.performCreate(Activity.java:8051)
    at android.app.Activity.performCreate(Activity.java:8031)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1329)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3608)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3792) 
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103) 
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2210) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loopOnce(Looper.java:201) 
    at android.os.Looper.loop(Looper.java:288) 
    at android.app.ActivityThread.main(ActivityThread.java:7839) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)   
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)

触发崩溃的代码:

loginViewModel = ViewModelProviders.of(this, new LoginViewModelFactory())
                .get(LoginViewModel.class);

已尝试更新相关依赖,也改用了新写法:

new ViewModelProvider(this, new LoginViewModelFactory()).get(LoginViewModel.class);

但问题依旧。

补充代码

Activity中触发错误的代码

loginViewModel = ViewModelProviders.of(this, new LoginViewModelFactory())
                .get(LoginViewModel.class);

LoginViewModel.java

package com.timo.ecocloudpaciente.ui.login;

import android.app.Activity;
import android.util.Log;
import android.util.Patterns;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

import com.timo.ecocloudpaciente.data.LoginRepository;
import com.timo.ecocloudpaciente.R;
import com.timo.ecocloudpaciente.model.DefaultResponse;
import com.timo.ecocloudpaciente.model.DefaultResponseResult;
import com.timo.ecocloudpaciente.model.User;

public class LoginViewModel extends ViewModel {

    private MutableLiveData<LoginFormState> loginFormState = new MutableLiveData<>();
    private MutableLiveData<RecoverFormState> recoverFormState = new MutableLiveData<>();

    private MutableLiveData<LoginResult> loginResult = new MutableLiveData<>();
    private MutableLiveData<DefaultResponseResult> defaultResult = new MutableLiveData<>();
    private LoginRepository loginRepository;

    LoginViewModel(LoginRepository loginRepository) {
        this.loginRepository = loginRepository;
    }


    /**
     * Login
     */

    LiveData<LoginFormState> getLoginFormState() {
        return loginFormState;
    }

    LiveData<LoginResult> getLoginResult() {
        return loginResult;
    }

    public void login(String username, String password) {
        // can be launched in a separate asynchronous job
        loginRepository.login(username, password, this);
    }

    public void loginDataChanged(String username, String password) {
        if (!isUserNameValid(username)) {
            loginFormState.setValue(new LoginFormState(R.string.login_invalid_username, null));
        } else if (!isPasswordValid(password)) {
            loginFormState.setValue(new LoginFormState(null, R.string.login_invalid_password));
        } else {
            loginFormState.setValue(new LoginFormState(true));
        }
    }

    // A placeholder username validation check
    private boolean isUserNameValid(String username) {
        return username != null && !username.equals("");
    }

    // A placeholder password validation check
    private boolean isPasswordValid(String password) {
        return password != null && password.trim().length() == 6;
    }

    /**
     * Used for callback
     */
    public void onSuccess(User user) {
        loginResult.setValue(new LoginResult(user));
    }

    public void onError(String message) {
        loginResult.setValue(new LoginResult(message));
    }

    /**
     * Recover password
     */
    LiveData<RecoverFormState> getRecoverFormState() {
        return recoverFormState;
    }

    public void recoverDataChanged(String useremail) {

        if (!isEmailValid(useremail)) {
            recoverFormState.setValue(new RecoverFormState(R.string.recover_invalid_email));
        }else {
            recoverFormState.setValue(new RecoverFormState(true));
        }
    }

    LiveData<DefaultResponseResult> getDefaultResult() {
        return defaultResult;
    }

    public void recoverPwd(Activity activity, LoginViewModel loginViewModel, String email){
        loginRepository.recoverPwd(activity, loginViewModel,  email);
    }

    private boolean isEmailValid(String email){
        if (email == null || email.trim().isEmpty())
           return false;

        if (email.contains("@"))
            return Patterns.EMAIL_ADDRESS.matcher(email).matches();
        else
            return false;
    }


    /**
     * Used for callback
     */
    public void defaultReturnOnSuccess(DefaultResponse defaultResponse) {
        defaultResult.setValue(new DefaultResponseResult(defaultResponse, ""));
    }

    public void defaultReturnOnError(String message) {
        defaultResult.setValue(new DefaultResponseResult(message));
    }
}

LoginViewModelFactory.java

package com.timo.ecocloudpaciente.ui.login;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import androidx.annotation.NonNull;

import com.timo.ecocloudpaciente.data.LoginDataSource;
import com.timo.ecocloudpaciente.data.LoginRepository;
public class LoginViewModelFactory implements ViewModelProvider.Factory {
    @NonNull
    @Override
    @SuppressWarnings("unchecked")
    public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
        if (modelClass.isAssignableFrom(LoginViewModel.class)) {
            return (T) new LoginViewModel(LoginRepository.getInstance(new LoginDataSource()));
        } else {
            throw new IllegalArgumentException("Unknown ViewModel class");
        }
    }
}
解决方案

这个问题的核心是Release模式下的代码混淆导致ViewModel相关类被错误重命名,进而引发类型转换异常。从崩溃栈可以看到,类名已经被混淆成j1.a、com.timo.ecocloudpaciente.ui.login.f这类无意义名称,ViewModel的类型信息在混淆后丢失,导致get(LoginViewModel.class)时无法正确转换类型。

需要在项目的混淆规则文件(通常是proguard-rules.pro)中添加以下规则,排除ViewModel相关类的混淆:

# 保留所有继承自ViewModel的类及其构造方法
-keep public class * extends androidx.lifecycle.ViewModel {
    <init>(...);
}

# 保留所有实现ViewModelProvider.Factory的类及其构造方法
-keep public class * implements androidx.lifecycle.ViewModelProvider.Factory {
    <init>(...);
}

# 保留当前项目中的LoginViewModel和LoginViewModelFactory
-keep class com.timo.ecocloudpaciente.ui.login.LoginViewModel
-keep class com.timo.ecocloudpaciente.ui.login.LoginViewModelFactory

# 保留LiveData相关类,避免潜在的混淆问题
-keep class androidx.lifecycle.LiveData
-keep class androidx.lifecycle.MutableLiveData

如果希望更简单直接,也可以保留整个登录模块的类不被混淆:

-keep class com.timo.ecocloudpaciente.ui.login.** { *; }

添加完混淆规则后,重新构建Release变体即可解决这个ClassCastException问题。


内容的提问来源于stack exchange,提问作者Thiago Souza

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 19:25:53