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

开启minifyEnabled=true后Android发布版App因NullPointerException崩溃

问题:开启混淆与资源压缩后Preference触发空指针崩溃

发布构建中设置minifyEnabled=true和shrinkResources=true时,应用因NullPointerException崩溃;关闭minifyEnabled后恢复正常。需要保留这两个参数以缩减应用体积,但现有ProGuard规则无法解决问题。

相关代码

Preference appearance = findPreference(AppearanceSettingsFragment.class.getSimpleName());
appearance.setOnPreferenceClickListener(prefClickListener);

Preference behavior = findPreference(BehaviorSettingsFragment.class.getSimpleName());
behavior.setOnPreferenceClickListener(prefClickListener);

Preference storage = findPreference(StorageSettingsFragment.class.getSimpleName());
storage.setOnPreferenceClickListener(prefClickListener);

Preference browser = findPreference(BrowserSettingsFragment.class.getSimpleName());
browser.setOnPreferenceClickListener(prefClickListener);

Preference limitations = findPreference(LimitationsSettingsFragment.class.getSimpleName());
limitations.setOnPreferenceClickListener(prefClickListener);

当前ProGuard配置

-keep interface androidx.** { *; }
-keep class androidx.** { *; }

-keep class com.android.** { *; }
-keep class com.google.** { *; }

-keep class SettingsFragment.** { *; }
-keep class com.mix.downloader.model.* { *; }
-keepattributes Annotation,Signature

异常日志

FATAL EXCEPTION: main
Process: com.mix.downloader, PID: 31333
java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.preference.Preference.setOnPreferenceClickListener(androidx.preference.Preference$OnPreferenceClickListener)' on a null object reference
at com.mix.downloader.ui.settings.SettingsFragment.onViewCreated(SettingsFragment.java:115)
at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:5)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:262)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:117)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:31)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:57)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:10)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:12)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:5)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:21)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:1)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1435)
at android.app.Activity.performStart(Activity.java:8231)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3845)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2309)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:246)
at android.app.ActivityThread.main(ActivityThread.java:8587)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)


原因分析

混淆过程中,ProGuard会对AppearanceSettingsFragment这类类的名称进行混淆,导致class.getSimpleName()返回的混淆后名称与Preference配置中定义的key不匹配,findPreference()返回null,进而触发空指针异常。

解决方法

方法1:保留Fragment类名不被混淆

在ProGuard规则中添加以下配置,确保相关SettingsFragment的类名不被混淆:

-keepnames class com.mix.downloader.ui.settings.AppearanceSettingsFragment
-keepnames class com.mix.downloader.ui.settings.BehaviorSettingsFragment
-keepnames class com.mix.downloader.ui.settings.StorageSettingsFragment
-keepnames class com.mix.downloader.ui.settings.BrowserSettingsFragment
-keepnames class com.mix.downloader.ui.settings.LimitationsSettingsFragment

-keepnames仅保留类名,不会保留类内部未使用的方法,不影响体积优化效果。

方法2:改用固定字符串作为Preference的key

不再依赖class.getSimpleName(),直接使用硬编码的字符串常量作为key,同时确保Preference XML配置中的key与代码常量一致:

// 定义常量
private static final String KEY_APPEARANCE = "appearance_settings";
private static final String KEY_BEHAVIOR = "behavior_settings";
private static final String KEY_STORAGE = "storage_settings";
private static final String KEY_BROWSER = "browser_settings";
private static final String KEY_LIMITATIONS = "limitations_settings";

// 使用常量查找并设置监听
Preference appearance = findPreference(KEY_APPEARANCE);
if (appearance != null) {
    appearance.setOnPreferenceClickListener(prefClickListener);
}

// 其他Preference同理

同时添加null判断,即使出现异常也不会导致应用崩溃。

方法3:保留Preference配置中的字符串资源

如果Preference的key定义在XML中,可添加规则避免资源压缩移除这些字符串:

-keepresourcestrings res/values/preferences.xml

该配置为辅助项,核心问题仍需通过前两种方法解决。

内容的提问来源于stack exchange,提问作者Abdullah Kahtan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 18:10:37