refactor(mvvm): 重构 BaseViewModel 依赖注入并移除 ViewDataBindingCallback 接口

This commit is contained in:
tongtong committed 2026-10-29 10:06:42 +08:00
1 parent 8a3ac6f5b4
commit 497af25e2e
13 files changed
+142 -165

No files matched your search

@@ -71,9 +71,6 @@ public class DebugActivity extends BaseMvvmActivity<DebugViewModel, ActivityDebu
@Override
protected void initDataBinding() {
mViewModel.setCtx(this);
mViewModel.setLifecycle(getLifecycleSubject());
mViewModel.setVDBinding(mViewDataBinding);
mViewDataBinding.setClick(new BtnClick());
}
@@ -2,17 +2,6 @@ package com.aoleyun.sn.activity.debug;
import com.aoleyun.sn.base.mvvm.BaseViewModel;
import com.aoleyun.sn.databinding.ActivityDebugBinding;
import com.trello.rxlifecycle4.android.ActivityEvent;
public class DebugViewModel extends BaseViewModel<ActivityDebugBinding, ActivityEvent> {
@Override
public ActivityDebugBinding getVDBinding() {
return binding;
}
@Override
public void onDestroy() {
}
public class DebugViewModel extends BaseViewModel<ActivityDebugBinding> {
}
@@ -167,7 +167,7 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
}
@Override
public int getLayoutId() {
protected int getLayoutId() {
return R.layout.activity_main;
}
@@ -178,14 +178,11 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
@Override
protected void initDataBinding() {
mViewModel.setCtx(this);
mViewModel.setLifecycle(getLifecycleSubject());
mViewModel.setVDBinding(mViewDataBinding);
mViewDataBinding.setClick(new BtnClick());
}
@Override
public void initView() {
protected void initView() {
if (BuildConfig.DEBUG) {
// Uri uri = Uri.parse("https://www.baidu.com");
// Intent intent = new Intent(Intent.ACTION_VIEW, uri);
@@ -371,7 +368,7 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
}
@Override
public void initData() {
protected void initData() {
Log.e("getMacAddress", Utils.getAndroid10MAC(this));
Intent intent = new Intent(MainActivity.this, MainService.class);
bindService(intent, serviceConnect, BIND_AUTO_CREATE);
@@ -41,19 +41,9 @@ import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
public class MainViewModel extends BaseViewModel<ActivityMainBinding, ActivityEvent> {
public class MainViewModel extends BaseViewModel<ActivityMainBinding> {
private static final String TAG = "MainViewModel";
@Override
public ActivityMainBinding getVDBinding() {
return binding;
}
@Override
public void onDestroy() {
}
public void init() {
checkUpdateInfo();
checkAoleyunUpdate();
@@ -19,7 +19,7 @@ public class RequestLogActivity extends BaseMvvmActivity<RequestLogViewModel, Ac
private RequestLogAdapter mAdapter;
@Override
public int getLayoutId() {
protected int getLayoutId() {
return R.layout.activity_request_log;
}
@@ -30,21 +30,18 @@ public class RequestLogActivity extends BaseMvvmActivity<RequestLogViewModel, Ac
@Override
protected void initDataBinding() {
mViewModel.setCtx(this);
mViewModel.setLifecycle(getLifecycleSubject());
mViewModel.setVDBinding(mViewDataBinding);
mViewDataBinding.setClick(new BtnClick());
}
@Override
public void initView() {
protected void initView() {
mViewDataBinding.recyclerview.setLayoutManager(new LinearLayoutManager(this));
mAdapter = new RequestLogAdapter();
mViewDataBinding.recyclerview.setAdapter(mAdapter);
}
@Override
public void initData() {
protected void initData() {
mViewModel.getLogBeanListData().observe(this, new Observer<List<LogBean>>() {
@Override
public void onChanged(List<LogBean> logBeans) {
@@ -6,29 +6,18 @@ import com.aoleyun.sn.base.mvvm.BaseViewModel;
import com.aoleyun.sn.databinding.ActivityRequestLogBinding;
import com.aoleyun.sn.rlog.LogBean;
import com.aoleyun.sn.rlog.LogDBManager;
import com.trello.rxlifecycle4.android.ActivityEvent;
import java.util.List;
public class RequestLogViewModel extends BaseViewModel<ActivityRequestLogBinding, ActivityEvent> {
public class RequestLogViewModel extends BaseViewModel<ActivityRequestLogBinding> {
@Override
public ActivityRequestLogBinding getVDBinding() {
return binding;
}
@Override
public void onDestroy() {
}
private MutableLiveData<List<LogBean>> mLogBeanListData =new MutableLiveData<>();
private final MutableLiveData<List<LogBean>> mLogBeanListData = new MutableLiveData<>();
public MutableLiveData<List<LogBean>> getLogBeanListData() {
return mLogBeanListData;
}
public void getDBList(){
public void getDBList() {
mLogBeanListData.setValue(LogDBManager.getInstance().getLogList());
}
}
@@ -1,5 +1,7 @@
package com.aoleyun.sn.activity.update;
import static com.arialyy.aria.core.inf.IEntity.STATE_RUNNING;
import android.content.Intent;
import android.view.View;
@@ -17,8 +19,6 @@ import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.hjq.toast.Toaster;
import static com.arialyy.aria.core.inf.IEntity.STATE_RUNNING;
public class AppUpdateActivity extends BaseMvvmActivity<AppUpdateViewModel, ActivityAppUpdateBinding> {
private AppUpdateInfo mAppInfoData;
@@ -31,9 +31,6 @@ public class AppUpdateActivity extends BaseMvvmActivity<AppUpdateViewModel, Acti
@Override
protected void initDataBinding() {
mViewModel.setCtx(this);
mViewModel.setLifecycle(getLifecycleSubject());
mViewModel.setVDBinding(mViewDataBinding);
mViewDataBinding.setClick(new BtnClick());
}
@@ -1,18 +1,7 @@
package com.aoleyun.sn.activity.update;
import com.trello.rxlifecycle4.android.ActivityEvent;
import com.aoleyun.sn.base.mvvm.BaseViewModel;
import com.aoleyun.sn.databinding.ActivityAppUpdateBinding;
public class AppUpdateViewModel extends BaseViewModel<ActivityAppUpdateBinding, ActivityEvent> {
@Override
public ActivityAppUpdateBinding getVDBinding() {
return binding;
}
@Override
public void onDestroy() {
}
public class AppUpdateViewModel extends BaseViewModel<ActivityAppUpdateBinding> {
}
@@ -25,7 +25,7 @@ public class UpdateActivity extends BaseMvvmActivity<UpdateViewModel, ActivityUp
private AppUpdateAdapter mAppUpdateAdapter;
@Override
public int getLayoutId() {
protected int getLayoutId() {
return R.layout.activity_update;
}
@@ -36,21 +36,18 @@ public class UpdateActivity extends BaseMvvmActivity<UpdateViewModel, ActivityUp
@Override
protected void initDataBinding() {
mViewModel.setCtx(this);
mViewModel.setLifecycle(getLifecycleSubject());
mViewModel.setVDBinding(mViewDataBinding);
mViewDataBinding.setClick(new BtnClick());
}
@Override
public void initView() {
protected void initView() {
mAppUpdateAdapter = new AppUpdateAdapter();
mViewDataBinding.recyclerView.setLayoutManager(new LinearLayoutManager(UpdateActivity.this));
mViewDataBinding.recyclerView.setAdapter(mAppUpdateAdapter);
}
@Override
public void initData() {
protected void initData() {
mViewModel.getAppUpdateInfoListData().observe(this, new Observer<List<AppUpdateInfo>>() {
@Override
public void onChanged(List<AppUpdateInfo> appUpdateInfos) {
@@ -6,23 +6,12 @@ import com.aoleyun.sn.base.mvvm.BaseViewModel;
import com.aoleyun.sn.bean.AppUpdateInfo;
import com.aoleyun.sn.databinding.ActivityUpdateBinding;
import com.aoleyun.sn.network.NetInterfaceManager;
import com.trello.rxlifecycle4.android.ActivityEvent;
import java.util.List;
public class UpdateViewModel extends BaseViewModel<ActivityUpdateBinding, ActivityEvent> {
public class UpdateViewModel extends BaseViewModel<ActivityUpdateBinding> {
@Override
public ActivityUpdateBinding getVDBinding() {
return binding;
}
@Override
public void onDestroy() {
}
private MutableLiveData<List<AppUpdateInfo>> mAppUpdateInfoListData = new MutableLiveData<>();
private final MutableLiveData<List<AppUpdateInfo>> mAppUpdateInfoListData = new MutableLiveData<>();
public MutableLiveData<List<AppUpdateInfo>> getAppUpdateInfoListData() {
return mAppUpdateInfoListData;
@@ -1,45 +1,91 @@
package com.aoleyun.sn.base.mvvm;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.CallSuper;
import androidx.annotation.Nullable;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import com.aoleyun.sn.base.BaseTransparentActivity;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public abstract class BaseMvvmActivity<VM extends ViewModel, VDB extends ViewDataBinding> extends BaseTransparentActivity {
private static final String TAG = "BaseMvvmActivity";
/**
* MVVM Activity 基类。
*
* <p>子类按 {@code BaseMvvmActivity<VM, VDB>} 声明泛型后,基类会在 onCreate 中自动完成:</p>
* <ul>
* <li>加载布局并创建 ViewDataBinding,设置 lifecycleOwner;</li>
* <li>通过 ViewModelProvider 创建并复用 ViewModel;</li>
* <li>为 ViewModel 注入 Binding / Application Context / 页面生命周期。</li>
* </ul>
*
* @param <VM> 页面 ViewModel,必须继承 {@link BaseViewModel}
* @param <VDB> 页面 ViewDataBinding
*/
public abstract class BaseMvvmActivity<VM extends BaseViewModel<VDB>, VDB extends ViewDataBinding>
extends BaseTransparentActivity {
protected VM mViewModel;
protected VDB mViewDataBinding;
protected Class<VM> vmClass;
@Override
@CallSuper
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//ViewDataBinding
mViewDataBinding = DataBindingUtil.setContentView(this, getLayoutId());
mViewDataBinding.setLifecycleOwner(this);
//ViewModel
vmClass = (Class<VM>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
boolean isAbstract = Modifier.isAbstract(vmClass.getModifiers());
Log.e(TAG, "isLocalClass:" + vmClass.getSimpleName().equals(ViewModel.class.getSimpleName()) + " isAbstract:" + isAbstract);
if (!isAbstract) {//不是一个抽象类
mViewModel = new ViewModelProvider(this).get(vmClass);
}
mViewModel = new ViewModelProvider(this).get(resolveViewModelClass());
mViewModel.attach(mViewDataBinding, this, getLifecycleSubject());
initDataBinding();
initView();
initData();
}
protected abstract void initDataBinding();
@Override
@CallSuper
protected void onDestroy() {
if (mViewModel != null) {
mViewModel.detach(mViewDataBinding);
}
mViewDataBinding = null;
super.onDestroy();
}
/**
* 从泛型声明中解析 ViewModel 类型,支持子类之间存在多层继承。
*/
@SuppressWarnings("unchecked")
private Class<VM> resolveViewModelClass() {
Class<?> clazz = getClass();
while (clazz != null && clazz != BaseMvvmActivity.class) {
Type genericSuperclass = clazz.getGenericSuperclass();
if (genericSuperclass instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
if (parameterizedType.getRawType() == BaseMvvmActivity.class) {
Type[] typeArguments = parameterizedType.getActualTypeArguments();
if (typeArguments[0] instanceof Class) {
return (Class<VM>) typeArguments[0];
}
}
}
clazz = clazz.getSuperclass();
}
throw new IllegalStateException("无法解析 ViewModel 类型,请检查 "
+ getClass().getName() + " 是否声明为 BaseMvvmActivity<VM, VDB>");
}
/**
* binding 相关初始化(如 setClick / setXxx),此时 ViewModel 已完成注入
*/
protected void initDataBinding() {
}
/**
* 初始化视图
@@ -2,70 +2,92 @@ package com.aoleyun.sn.base.mvvm;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.databinding.ViewDataBinding;
import androidx.lifecycle.ViewModel;
import java.lang.ref.WeakReference;
import com.trello.rxlifecycle4.android.ActivityEvent;
import io.reactivex.rxjava3.subjects.BehaviorSubject;
/**
* 所有viewmodel的基类
* 所有 ViewModel 的基类。
*
* <p>Binding、Application Context、页面生命周期均由 {@link BaseMvvmActivity}
* 在 onCreate 时自动注入,子类无需(也不应该)手动设置这些依赖。</p>
*
* @param <VDB> 该 ViewModel 对应的 ViewDataBinding 类型
*/
public abstract class BaseViewModel<VDB extends ViewDataBinding, T> extends ViewModel implements ViewDataBindingCallback {
public abstract class BaseViewModel<VDB extends ViewDataBinding> extends ViewModel {
/**
* 当前viewmodel对应的页面binding
* 当前页面 binding,页面销毁时会被置空
*/
protected VDB binding;
@Nullable
private VDB binding;
@Override
public void setVDBinding(ViewDataBinding vdBinding) {
/**
* Application Context,避免持有 Activity 造成内存泄漏
*/
@Nullable
private Context appContext;
binding = (VDB) vdBinding;
/**
* 页面生命周期(RxLifecycle)
*/
@Nullable
private BehaviorSubject<ActivityEvent> lifecycleSubject;
/**
* 由 {@link BaseMvvmActivity} 调用,完成依赖注入。
*/
final void attach(@NonNull VDB binding,
@NonNull Context context,
@NonNull BehaviorSubject<ActivityEvent> lifecycleSubject) {
this.binding = binding;
this.appContext = context.getApplicationContext();
this.lifecycleSubject = lifecycleSubject;
}
@Override
public VDB getVDBinding() {
if (binding == null) {
throw new NullPointerException("BaseViewModel >> getVDBinding >> null!!!");
/**
* 页面销毁时解除 binding 引用,避免 ViewModel 在配置变更后持有已销毁的视图。
*/
final void detach(@Nullable VDB vdBinding) {
if (this.binding == vdBinding) {
this.binding = null;
}
}
/**
* @return 当前页面 binding,页面销毁后返回 null
*/
@Nullable
public final VDB getBinding() {
return binding;
}
/**
* @return Application Context,ViewModel 被回收后返回 null
*/
@Nullable
public final Context getCtx() {
return appContext;
}
/**
* 上下文
* @return 页面生命周期,用于 RxLifecycle 绑定
*/
private WeakReference<Context> ctx;
@Override
public void setCtx(Context context) {
if (ctx == null) {
ctx = new WeakReference<>(context);
}
@Nullable
public final BehaviorSubject<ActivityEvent> getLifecycle() {
return lifecycleSubject;
}
@Override
public Context getCtx() {
if (ctx == null) {
throw new NullPointerException("BaseViewModel >> getCtx >> null!!!");
}
return ctx.get();
}
public abstract void onDestroy();
private BehaviorSubject<T> mBehaviorSubject;
@Override
public void setLifecycle(BehaviorSubject subject) {
this.mBehaviorSubject = (BehaviorSubject<T>) subject;
}
@Override
public BehaviorSubject<T> getLifecycle() {
return mBehaviorSubject;
protected void onCleared() {
binding = null;
appContext = null;
lifecycleSubject = null;
super.onCleared();
}
}
@@ -1,22 +0,0 @@
package com.aoleyun.sn.base.mvvm;
import android.content.Context;
import androidx.databinding.ViewDataBinding;
import io.reactivex.rxjava3.subjects.BehaviorSubject;
public interface ViewDataBindingCallback<VDB extends ViewDataBinding, T> {
void setVDBinding(VDB binding);
VDB getVDBinding() throws NullPointerException;
void setCtx(Context context);
Context getCtx() throws NullPointerException;
void setLifecycle(BehaviorSubject<T> subject);
BehaviorSubject<T> getLifecycle();
}