Bläddra i källkod

集成ViewModel

詹子聪 5 år sedan
förälder
incheckning
9602543cba

+ 7 - 2
app/src/main/java/com/miekir/newmvp/MainActivity.java

@@ -7,12 +7,16 @@ import android.view.View;
 
 import com.miekir.mvp.presenter.DataMethod;
 import com.miekir.mvp.presenter.InjectPresenter;
-import com.miekir.mvp.view.BaseMVPActivity;
+import com.miekir.mvp.presenter.InjectViewModel;
+import com.miekir.mvp.view.model.BaseMVPActivity;
 
 public class MainActivity extends BaseMVPActivity {
     @InjectPresenter
     TestPresenter1 presenter1;
 
+    @InjectViewModel
+    TestViewModel1 viewModel1;
+
     @Override
     public int getLayoutID() {
         return R.layout.activity_main;
@@ -29,7 +33,8 @@ public class MainActivity extends BaseMVPActivity {
         findViewById(R.id.view_test).setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View view) {
-                presenter1.go();
+                //presenter1.go();
+                viewModel1.go();
             }
         });
     }

+ 27 - 0
app/src/main/java/com/miekir/newmvp/TestViewModel1.java

@@ -0,0 +1,27 @@
+package com.miekir.newmvp;
+
+import com.miekir.mvp.presenter.BaseViewModel;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/10/6 20:53
+ * Description:
+ */
+public class TestViewModel1 extends BaseViewModel {
+    public void go() {
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    Thread.sleep(10000);
+                    //getView().onLoginResult(3, "ddd");
+                    post(0, "test", new TestBean1(3, "ViewModel Jason"));
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }).start();
+    }
+}

+ 1 - 0
mvp/build.gradle

@@ -34,4 +34,5 @@ dependencies {
     def lifecycle_version = "2.2.0"
     implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
     implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
+    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
 }

+ 37 - 0
mvp/src/main/java/com/miekir/mvp/presenter/BaseViewModel.java

@@ -0,0 +1,37 @@
+package com.miekir.mvp.presenter;
+
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.ViewModel;
+
+import com.miekir.mvp.base.DataResult;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/10/7 22:46
+ * Description:
+ */
+public class BaseViewModel extends ViewModel {
+    /**
+     * ViewModel的生命周期和Activity保持一致;在onStart()、onResume()、onPause()时调用LiveData的setValue才会通知观察者
+     * liveData在ViewModel(Presenter)创建,然后提供方法给Activity获取,方便取消观察
+     */
+    private MutableLiveData<DataResult> liveData = new MutableLiveData<DataResult>();
+
+    public MutableLiveData<DataResult> getLiveData() {
+        return liveData;
+    }
+
+    public void post(int code, String msg, Object dataBean) {
+        if (liveData == null) {
+            return;
+        }
+
+        liveData.postValue(new DataResult(code, msg, dataBean));
+    }
+
+    public void detachView() {
+        liveData = null;
+    }
+}

+ 15 - 0
mvp/src/main/java/com/miekir/mvp/presenter/InjectViewModel.java

@@ -0,0 +1,15 @@
+package com.miekir.mvp.presenter;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @description Presenter注入标记
+ * @date 2019/8/19
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface InjectViewModel {
+}

+ 142 - 0
mvp/src/main/java/com/miekir/mvp/view/model/BaseMVPActivity.java

@@ -0,0 +1,142 @@
+package com.miekir.mvp.view.model;
+
+
+import android.os.Bundle;
+import android.text.TextUtils;
+
+import androidx.lifecycle.Observer;
+import androidx.lifecycle.ViewModelProvider;
+
+import com.miekir.mvp.base.BaseActivity;
+import com.miekir.mvp.base.DataResult;
+import com.miekir.mvp.presenter.BasePresenter;
+import com.miekir.mvp.presenter.BaseViewModel;
+import com.miekir.mvp.presenter.DataMethod;
+import com.miekir.mvp.presenter.InjectPresenter;
+import com.miekir.mvp.presenter.InjectViewModel;
+import com.miekir.mvp.view.IView;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 利用反射,BaseMVPActivity将会查找子类中有{@link InjectPresenter}注解的成员变量,
+ * 筛选出父类是{@link BasePresenter}的成员变量,对它们进行实例化
+ * 然后BaseMVPActivity调用{@link BasePresenter}的一个方法把自身的{@link androidx.lifecycle.LiveData}类型引用
+ * 传递给{@link BasePresenter},这样{@link BasePresenter}的子类就可以调用相应Activity的LiveData;
+ *
+ */
+public abstract class BaseMVPActivity extends BaseActivity implements IView {
+    private List<Method> mDataMethodList = new ArrayList<>();
+    private List<BaseViewModel> mInjectPresenters;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // 查找回调方法
+        if (mDataMethodList.size() == 0) {
+            Method[] methods = null;
+            try {
+                // This is faster than getMethods, especially when subscribers are fat classes like Activities
+                methods = getClass().getDeclaredMethods();
+            } catch (Throwable th) {
+                // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
+                try {
+                    methods = getClass().getDeclaredMethods();
+                } catch (LinkageError error) { // super class of NoClassDefFoundError to be a bit more broad...
+                    error.printStackTrace();
+                }
+            }
+
+            // 参数校验
+            if (methods != null && methods.length > 0) {
+                for (Method method : methods) {
+                    DataMethod dataMethod = method.getAnnotation(DataMethod.class);
+                    if (dataMethod != null) {
+                        int length = method.getParameterTypes().length;
+                        if (length != 3) {
+                            throw new AssertionError("DataMethod参数数量必须为3个");
+                        }
+
+                        String firstType = method.getParameterTypes()[0].getSimpleName();
+                        String firstCorrectType = int.class.getSimpleName();
+                        if (!TextUtils.equals(firstCorrectType, firstType)) {
+                            throw new AssertionError("DataMethod第1个参数必须为" + firstCorrectType);
+                        }
+
+                        String secondType = method.getParameterTypes()[1].getSimpleName();
+                        String secondCorrectType = String.class.getSimpleName();
+                        if (!TextUtils.equals(secondCorrectType, secondType)) {
+                            throw new AssertionError("DataMethod第2个参数必须为" + secondCorrectType);
+                        }
+
+                        mDataMethodList.add(method);
+                    }
+                }
+            }
+        }
+
+        // 这里可以获取到子类的成员变量
+        mInjectPresenters = new ArrayList<>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            //获取变量上面的注解类型
+            InjectViewModel injectViewModel = field.getAnnotation(InjectViewModel.class);
+            if (injectViewModel != null) {
+                try {
+                    field.setAccessible(true);
+
+                    Class<? extends BaseViewModel> type = (Class<? extends BaseViewModel>) field.getType();
+                    //BaseViewModel presenter = type.newInstance();
+
+                    //创建一个观察者去更新UI
+                    final Observer<DataResult> observer = new Observer<DataResult>() {
+                        @Override
+                        public void onChanged(final DataResult result) {
+                            onDataResult(result);
+                        }
+                    };
+                    BaseViewModel presenter = new ViewModelProvider(this).get(type);
+                    presenter.getLiveData().observe(this, observer);
+
+                    field.set(this, presenter);
+                    mInjectPresenters.add(presenter);
+                } catch (IllegalAccessException e) {
+                    e.printStackTrace();
+                } catch (ClassCastException e) {
+                    e.printStackTrace();
+                    throw new RuntimeException("SubClass must extends Class:BaseViewModel");
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        if (mInjectPresenters != null && mInjectPresenters.size() > 0) {
+            for (BaseViewModel presenter : mInjectPresenters) {
+                presenter.getLiveData().removeObservers(this);
+                presenter.detachView();
+            }
+            mInjectPresenters.clear();
+            mInjectPresenters = null;
+        }
+
+        mDataMethodList.clear();
+    }
+
+
+    private void onDataResult(DataResult result) {
+        for (Method method : mDataMethodList) {
+            try {
+                method.invoke(this, result.getCode(), result.getMessage(), result.getBean());
+            } catch (Exception e) {
+                //e.printStackTrace();
+            }
+        }
+    }
+}

+ 185 - 0
mvp/src/main/java/com/miekir/mvp/view/model/BaseMVPFragment.java

@@ -0,0 +1,185 @@
+package com.miekir.mvp.view.model;
+
+import android.os.Bundle;
+import android.text.TextUtils;
+
+import androidx.annotation.Nullable;
+import androidx.lifecycle.Observer;
+import androidx.lifecycle.ViewModelProvider;
+
+import com.miekir.mvp.base.BaseFragment;
+import com.miekir.mvp.base.DataResult;
+import com.miekir.mvp.presenter.BaseViewModel;
+import com.miekir.mvp.presenter.DataMethod;
+import com.miekir.mvp.presenter.InjectViewModel;
+import com.miekir.mvp.view.IView;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+
+public abstract class BaseMVPFragment extends BaseFragment implements IView {
+    /**
+     * 是否被创建了
+     */
+    protected boolean isViewCreated;
+    /**
+     * 当前是否可见
+     */
+    protected boolean isUIVisible;
+
+    private List<Method> mDataMethodList = new ArrayList<>();
+    private List<BaseViewModel> mInjectPresenters;
+
+    @Override
+    public  void onCreateViewFinished(@Nullable Bundle savedInstanceState) {
+        onViewInit();
+
+        // 查找回调方法
+        if (mDataMethodList.size() == 0) {
+            Method[] methods = null;
+            try {
+                // This is faster than getMethods, especially when subscribers are fat classes like Activities
+                methods = getClass().getDeclaredMethods();
+            } catch (Throwable th) {
+                // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
+                try {
+                    methods = getClass().getDeclaredMethods();
+                } catch (LinkageError error) { // super class of NoClassDefFoundError to be a bit more broad...
+                    error.printStackTrace();
+                }
+            }
+
+            if (methods != null && methods.length > 0) {
+                for (Method method : methods) {
+                    DataMethod dataMethod = method.getAnnotation(DataMethod.class);
+                    if (dataMethod != null) {
+                        mDataMethodList.add(method);
+                    }
+                }
+            }
+
+            // 参数校验
+            if (methods != null && methods.length > 0) {
+                for (Method method : methods) {
+                    DataMethod dataMethod = method.getAnnotation(DataMethod.class);
+                    if (dataMethod != null) {
+                        int length = method.getParameterTypes().length;
+                        if (length != 3) {
+                            throw new AssertionError("DataMethod参数数量必须为3个");
+                        }
+
+                        String firstType = method.getParameterTypes()[0].getSimpleName();
+                        String firstCorrectType = int.class.getSimpleName();
+                        if (!TextUtils.equals(firstCorrectType, firstType)) {
+                            throw new AssertionError("DataMethod第1个参数必须为" + firstCorrectType);
+                        }
+
+                        String secondType = method.getParameterTypes()[1].getSimpleName();
+                        String secondCorrectType = String.class.getSimpleName();
+                        if (!TextUtils.equals(secondCorrectType, secondType)) {
+                            throw new AssertionError("DataMethod第2个参数必须为" + secondCorrectType);
+                        }
+
+                        mDataMethodList.add(method);
+                    }
+                }
+            }
+        }
+
+        // 这里可以获取到子类的成员变量
+        mInjectPresenters = new ArrayList<>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            //获取变量上面的注解类型
+            InjectViewModel injectViewModel = field.getAnnotation(InjectViewModel.class);
+            if (injectViewModel != null) {
+                try {
+                    field.setAccessible(true);
+
+                    Class<? extends BaseViewModel> type = (Class<? extends BaseViewModel>) field.getType();
+                    //BaseViewModel presenter = type.newInstance();
+
+                    //创建一个观察者去更新UI
+                    final Observer<DataResult> observer = new Observer<DataResult>() {
+                        @Override
+                        public void onChanged(final DataResult result) {
+                            onDataResult(result);
+                        }
+                    };
+                    BaseViewModel presenter = new ViewModelProvider(this).get(type);
+                    presenter.getLiveData().observe(this, observer);
+
+                    field.set(this, presenter);
+                    mInjectPresenters.add(presenter);
+                } catch (IllegalAccessException e) {
+                    e.printStackTrace();
+                } catch (ClassCastException e) {
+                    e.printStackTrace();
+                    throw new RuntimeException("SubClass must extends Class:BaseViewModel");
+                }
+            }
+        }
+
+        isViewCreated = true;
+        loadData();
+    }
+
+    /**
+     * View初始化
+     */
+    protected abstract void onViewInit();
+
+    @Override
+    public void setUserVisibleHint(boolean isVisibleToUser) {
+        super.setUserVisibleHint(isVisibleToUser);
+        isUIVisible = isVisibleToUser;
+        if (isVisibleToUser) {
+            loadData();
+        }
+    }
+
+    /**
+     * 懒加载,当Fragment可见的时候,再去加载数据
+     * 应用初始化会先调用完所有的setUserVisibleHint再调用onViewCreated,然后切换的时候,就只调用setUserVisibleHint了
+     */
+    private void loadData() {
+        if (isViewCreated && isUIVisible) {
+            isViewCreated = false;
+            isUIVisible = false;
+            onLazyLoad();
+        }
+    }
+
+    /**
+     * 懒加载,初始化加载数据
+     */
+    protected abstract void onLazyLoad();
+
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        if (mInjectPresenters != null && mInjectPresenters.size() > 0) {
+            for (BaseViewModel presenter : mInjectPresenters) {
+                presenter.getLiveData().removeObservers(this);
+                presenter.detachView();
+            }
+            mInjectPresenters.clear();
+            mInjectPresenters = null;
+        }
+
+        mDataMethodList.clear();
+    }
+
+    private void onDataResult(DataResult result) {
+        for (Method method : mDataMethodList) {
+            try {
+                method.invoke(this, result.getCode(), result.getMessage(), result.getBean());
+            } catch (Exception e) {
+                //e.printStackTrace();
+            }
+        }
+    }
+}