如何在子 Activity 中正确复用并扩展 ViewModel 功能

星敏小哥_1572

星敏小哥_1572

2026-07-21

804人浏览

原创

如何在子 Activity 中正确复用并扩展 ViewModel 功能

本文介绍一种面向抽象、可扩展的 viewmodel 使用模式:通过定义抽象基类 viewmodel 和泛型 baseactivity,使子 activity 能安全复用公共逻辑,同时独立实现差异化业务(如调用不同 retrofit 接口),避免代码重复与紧耦合。

本文介绍一种面向抽象、可扩展的 viewmodel 使用模式:通过定义抽象基类 viewmodel 和泛型 baseactivity,使子 activity 能安全复用公共逻辑,同时独立实现差异化业务(如调用不同 retrofit 接口),避免代码重复与紧耦合。

在 Android 架构实践中,当多个 Activity 共享基础功能(如文档列表加载、状态观察、错误处理)但需调用不同后端接口时,直接继承 QueueViewModel 并重写方法往往导致职责混乱或破坏单一职责原则。更合理的方式是分离契约与实现:定义清晰的抽象层,让每个具体 Activity 持有专属 ViewModel 实例,同时复用底层 Repository、生命周期感知机制和 UI 状态管理逻辑。

✅ 推荐方案:抽象 ViewModel + 泛型 BaseActivity

首先,定义统一的行为契约:

// 抽象 ViewModel 基类 —— 仅声明能力,不包含具体实现
abstract class BaseActivityViewModel : ViewModel() {
    abstract fun loadDocuments(search: String = "")
    abstract val documents: LiveData<list>>
}</list>

接着,重构 BaseActivity 为泛型基类,支持类型安全的 ViewModel 获取:

Moltbot
Moltbot

一款AI开发辅助工具,主要用于开源的自托管AI智能体助手,自动化执行系统级任务,适合需要提升相关任务效率的用户。

下载
public abstract class BaseActivity<vm extends baseactivityviewmodel> extends AppCompatActivity {
    private Class<vm> viewModelClass;

    @SuppressWarnings("unchecked")
    public BaseActivity() {
        this.viewModelClass = (Class<vm>) ((ParameterizedType) getClass()
                .getGenericSuperclass()).getActualTypeArguments()[0];
    }

    protected ViewModelProvider.Factory getViewModelFactory() {
        return null; // 子类可选择性提供自定义 Factory
    }

    protected final VM viewModel;

    {
        ViewModelProvider provider = new ViewModelProvider(this, getViewModelFactory());
        this.viewModel = provider.get(viewModelClass);
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 自动观察 documents,子类无需重复编写
        viewModel.documents.observe(this, docs -> showDocuments(docs));
    }

    protected abstract void showDocuments(List<models.queuedoc> docs);
}</models.queuedoc></vm></vm></vm>

然后,为不同业务场景创建具体 ViewModel:

class QueueViewModel(private val repository: QueueRepository) : BaseActivityViewModel() {
    private val _documents = MutableLiveData<list>>()
    override val documents: LiveData<list>> = _documents

    override fun loadDocuments(search: String) {
        repository.loadDocuments(documentTypes, search)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                { _documents.value = it },
                { handleError(it) }
            )
    }
}

class AnotherQueueViewModel(private val repository: QueueRepository) : BaseActivityViewModel() {
    private val _documents = MutableLiveData<list>>()
    override val documents: LiveData<list>> = _documents

    override fun loadDocuments(search: String) {
        repository.loadAnotherDocuments(documentTypes, search) // 调用另一接口
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                { _documents.value = it },
                { handleError(it) }
            )
    }
}</list></list></list></list>

对应地,子 Activity 只需指定泛型并实现 UI 回调:

class MainQueueActivity : BaseActivity<queueviewmodel>() {
    override fun getViewModelFactory(): ViewModelProvider.Factory {
        return QueueViewModelFactory(documentTypes)
    }

    override fun showDocuments(docs: List<models.queuedoc>) {
        // 更新 RecyclerView 或其他 UI 组件
    }
}

class AnotherQueueActivity : BaseActivity<anotherqueueviewmodel>() {
    override fun getViewModelFactory(): ViewModelProvider.Factory {
        return AnotherQueueViewModelFactory(documentTypes)
    }

    override fun showDocuments(docs: List<models.queuedoc>) {
        // 同样复用 showDocuments 逻辑,UI 层保持一致
    }
}</models.queuedoc></anotherqueueviewmodel></models.queuedoc></queueviewmodel>

⚠️ 注意事项与最佳实践

  • 避免在 ViewModel 中持有 Activity/Context 引用:确保 QueueRepository 是无状态的,所有依赖(如 Retrofit Service)通过构造注入;
  • Factory 的必要性:若 ViewModel 需要参数(如 documentTypes),必须提供自定义 ViewModelProvider.Factory,否则 ViewModelProvider(this).get(...) 将抛出异常;
  • LiveData 复用安全:documents 在基类中统一观察,子类只需关注数据展示逻辑,避免重复订阅/解订阅;
  • 扩展性保障:未来新增第三种队列类型(如 listPendingDocQueue),只需新增一个 ViewModel 实现,完全不影响现有类;
  • 测试友好:每个 ViewModel 可独立单元测试,Mock Repository 即可验证业务逻辑。

该方案兼顾了 DRY 原则与开闭原则——基类封装不变逻辑,子类专注变化点,是 MVVM 架构下多 Activity 复用 ViewModel 的推荐实践。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
android开发三大框架
android开发三大框架

android开发三大框架是XUtil框架、volley框架、ImageLoader框架。本专题为大家提供android开发三大框架相关的各种文章、以及下载和课程。

2023.08.14

902

4

android是什么系统
android是什么系统

Android是一种功能强大、灵活可定制、应用丰富、多任务处理能力强、兼容性好、网络连接能力强的操作系统。本专题为大家提供android相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.22

2587

5

android权限限制怎么解开
android权限限制怎么解开

android权限限制可以使用Root权限、第三方权限管理应用程序、ADB命令和Xposed框架解开。详细介绍:1、Root权限,通过获取Root权限,用户可以解锁所有权限,并对系统进行自定义和修改;2、第三方权限管理应用程序,用户可以轻松地控制和管理应用程序的权限;3、ADB命令,用户可以在设备上执行各种操作,包括解锁权限;4、Xposed框架,用户可以在不修改系统文件的情况下修改应用程序的行为和权限。

2023.09.19

4877

7

android重启应用的方法有哪些
android重启应用的方法有哪些

android重启应用有通过Intent、PendingIntent、系统服务、Runtime等方法。本专题为大家提供Android相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.18

625

5

Android语音播放功能实现方法
Android语音播放功能实现方法

实现方法有使用MediaPlayer实现、使用SoundPool实现两种。可以根据具体的需求选择适合的方法进行实现。想了解更多语音播放的相关内容,可以阅读本专题下面的文章。

2024.03.01

944

5

FrankenPHP集成Laravel详细教程
FrankenPHP集成Laravel详细教程

本专题提供FrankenPHP集成Laravel的详细配置指南,全面解析运行原理、开发环境搭建、Caddyfile配置、Octane工作模式、数据库连接、队列任务、定时任务和生产环境优化,解决部署过程中常见的报错与兼容性问题。

2026.10.08

40

20

LLVM自定义Pass怎么写
LLVM自定义Pass怎么写

本专题聚焦LLVM自定义Pass开发,整理Pass类结构、run()方法、PreservedAnalyses、CMake构建、插件注册、-load-pass-plugin加载和测试用例编写流程。

2026.09.30

140

10

LLVM RISC-V参数配置教程
LLVM RISC-V参数配置教程

本专题介绍LLVM对RISC-V基础ISA和扩展的支持方式,涵盖RV32、RV64、标准扩展、实验性扩展、厂商扩展、-menable-experimental-extensions和版本差异。

2026.09.30

140

14

LLVM IR中间表示入门指南
LLVM IR中间表示入门指南

本专题整理LLVM IR的核心概念,包括中间表示作用、模块结构、函数、基本块、SSA形式、类型系统和常见语法,帮助新手理解LLVM编译流程中的关键层。

2026.09.30

100

12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.4万人学习