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

Android升级Material库1.6.1后触发String转Boolean启动崩溃

Material组件库升级后启动崩溃问题

问题现象

将自有应用中的Material组件库从1.4.0版本升级至1.6.1版本,依赖配置如下:

implementation 'com.google.android.material:material:1.6.1'

使用1.4.0版本时应用运行完全正常,升级后应用启动时立即崩溃,报错信息如下:

2022-07-05 17:13:17.784 17333-17333/? E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.nooriginalthought.amalfi, PID: 17333
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.nooriginalthought.amalfi/com.nooriginalthought.amalfi.MainActivity}: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Boolean
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2195)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
        at android.app.ActivityThread.access$800(ActivityThread.java:135)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:136)
        at android.app.ActivityThread.main(ActivityThread.java:5017)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
        at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Boolean
        at android.app.SharedPreferencesImpl.getBoolean(SharedPreferencesImpl.java:261)
        at o4.w.u()
        at com.nooriginalthought.amalfi.MainActivity.onCreate(:2)
        at android.app.Activity.performCreate(Activity.java:5231)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2159)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245) 
        at android.app.ActivityThread.access$800(ActivityThread.java:135) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:136) 
        at android.app.ActivityThread.main(ActivityThread.java:5017) 
        at java.lang.reflect.Method.invokeNative(Native Method) 
        at java.lang.reflect.Method.invoke(Method.java:515) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595) 
        at dalvik.system.NativeStart.main(Native Method) 
2022-07-05 17:13:26.944 1609-1623/system_process E/WindowManager: Starting window AppWindowToken{ad48a468 token=Token{ad419be0 ActivityRecord{ad079590 u0 com.nooriginalthought.amalfi/.MainActivity t84}}} timed out

测试发现,注释掉onCreate()方法中如下Google Play服务校验代码行,应用即可正常启动,但会缺失必需的校验逻辑:

isGooglePlayServicesAvailable(this);

自定义的isGooglePlayServicesAvailable方法明确定义返回Boolean类型,方法实现如下:

public boolean isGooglePlayServicesAvailable(Activity activity) {
    GoogleApiAvailability googleApiAvailability = GoogleApiAvailability.getInstance();
    int status = googleApiAvailability.isGooglePlayServicesAvailable(activity);
    if(status != ConnectionResult.SUCCESS) {
        if(googleApiAvailability.isUserResolvableError(status)) {
            googleApiAvailability.getErrorDialog(activity, status, GOOGLE_PLAY_SERVICES_API_REQUEST_CODE).show();
        }
        return false;
    }
    return true;
}

已尝试Gradle重同步、Clean后重新构建,问题依旧复现。测试设备均已正常安装Google Play服务,初步怀疑是错误弹窗调用时出现异常。


补充信息

完整onCreate()方法代码如下,排查后未发现方法内存在直接触发该类型转换错误的逻辑:

@Override
protected void onCreate(Bundle _savedInstanceState) {
    super.onCreate(_savedInstanceState);

    isGooglePlayServicesAvailable(this);
    addExtraSslProtocolsIfNeeded();

    amalfi = Amalfi.getInstance(getApplicationContext());
    affiliateRegions = new AffiliateRegions(this);


    // Read prefs and aff_ids here because they are used in start activity decision making
    amalfi.read_prefs();
    CommonFuncs.setLocale(this,amalfi.UIlang);

    // Go directly to the First Run Welcome Activity if it hasn't been shown AND acknowledged
    if (!amalfi.compWarnShown_firstRun) {
        showFirstRunMessage();
    }

    amalfi.get_affids_fromprefs(affiliateRegions);

    // Get the intent that started this activity
    Intent intent = getIntent();
    String action = intent.getAction();
    String type = intent.getType();

    // Figure out what to do based on the intent type
    if (Intent.ACTION_SEND.equals(action) && type != null) {
        if ("text/plain".equals(type)) {
            incomingString = intent.getStringExtra(Intent.EXTRA_TEXT);
        }
    } else if (Intent.ACTION_VIEW.equals(action)) {
        if (intent.getDataString() != null) {
            incomingString = intent.getDataString();
        }
    }

    if ( amalfi.launchIntoBrowser && (incomingString == null || "".equals(incomingString) ) ) {
        startBrowseAmazonActivity();
    }


    // If not starting another activity, then continue loading this one as normal.
    viewBinding = MainBinding.inflate(getLayoutInflater());
    View view = viewBinding.getRoot();
    drawerViewBinding = viewBinding.drawerMenu;
    setContentView(view);

    // This if block is trying to get the auto layout transitions working - but doesn't seem to make any difference.
    viewBinding.mainLayout.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
    drawerViewBinding.drawerRoot.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);

    // Hide the expanded source URL block
    viewBinding.expandedSrcUrlContainer.setVisibility(GONE);

    amalfi.isPro();
    enable_and_disable_buttons();

    // Setup the in app purchases stuff
    setupBillingClient();

}

方法内仅在调用intent.getAction()和intent.getType()时赋值String类型变量,这两个API的返回值本身就是String类型,不存在类型转换错误。


问题根因

崩溃是Material 1.6.0+版本内部逻辑调整导致的:从1.6.0版本开始,Material组件初始化时会从自身的SharedPreferences文件中读取主题相关的布尔型配置标记,但本地缓存中该key对应的值是1.4.0版本时期存入的字符串类型,调用getBoolean方法读取时直接触发类型转换异常。
崩溃恰好出现在Google Play服务校验逻辑处,是因为getErrorDialog弹出的对话框默认使用全局Material主题,会提前触发Material组件的初始化流程;注释掉这段校验代码后,Material组件初始化延后到inflate布局阶段,并不是真的解决了问题。

修复方案

按优先级依次尝试:

  • 在onCreate方法最靠前的位置,清理Material组件的旧缓存偏好,这段逻辑不会影响任何业务数据:
    getSharedPreferences("com.google.android.material.theme", MODE_PRIVATE).edit().clear().apply();
    
    注意这段代码必须放在所有调用Material组件、弹出系统对话框、inflate布局的逻辑之前执行。
  • 排查所有主题配置文件,确认所有布尔类型的属性值都直接写true/false,不要加引号写成字符串格式,重点检查状态栏明暗模式、深色主题开关、Material组件主题覆盖相关的属性。
  • 如果清理缓存后仍有异常,可以给Google Play服务的错误对话框指定独立主题,避免和全局Material配置冲突:
    先在styles.xml中定义独立的对话框主题:
    <style name="GpsErrorDialogTheme" parent="Theme.MaterialComponents.Light.Dialog.Alert">
        <item name="colorPrimary">@color/应用主色值</item>
        <item name="colorAccent">@color/应用强调色值</item>
    </style>
    
    再修改弹窗调用代码,传入自定义主题:
    googleApiAvailability.getErrorDialog(activity, status, GOOGLE_PLAY_SERVICES_API_REQUEST_CODE, R.style.GpsErrorDialogTheme).show();
    

内容的提问来源于stack exchange,提问作者Fat Monk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 23:27:35