
本文介绍一种面向抽象、可扩展的 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<Models.QueueDoc>>
}接着,重构 BaseActivity 为泛型基类,支持类型安全的 ViewModel 获取:
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);
}然后,为不同业务场景创建具体 ViewModel:
class QueueViewModel(private val repository: QueueRepository) : BaseActivityViewModel() {
private val _documents = MutableLiveData<List<Models.QueueDoc>>()
override val documents: LiveData<List<Models.QueueDoc>> = _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<Models.QueueDoc>>()
override val documents: LiveData<List<Models.QueueDoc>> = _documents
override fun loadDocuments(search: String) {
repository.loadAnotherDocuments(documentTypes, search) // 调用另一接口
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ _documents.value = it },
{ handleError(it) }
)
}
}对应地,子 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 层保持一致
}
}⚠️ 注意事项与最佳实践
- 避免在 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 的推荐实践。

















