android基础之onSaveInstanceState用法(一)保存容易被回收的自定义类的静态全局变量

本文详细介绍了如何在Android应用中通过将单例模式变量定义为全局变量或在onSaveInstanceState中进行保存,来避免内存不足时变量被回收导致的数据丢失问题。通过实例代码演示了实现过程。

当切换到其它apk时且内存不足时,在之前设置的单例模式静态变量会被回收掉。解决方法要么定义为Applicantion全局变量,要么在onSaveInstanceState中保存


@Override

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//恢复容易被回收的投保人

if(savedInstanceState!=null){

//自定义单例

InsuranceFormAgent insFormAgent = InsuranceFormAgent.createInstance();
CustomerDetailInfo applicant = (CustomerDetailInfo) savedInstanceState.getSerializable("Applicant");
if(applicant!=null){
insFormAgent.setApplicantInfo(applicant);
}
AppLog.debug("-------ActProposalChooseProduct---------onCreate get the savedInstanceState---------");
}

setContentView(R.layout.demo_pro_choose_insurant);

}



@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// 为了防止万一程序被销毁的风险,这个方法可以保证重要数据的正确性
// 不写这个方法并不意味着一定出错,但是一旦遇到了一些非常奇怪的数据问题的时候
// 可以看看是不是由于某些重要的数据没有保存,在程序被销毁时被重置
// Save away the original text, so we still have it if the activity needs to be killed while paused.


//切换到其它apk时,当内存不足时,在之前设置的静态变量投保人会被回收掉。所以在此要保存
InsuranceFormAgent insFormAgent = InsuranceFormAgent.createInstance();
CustomerDetailInfo customer = insFormAgent.getmApplicantInfo();
savedInstanceState.putSerializable(APPLICANT,customer);
super.onSaveInstanceState(savedInstanceState);
AppLog.debug("-----------ActDemoProChooseInsurant---------------onSaveInstanceState--");
}


@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// int mCount = savedInstanceState.getInt("IntTest");
//恢复容易被回收的投保人
if(savedInstanceState!=null){
InsuranceFormAgent insFormAgent = InsuranceFormAgent.createInstance();
CustomerDetailInfo applicant = (CustomerDetailInfo) savedInstanceState.getSerializable(APPLICANT);
if(applicant!=null){
insFormAgent.setApplicantInfo(applicant);
}
}
AppLog.debug("------ActDemoProChooseInsurant----------onRestoreInstanceState---");
}

<think> 我们已经在之前的回答中介绍了通过自定义Application和UncaughtExceptionHandler来保存全局变量的方法。结合用户提供的引用内容,我们发现引用[5]提到了种收集崩溃日志保存到本地的实现方式,这与我们的目标(保存全局变量)在技术实现上类似。下面我们将整合这些信息,给出个更完善的解决方案。 ### 解决方案:程序崩溃时保存全局变量 #### 原理 1. 使用`Thread.setDefaultUncaughtExceptionHandler`设置自定义崩溃处理器 2. 在崩溃处理器的`uncaughtException`方法中保存全局变量 3. 通过持久化存储(如SharedPreferences)保存数据 4. 应用重启时恢复数据 #### 具体实现 **步骤1:创建自定义Application类(继承Application)** ```java public class CrashApp extends Application { private static CrashApp instance; private String globalData; // 示例全局变量 @Override public void onCreate() { super.onCreate(); instance = this; // 初始化崩溃处理器 CrashHandler.init(this); // 恢复全局变量(如果存在崩溃保存的数据) restoreGlobalData(); } public static CrashApp getInstance() { return instance; } // 保存全局变量到SharedPreferences public void saveGlobalData() { SharedPreferences prefs = getSharedPreferences("global_data", MODE_PRIVATE); prefs.edit() .putString("global_var", globalData) .apply(); } // 从SharedPreferences恢复全局变量 private void restoreGlobalData() { SharedPreferences prefs = getSharedPreferences("global_data", MODE_PRIVATE); globalData = prefs.getString("global_var", "default_value"); } } ``` **步骤2:实现自定义崩溃处理器(参考引用[5]的日志保存思路)** ```java public class CrashHandler implements Thread.UncaughtExceptionHandler { private static final String TAG = "CrashHandler"; private static CrashHandler instance; private Context context; private Thread.UncaughtExceptionHandler defaultHandler; public static void init(Context context) { if (instance == null) { instance = new CrashHandler(context); } } private CrashHandler(Context context) { this.context = context.getApplicationContext(); // 获取系统默认的异常处理器 defaultHandler = Thread.getDefaultUncaughtExceptionHandler(); // 设置当前处理器为默认处理器 Thread.setDefaultUncaughtExceptionHandler(this); } @Override public void uncaughtException(Thread thread, Throwable ex) { try { // 1. 保存全局变量 if (context instanceof CrashApp) { ((CrashApp) context).saveGlobalData(); } // 2. (可选)保存崩溃日志到文件(参考引用[1][5]) saveCrashInfoToFile(ex); } catch (Exception e) { Log.e(TAG, "Error handling crash", e); } finally { // 3. 调用系统默认处理器(结束应用) defaultHandler.uncaughtException(thread, ex); } } // 保存崩溃信息到文件(示例) private void saveCrashInfoToFile(Throwable ex) { // 实现方式参考引用[5]或以下简化版: String logPath = context.getExternalFilesDir(null) + "/crash_logs/"; File dir = new File(logPath); if (!dir.exists()) dir.mkdirs(); try (PrintWriter pw = new PrintWriter(new File(dir, "crash_" + System.currentTimeMillis() + ".log"))) { ex.printStackTrace(pw); // 可以添加设备信息等(参考引用[1]) } catch (Exception e) { Log.e(TAG, "Save crash info failed", e); } } } ``` **步骤3:在AndroidManifest.xml中注册自定义Application** ```xml <application android:name=".CrashApp" <!-- 参考引用[4] --> ... > ... </application> ``` #### 关键点说明 1. **数据持久化**: - 使用`SharedPreferences`存储简单全局变量 - 复杂对象建议用Gson转换为JSON字符串存储 2. **同步写入保证**: - 崩溃时使用`commit()`替代`apply()`确保同步写入(但会阻塞线程): ```java prefs.edit().putString("key", value).commit(); ``` - 权衡:`commit()`的可靠性 vs `apply()`的性能 3. **多进程问题**: - 如果应用使用多进程,需考虑跨进程数据共享问题 - 解决方案:使用`ContentProvider`或`MODE_MULTI_PROCESS`(已废弃) 4. **崩溃日志与全局变量分离**: - 全局变量保存和崩溃日志保存应分开处理 - 全局变量存储在应用私有目录,崩溃日志可存储在公共目录(便于导出分析) #### 注意事项 1. **性能影响**: - 在崩溃处理中执行存储操作要尽量快速,避免ANR - 复杂数据建议只保存关键字段 2. **数据污染**: - 添加版本控制字段,防止旧版本数据污染新版本 - 应用正常退出时清除崩溃保存的标志 3. **生命周期协调**: - 当系统因内存不足终止进程时(引用[2]),此方法无法保存变量 - 需配合`onSaveInstanceState`保存Activity状态 #### 替代方案:使用进程检查 ```java // 在Application中检查上次是否异常退出 SharedPreferences prefs = getSharedPreferences("crash_flag", MODE_PRIVATE); if (prefs.getBoolean("is_crashed", false)) { // 执行数据恢复 } prefs.edit().putBoolean("is_crashed", true).apply(); // 正常退出时清除标志 @Override public void onTerminate() { super.onTerminate(); getSharedPreferences("crash_flag", MODE_PRIVATE).edit() .remove("is_crashed").apply(); } ``` ### 总结流程图 ```mermaid graph TD A[程序崩溃] --> B[自定义崩溃处理器捕获] B --> C[保存全局变量到SharedPreferences] C --> D[保存崩溃日志到文件] D --> E[调用系统默认处理器] F[应用重启] --> G[Application初始化] G --> H[检查上次是否崩溃] H --> I{是} I --> J[恢复全局变量] ``` 通过以上方法,可以在Android程序崩溃时可靠地保存全局变量值,并在重启后恢复。对于更复杂的场景,建议结合使用`onSaveInstanceState`和ViewModel等组件实现多层次数据保护[^2][^4]。 --- §§相关问题§§ 1. 如何优化SharedPreferences在崩溃处理中的写入性能? 2. 除了SharedPreferences,还有哪些适合保存崩溃时全局变量的存储方式? 3. 如何避免因多次崩溃导致保存全局变量数据混乱? 4. 在Android多进程应用中如何实现崩溃时全局变量保存? 5. 如何将保存的崩溃日志自动发送给开发者服务器(参考引用[1])? </think> ### Android程序崩溃时保存全局变量的完整解决方案 在Android中实现程序崩溃时保存全局变量的核心方法是**自定义`Application`类**和**实现`UncaughtExceptionHandler`接口**。以下是详细实现方案: #### 、核心实现类与方法 ```mermaid classDiagram class CustomApplication { -static instance: CustomApplication -globalVar: String +onCreate() +saveGlobalData() +restoreGlobalData() } class CrashHandler { -defaultHandler: UncaughtExceptionHandler +uncaughtException(Thread, Throwable) } CustomApplication --|> Application CrashHandler ..|> UncaughtExceptionHandler ``` #### 二、具体实现步骤 **1. 创建自定义Application类**(参考引用[4]) ```java public class CustomApplication extends Application { private static CustomApplication instance; private String globalVar; // 示例全局变量 @Override public void onCreate() { super.onCreate(); instance = this; // 设置全局异常处理器(核心步骤) Thread.setDefaultUncaughtExceptionHandler(new CrashHandler()); // 恢复上次保存的变量 restoreGlobalData(); } public static CustomApplication getInstance() { return instance; } // 保存全局变量到SharedPreferences public void saveGlobalData() { SharedPreferences prefs = getSharedPreferences("global_data", MODE_PRIVATE); prefs.edit() .putString("global_var", globalVar) .apply(); // 使用apply()保证异步写入 } // 从SharedPreferences恢复全局变量 private void restoreGlobalData() { SharedPreferences prefs = getSharedPreferences("global_data", MODE_PRIVATE); globalVar = prefs.getString("global_var", "default_value"); } } ``` **2. 实现崩溃处理器**(参考引用[1][5]) ```java public class CrashHandler implements Thread.UncaughtExceptionHandler { private final Thread.UncaughtExceptionHandler defaultHandler; public CrashHandler() { this.defaultHandler = Thread.getDefaultUncaughtExceptionHandler(); } @Override public void uncaughtException(Thread thread, Throwable ex) { try { // 1. 保存全局变量 CustomApplication.getInstance().saveGlobalData(); // 2. 保存崩溃日志(可选) saveCrashLog(ex); // 参见引用[5] } catch (Exception e) { Log.e("CRASH_HANDLER", "保存数据失败", e); } finally { // 3. 调用默认处理器终止应用 defaultHandler.uncaughtException(thread, ex); } } // 保存崩溃日志到文件(参考引用[1][5]) private void saveCrashLog(Throwable ex) { String logPath = getExternalFilesDir(null) + "/crash_logs/"; // 实现日志保存逻辑... } } ``` **3. 配置AndroidManifest.xml**(参考引用[4]) ```xml <application android:name=".CustomApplication" ... > ... </application> ``` #### 三、关键增强措施 1. **确保数据可靠性**: ```java // 使用commit()替代apply()确保同步写入 prefs.edit().putString("key", value).commit(); ``` 注意:`commit()`会阻塞UI线程,但能保证崩溃前完成写入 2. **处理复杂对象**: ```java // 使用Gson序列化对象 Gson gson = new Gson(); String json = gson.toJson(complexObject); prefs.edit().putString("obj_key", json).apply(); ``` 3. **防止数据污染**(参考引用[2]): ```java // 应用正常退出时清除崩溃标志 @Override public void onTerminate() { getSharedPreferences("crash_flag", MODE_PRIVATE).edit() .remove("is_crashed").apply(); } ``` #### 四、替代方案比较 | 方法 | 适用场景 | 可靠性 | |--------------------|--------------------------|--------| | SharedPreferences | 简单数据类型 | ★★★☆ | | 文件存储 | 大数据/复杂对象 | ★★★★ | | SQLite数据库 | 结构化数据/需要查询 | ★★★★☆ | | ViewModel+保存状态 | 临时数据/配置变更 | ★★☆ | > **最佳实践**:关键数据采用`SharedPreferences`同步写入(`commit()`)+ 文件存储双重备份 #### 五、工作流程图 ```mermaid sequenceDiagram participant A as 应用程序 participant H as CrashHandler participant S as SharedPreferences A->>H: 发生未捕获异常 H->>S: 保存全局变量(commit()) H->>H: 保存崩溃日志 H->>A: 终止进程 A->>S: 重启后读取数据 S->>A: 恢复全局变量 ``` 通过此方案,即使应用崩溃也能可靠保存全局变量值,同时记录崩溃日志供分析[^1][^5]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值