子类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:
- 修改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) } } }
- 修改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); }
- 子类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调用部分,符合开闭原则,适合长期维护:
- 修改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) } }
- 创建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(""); } }
- 修改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(); } ); } }
- 实现子类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
相关产品推荐
相关产品推荐

