warning :OnDestroy or PostNcDestroy in derived class will not be called

本文介绍了在应用程序中使用指针创建对话框时如何避免警告信息。正确的做法是在析构函数中先调用DestroyWindow()方法关闭对话框,然后使用delete操作符释放内存。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

应用程序中使用指针创建了对话框,在析构函数中使用delete时,会出现以下警告:

Warning: calling DestroyWindow in CDialog::~CDialog --
OnDestroy or PostNcDestroy in derived class will not be called.

我们在释放指针的时候应该先通过对话框指针调用DestroyWindow()方法,然后再用delete删除。

CDlg::~CDlg()
{
 if(m_pDlg!= NULL)
 {
  m_pDlg->DestroyWindow();
  delete m_pDlg;
 }
}

只有这样才可以把这个警告给去掉

 

备注:

       接了两次外包,发现有些问题,决定不再接外包了,第一:它影响到我的正常上班,第二:因为都是私人或是小公司的外包,无法像大公司一样,把需求,功能说清楚,以致做一下停一下,又有新功能又做一些,周期太长,钱太少。特别说明,已经不再接外包,如果接的话,就是牵个线了。

 

 

<think>嗯,用户这次的问题是关于Fragment在Activity重建时的状态保留,特别是替代setRetainInstance方法的现代方案。用户是Android开发者,显然正在处理配置变更导致的数据丢失问题,需要符合现代架构规范的解决方案。回顾之前的对话,用户已经了解Glide的SimpleTarget过时问题,说明ta对技术更新很敏感。这次的问题虽然不同领域,但同样涉及Android组件的生命周期管理。用户提到“参考站内引用”,但其实并没有具体引用内容,可能是误触发了某个功能,重点还是ta核心的Fragment保留问题。用户深层需求应该包括:1)完全替代setRetainInstance的官方方案2)保证数据不因屏幕旋转等操作丢失3)避免内存泄漏。尤其需要解释清楚ViewModel和ViewBinding的区别,因为两者都涉及状态保存但作用不同。这个问题的关键在于阐明ViewModel的生命周期范围:ViewModel本质上通过HolderFragment机制实现跨Activity重建存活,但不会跨进程存活(这点用户容易误解)。需要强调onCleared方法的资源释放重要性,否则可能造成内存泄漏。另外,viewModels和activityViewModels的scope差异需要重点说明,用户可能在多个Fragment共享数据时遇到问题。从技术深度看,用户应该是中级开发者(知道过时的retainInstance方法),但可能对现代Android架构组件不够熟悉。可以适当引入SavedStateHandle解决进程被杀后恢复数据的场景,这是用户可能尚未察觉但实际需要的高级功能。关于架构推荐,Google的MAD指南强调ViewModel+LiveData组合,这点必须作为核心方案。同时要警告两个常见陷阱:1)在ViewModel里持有context导致泄漏2)错误使用全局静态变量替代ViewModel。最后考虑生成的相关问题需要覆盖用户后续可能遇到的:1)Navigation组件中的状态保存2)大型数据的分页处理3)Hilt对ViewModel的注入支持等进阶场景。</think> 好的,Fragment 的 `setRetainInstance(true)` 方法是旧版 API 中用于在 `Activity` 因配置更改(如屏幕旋转)被销毁重建时保留 Fragment 实例的有效方式。但在现代 Android 开发(尤其是引入 Android Architecture Components 之后),它已被弃用,主要原因是: 1. **耦合性与安全性**:它使 Fragment 的生命周期与其宿主 Activity 的管理脱节,可能导致意料之外的行为或内存泄漏风险。 2. **现代替代品更优**:`ViewModel` 搭配 `SavedStateHandle` 或 `onSaveInstanceState(Bundle)` 提供了更灵活、可控且生命周期感知的状态管理方式,而且核心设计理念就是将状态管理与视图控制器(如 Activity/Fragment)分离[^1]。 ### ✅ 推荐的现代替代方案:使用 `ViewModel` + `SavedStateHandle` `ViewModel` 是 Jetpack 的核心组件,其设计目的就是**管理 UI 相关的数据,并在配置更改(如屏幕旋转)期间保持存活**。其生命周期范围通常由与之关联的 `ViewModelStoreOwner` (如 `Activity` 或 `Fragment`) 决定。 #### 🔧 核心步骤 1. **创建 `ViewModel`**: 在您的 Fragment (或 Activity) 中获取 ViewModel 实例: ```kotlin // 方式一:创建仅限当前 Fragment 使用的 ViewModel (如果 Activity 重建,该 Fragment 重新创建时会得到一个新的 ViewModel) private val myViewModel: MyViewModel by viewModels() // 方式二:创建与宿主 Activity 共享范围的 ViewModel (Activity 重建后,新的 Fragment 仍能访问同一个 ViewModel 实例) private val sharedViewModel: SharedViewModel by activityViewModels() ``` 2. **在 `ViewModel` 中存储关键数据**: 将您希望在 Activity 重建后保留的数据存储在 ViewModel 的内部属性中: ```kotlin class MyViewModel : ViewModel() { val myLiveData: MutableLiveData<String> = MutableLiveData() var myImportantValue: Int = 0 // ... 其他需要保留的数据 } ``` 📌 **关键点**:当宿主 Activity 因配置更改被销毁时,关联的 `ViewModel` 实例**不会**被销毁。之后当 Activity (以及其中的 Fragment) 被重建时,系统会**提供相同的 ViewModel 实例**[^2]。 3. **在 Fragment 中使用 ViewModel 数据**: 在 Fragment 的 `onViewCreated` 或 `onActivityCreated` 中,观察 ViewModel 暴露的数据(如 `LiveData`): ```kotlin override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) myViewModel.myLiveData.observe(viewLifecycleOwner) { newValue -> // 更新 UI 以反映 newValue } // 如果是直接访问属性,确保值已初始化 myImportantTextView.text = myViewModel.myImportantValue.toString() } ``` 4. **处理进程终止的场景(可选但推荐)—— `SavedStateHandle`**: 如果应用在后台因系统资源紧张被**终止进程**,那么仅靠 ViewModel 本身的数据也会丢失,因为 ViewModel 只保证在内存中存活。 - 使用 `SavedStateHandle` 可以**保存并恢复少量轻量级的关键数据**(如 ID、滚动位置),这些数据会在进程终止后重建时恢复: ```kotlin class MyViewModel(savedStateHandle: SavedStateHandle) : ViewModel() { // 创建一个由 SavedStateHandle 支持的键值对存储 val myKey: MutableStateFlow<String?> = savedStateHandle.getStateFlow("myKey", null) // ... 其他数据 } ``` `SavedStateHandle` 会自动将底层 `Bundle` 中的数据在配置更改和进程重建时保存与恢复。 5. **资源清理(重要!)**: `ViewModel` 有一个名为 `onCleared()` 的生命周期回调方法。当其关联的 `ViewModelStore` 被永久销毁(通常是其宿主 Activity/Fragment 被**真正**销毁,而非因配置更改重建)时,这个方法会被调用。在此方法中释放任何需要释放的资源(如取消协程、关闭数据库连接等): ```kotlin override fun onCleared() { super.onCleared() myResource.close() // 关闭数据库连接、取消网络请求等 } ``` ### 📊 与 `setRetainInstance(true)` 的对比总结 | 特性 | `setRetainInstance(true)` | `ViewModel` (替代方案) | | :----------------- | :------------------------------------------ | :----------------------------------------- | | **配置更改保留** | ✅ `Fragment` 实例不销毁 | ✅ `ViewModel` 实例不销毁 | | **进程终止保留** | ❌ 数据丢失 | ❌(需配合 `SavedStateHandle` 实现✅) | | **耦合性** | ❌ 高 (Fragment 与其状态强绑定) | ✅ 低 (状态独立于 UI 控制器) | | **生命周期感知** | ❌ 基本没有 | ✅ 强 (自动感知组件销毁) | | **资源清理机制** | ❌ `onDestroy()` (逻辑复杂且不可靠) | ✅ 明确的 `onCleared()` 方法 | | **现代性/推荐度** | ❌ 已弃用,不推荐在新项目中使用 | ✅ 官方推荐的标准模式 | | **作用范围** | ❔ 仅限于单个 Fragment | ⭐ 可在 Activity、Fragment 间共享范围 | ### 💡 建议的最佳实践 1. **优先使用 `ViewModel`**: 将 Activity/Fragment 重建后需要保留的**UI相关数据**(网络响应、用户输入进度等)存储在 `ViewModel` 中[^2]。 2. **配合 `SavedStateHandle` 处理进程重建**: 在 ViewModel 构造器中使用 `SavedStateHandle`,以支持进程被系统终止后的数据恢复,保存少量必要的状态(如导航参数、滚动位置)。这些数据通常不应过大过重[^3]。 3. **避免在 `ViewModel` 中持有视图引用**: 绝对不要在 ViewModel 中持有 `Context`, `Activity`, `Fragment`, `View` 或其任何引用,这会导致严重的内存泄漏。ViewModel 的生命周期可能比其关联的 UI 控制器更长[^4]。 4. **利用 `LiveData`, `Flow` 等实现观察**: 在 ViewModel 中暴露数据时使用 `LiveData` 或 `StateFlow`/`SharedFlow`,并在 Fragment/Activity 中使用 `LifecycleOwner` (如 `viewLifecycleOwner`) 安全地观察它们[^4]。 5. **大型数据源使用 Repository + ViewModel**: 如果需要管理复杂或持久化的数据源(如数据库、网络),请遵循 Repository 模式,ViewModel 作为 UI 层与数据层之间的中介,通过调用 Repository 获取/更新数据[^5]。 总之,**弃用 `setRetainInstance` 并用 `ViewModel`(配合 `SavedStateHandle` 处理进程重建)来替代,是 Google 官方推动现代、安全且解耦的 Android 应用架构的必然选择**。这种方式既能安全地跨配置更改保持状态,又能通过显式的 `SavedState` 机制支持进程重建,同时避免了旧方法潜在的生命周期耦合问题[^1][^2][^3]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值