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

子类Activity复用Base ViewModel调用不同API的正确实现方式

问题描述

我的应用包含一个抽象Activity类BaseQueueActivity,它实现了Activity所需的大部分功能,同时使用QueueViewModel类和QueueRepository类。现在需要创建一个子类Activity,使其调用另一个API方法listAnotherDocQueue(替代原有的listDocQueue)。请问正确的实现方式是什么?是否需要创建子类ViewModel并重写loadDocuments方法?我需要保留父ViewModel中的其他代码。


现有代码片段

基础Activity代码

public abstract class BaseQueueActivity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        viewModel = new ViewModelProvider(this, new QueueViewModelFactory(documentTypes)).get(QueueViewModel.class);

        viewModel.documents.observe(
                this,
                response -> {
                    showDocuments();
                }
        );
    }
}

ViewModel代码

public class QueueViewModel extends ViewModel {
    final private QueueRepository repository = new QueueRepository();

    private final MutableLiveData<ArrayList<Models.QueueDoc>> _documents = new MutableLiveData<>();
    public LiveData<ArrayList<Models.QueueDoc>> documents = _documents;

    public QueueViewModel() {
    }

    public void loadDocuments() {
        loadDocuments("");
    }
    public void loadDocuments(String search) {
        Single<ArrayList<Models.QueueDoc>> response = repository.loadDocuments(_documentTypes.getValue(), search);
        Disposable disposable = response
            .subscribeOn(Schedulers.io())
            .subscribe(
                it -> {
                    _documents.postValue(it);
                },
                it -> {
                    // some error handling
                }
            );
    }
}

Repository代码

class QueueRepository {
    fun loadDocuments(documentTypes: ArrayList<DocumentType>, search: String) {
        return RESTConnection.getService().listDocQueue(documentTypesString, search)
    }
}

Retrofit API代码(存在方法名冲突问题)

@GET("listDocQueue/{DocType}/{Search}")
Single<ArrayList<Models.QueueDoc>> listDocQueue(
        @Path("DocType") String DocType,
        @Path("Search") String search);

@GET("listAnotherDocQueue/{DocType}/{Search}")
// 注意:此处方法名与上方重复,需修改为listAnotherDocQueue
Single<ArrayList<Models.QueueDoc>> listDocQueue(
        @Path("DocType") String DocType,
        @Path("Search") String search);

解决方案

首先需要修复Retrofit接口的方法名冲突问题,否则编译会报错:

@GET("listDocQueue/{DocType}/{Search}")
Single<ArrayList<Models.QueueDoc>> listDocQueue(
        @Path("DocType") String DocType,
        @Path("Search") String search);

@GET("listAnotherDocQueue/{DocType}/{Search}")
Single<ArrayList<Models.QueueDoc>> listAnotherDocQueue(
        @Path("DocType") String DocType,
        @Path("Search") String search);

以下提供两种可行方案,优先推荐方案二,因为更符合开闭原则且不破坏父类原有逻辑:


方案一:扩展Repository,通过参数切换API调用(无需创建ViewModel子类)

这种方式改动小,适合简单场景,通过给Repository增加参数控制调用目标API:

  1. 修改QueueRepository,新增API类型枚举和对应逻辑:
enum class QueueApiType {
    DEFAULT, ANOTHER
}

class QueueRepository {
    fun loadDocuments(documentTypes: ArrayList<DocumentType>, search: String, apiType: QueueApiType = QueueApiType.DEFAULT) {
        val service = RESTConnection.getService()
        return when(apiType) {
            QueueApiType.DEFAULT -> service.listDocQueue(documentTypesString, search)
            QueueApiType.ANOTHER -> service.listAnotherDocQueue(documentTypesString, search)
        }
    }
}
  1. 修改QueueViewModel,新增重载方法支持指定API类型:
// 新增重载方法,允许指定API类型
public void loadDocuments(String search, QueueApiType apiType) {
    Single<ArrayList<Models.QueueDoc>> response = repository.loadDocuments(_documentTypes.getValue(), search, apiType);
    Disposable disposable = response
        .subscribeOn(Schedulers.io())
        .subscribe(
            it -> {
                _documents.postValue(it);
            },
            it -> {
                // 复用原有错误处理逻辑
            }
        );
}

// 保留原有方法,默认调用DEFAULT类型
public void loadDocuments() {
    loadDocuments("", QueueApiType.DEFAULT);
}
public void loadDocuments(String search) {
    loadDocuments(search, QueueApiType.DEFAULT);
}
  1. 子类Activity调用指定API的加载方法:
public class AnotherQueueActivity extends BaseQueueActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewModel.loadDocuments("", QueueApiType.ANOTHER);
    }
}

方案二:创建ViewModel子类,重写loadDocuments方法(推荐)

这种方式完全复用父ViewModel的LiveData、错误处理等逻辑,仅替换API调用部分,符合开闭原则,适合长期维护:

  1. 修改QueueRepository,新增调用另一个API的方法:
class QueueRepository {
    fun loadDocuments(documentTypes: ArrayList<DocumentType>, search: String) {
        return RESTConnection.getService().listDocQueue(documentTypesString, search)
    }

    // 新增方法调用目标API
    fun loadAnotherDocuments(documentTypes: ArrayList<DocumentType>, search: String) {
        return RESTConnection.getService().listAnotherDocQueue(documentTypesString, search)
    }
}
  1. 创建QueueViewModel的子类,重写loadDocuments方法:
public class AnotherQueueViewModel extends QueueViewModel {
    @Override
    public void loadDocuments(String search) {
        Single<ArrayList<Models.QueueDoc>> response = repository.loadAnotherDocuments(_documentTypes.getValue(), search);
        Disposable disposable = response
            .subscribeOn(Schedulers.io())
            .subscribe(
                it -> {
                    _documents.postValue(it); // 复用父类的MutableLiveData
                },
                it -> {
                    // 复用父类错误处理逻辑,或自定义
                }
            );
    }

    @Override
    public void loadDocuments() {
        loadDocuments("");
    }
}
  1. 修改BaseQueueActivity,允许子类指定ViewModel类型:
public abstract class BaseQueueActivity{
    protected QueueViewModel viewModel;

    // 抽象方法,让子类返回对应的ViewModel类
    protected abstract Class<? extends QueueViewModel> getViewModelClass();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        viewModel = new ViewModelProvider(this, new QueueViewModelFactory(documentTypes)).get(getViewModelClass());

        viewModel.documents.observe(
                this,
                response -> {
                    showDocuments();
                }
        );
    }
}
  1. 实现子类Activity:
public class AnotherQueueActivity extends BaseQueueActivity {
    @Override
    protected Class<? extends QueueViewModel> getViewModelClass() {
        return AnotherQueueViewModel.class;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewModel.loadDocuments(); // 自动调用子类重写后的方法,切换到目标API
    }
}

方案对比

  • 方案一:改动小,适合临时需求,但ViewModel会增加额外参数,职责不够单一。
  • 方案二:符合面向对象设计,每个ViewModel对应一种业务场景,父类逻辑完全复用,扩展更清晰,适合长期维护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 00:55:04