Преглед на файлове

剩余错误推送的问题

詹子聪 преди 5 години
родител
ревизия
244a49a6a0

+ 6 - 12
app/src/main/java/com/miekir/newmvp/MainActivity.java

@@ -2,20 +2,19 @@ package com.miekir.newmvp;
 
 import android.content.Intent;
 import android.os.Bundle;
-import android.os.Handler;
 import android.view.View;
 import android.widget.TextView;
 import android.widget.Toast;
 
-import com.miekir.mvp.presenter.DataMethod;
-import com.miekir.mvp.presenter.InjectViewModel;
+import com.miekir.mvp.model.DataMethod;
+import com.miekir.mvp.presenter.InjectPresenter;
 import com.miekir.mvp.view.BaseMvpActivity;
 
 import java.util.List;
 
 public class MainActivity extends BaseMvpActivity {
-    @InjectViewModel
-    TestViewModel1 viewModel1;
+    @InjectPresenter
+    TestPresenter viewModel1;
 
     @Override
     public int getLayoutID() {
@@ -31,12 +30,7 @@ public class MainActivity extends BaseMvpActivity {
             @Override
             public void onClick(View view) {
                 // 点击之后,后台执行耗时操作
-                new Handler().postDelayed(new Runnable() {
-                    @Override
-                    public void run() {
-                        viewModel1.go();
-                    }
-                }, 5000);
+                viewModel1.go();
             }
         });
 
@@ -50,7 +44,7 @@ public class MainActivity extends BaseMvpActivity {
     }
 
     @DataMethod
-    public void onDataCome(int code, String msg, List<TestBean1> data, int source) {
+    public void onDataCome(int code, String msg, List<TestBean1> data) {
         Toast.makeText(this, data.get(0).getName(), Toast.LENGTH_SHORT).show();
     }
 }

+ 34 - 0
app/src/main/java/com/miekir/newmvp/TestBean2.java

@@ -0,0 +1,34 @@
+package com.miekir.newmvp;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/10/7 11:35
+ * Description:
+ */
+public class TestBean2 {
+    private int age;
+    private String name;
+
+    public TestBean2(int age, String name) {
+        this.age = age;
+        this.name = name;
+    }
+
+    public int getAge() {
+        return age;
+    }
+
+    public void setAge(int age) {
+        this.age = age;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}

+ 14 - 0
app/src/main/java/com/miekir/newmvp/TestModel.java

@@ -0,0 +1,14 @@
+package com.miekir.newmvp;
+
+import com.miekir.mvp.model.MvpModel;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/11/14 14:57
+ * Description:
+ */
+@MvpModel()
+public class TestModel {
+}

+ 12 - 3
app/src/main/java/com/miekir/newmvp/TestViewModel1.java

@@ -1,7 +1,9 @@
 package com.miekir.newmvp;
 
 import com.miekir.mvp.base.NeedLoading;
-import com.miekir.mvp.presenter.BaseViewModel;
+import com.miekir.mvp.constant.DataSource;
+import com.miekir.mvp.model.MvpModel;
+import com.miekir.mvp.presenter.BasePresenter;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -13,7 +15,13 @@ import java.util.List;
  * @date 2020/10/6 20:53
  * Description:注意ViewModel的类必须是public的,否则无法创建实例
  */
-public class TestViewModel1 extends BaseViewModel {
+public class TestPresenter extends BasePresenter {
+
+    @Override
+    public void init() {
+
+    }
+
     @NeedLoading
     public void go() {
         new Thread(new Runnable() {
@@ -23,7 +31,8 @@ public class TestViewModel1 extends BaseViewModel {
                     Thread.sleep(5000);
                     List<TestBean1> testBean1List = new ArrayList<>();
                     testBean1List.add(new TestBean1(3, "ViewModel Jason"));
-                    postSuccess(testBean1List);
+                    // todo 这里还有问题,就是post的错误没法被正确的方法接收
+                    postFail("错误", new ArrayList<TestBean2>());
                 } catch (Exception e) {
                     e.printStackTrace();
                 }

+ 1 - 0
mvp/src/main/java/com/miekir/mvp/base/BaseActivity.java

@@ -11,6 +11,7 @@ import android.view.inputmethod.InputMethodManager;
 
 import androidx.appcompat.app.AppCompatActivity;
 
+import com.miekir.mvp.bean.DataResult;
 import com.miekir.mvp.widget.LoadingDialog;
 
 /**

+ 2 - 2
mvp/src/main/java/com/miekir/mvp/constant/BaseMvpResponse.java

@@ -8,6 +8,6 @@ package com.miekir.mvp.constant;
  * Description:
  */
 public interface BaseMvpResponse {
-    int COMMON_SUCCESS = 0;
-    int COMMON_FAIL = -1;
+    int SUCCESS = 0;
+    int FAIL = -1;
 }

+ 5 - 4
mvp/src/main/java/com/miekir/mvp/constant/BaseMvpSource.java

@@ -8,8 +8,9 @@ package com.miekir.mvp.constant;
  * Description: 用于区分数据来源。如一个界面上有两个列表,左边是展示本地数据库的数据,右边是展示远程数据库的数据,数据类型一样,
  * 此时有必要区分来源。
  */
-public interface BaseMvpSource {
-    int COMMON = 0;
-    int DIALOG_SHOW = 99999;
-    int DIALOG_DISMISS = -99999;
+public interface DataSource {
+    int DEFAULT = 0;
+    int INTERNET = 1;
+    int DATABASE = 2;
+    int FILE = 3;
 }

+ 14 - 0
mvp/src/main/java/com/miekir/mvp/constant/DialogAction.java

@@ -0,0 +1,14 @@
+package com.miekir.mvp.constant;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/10/30 9:00
+ * Description: 用于区分数据来源。如一个界面上有两个列表,左边是展示本地数据库的数据,右边是展示远程数据库的数据,数据类型一样,
+ * 此时有必要区分来源。
+ */
+public interface DialogAction {
+    int DIALOG_SHOW = 1;
+    int DIALOG_DISMISS = -1;
+}

+ 6 - 1
mvp/src/main/java/com/miekir/mvp/presenter/DataMethod.java

@@ -1,4 +1,6 @@
-package com.miekir.mvp.presenter;
+package com.miekir.mvp.model;
+
+import com.miekir.mvp.constant.DataSource;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -6,10 +8,13 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 /**
+ *
+ * @author zicong
  * @description 方法回调标记
  * @date 2019/8/19
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.METHOD)
 public @interface DataMethod {
+    int dataSource() default DataSource.DEFAULT;
 }

+ 19 - 0
mvp/src/main/java/com/miekir/mvp/model/MvpModel.java

@@ -0,0 +1,19 @@
+package com.miekir.mvp.model;
+
+import com.miekir.mvp.constant.DataSource;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ * @author zhan
+ * @date 2019/8/19
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface MvpModel {
+    int dataSource() default DataSource.DEFAULT;
+}

+ 100 - 0
mvp/src/main/java/com/miekir/mvp/presenter/BasePresenter.java

@@ -0,0 +1,100 @@
+package com.miekir.mvp.presenter;
+
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.ViewModel;
+
+import com.miekir.mvp.bean.DataResult;
+import com.miekir.mvp.constant.BaseMvpResponse;
+import com.miekir.mvp.constant.DataSource;
+import com.miekir.mvp.constant.DialogAction;
+import com.miekir.mvp.model.MvpModel;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/10/7 22:46
+ * Description:
+ */
+public abstract class BasePresenter extends ViewModel {
+    //private ThreadLocal<Integer> mThreadLocal = new ThreadLocal<>();
+
+    /**
+     * ViewModel的生命周期和Activity保持一致;在onStart()、onResume()、onPause()时调用LiveData的setValue才会通知观察者
+     * liveData在ViewModel(Presenter)创建,然后提供方法给Activity获取,方便取消观察
+     * 由于使用了AspectJ,这个变量名和属性不能改动,否则AspectJ会拿不到值
+     */
+    public MutableLiveData<DataResult> liveData = new MutableLiveData<DataResult>();
+    public MutableLiveData<DataResult> dialogLiveData = new MutableLiveData<DataResult>();
+
+    public MutableLiveData<DataResult> getLiveData() {
+        return liveData;
+    }
+    public MutableLiveData<DataResult> getDialogLiveData() {
+        return dialogLiveData;
+    }
+
+    /**
+     * 由于使用了AspectJ,这个方法名不能改动
+     * 对弹出对话框此时进行计数,归零才dismiss
+     */
+    public void showLoading() {
+        showLoading("");
+    }
+
+    public void showLoading(String message) {
+        if (dialogLiveData == null) {
+            return;
+        }
+        dialogLiveData.postValue(new DataResult(0, message, null, DialogAction.DIALOG_SHOW));
+    }
+
+    public void dismissLoading() {
+        if (dialogLiveData == null) {
+            return;
+        }
+        dialogLiveData.postValue(new DataResult(0, null, null, DialogAction.DIALOG_DISMISS));
+    }
+
+    public void post(int responseCode, String message, Object dataBean, Class<?> clazz) {
+        if (liveData == null) {
+            return;
+        }
+
+        int sourceCode = DataSource.DEFAULT;
+        if (clazz != null) {
+            MvpModel model = clazz.getAnnotation(MvpModel.class);
+            if (model != null) {
+                sourceCode = model.dataSource();
+            }
+        }
+        liveData.postValue(new DataResult(responseCode, message, dataBean, sourceCode));
+    }
+
+    public void postSuccess(Object dataBean) {
+        post(BaseMvpResponse.SUCCESS, "", dataBean, null);
+    }
+
+    public void postSuccess(Object dataBean, Class<?> modelClass) {
+        post(BaseMvpResponse.SUCCESS, "", dataBean, modelClass);
+    }
+
+    public void postFail(String message, Object dataBean) {
+        post(BaseMvpResponse.FAIL, message, dataBean, null);
+    }
+
+    public void postFail(String message, Object dataBean, Class<?> modelClass) {
+        post(BaseMvpResponse.FAIL, message, dataBean, modelClass);
+    }
+
+    public void detachView() {
+        liveData = null;
+        onTaskCancel();
+    }
+
+    public abstract void init();
+    /**
+     * 当任务被取消时
+     */
+    public abstract void onTaskCancel();
+}

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

@@ -1,116 +0,0 @@
-package com.miekir.mvp.presenter;
-
-import androidx.lifecycle.MutableLiveData;
-import androidx.lifecycle.ViewModel;
-
-import com.miekir.mvp.bean.DataResult;
-import com.miekir.mvp.constant.BaseMvpResponse;
-import com.miekir.mvp.constant.BaseMvpSource;
-
-/**
- * Copyright (C), 2019-2020, Miekir
- *
- * @author Miekir
- * @date 2020/10/7 22:46
- * Description:
- */
-public abstract class BaseViewModel extends ViewModel {
-    //private ThreadLocal<Integer> mThreadLocal = new ThreadLocal<>();
-
-    /**
-     * ViewModel的生命周期和Activity保持一致;在onStart()、onResume()、onPause()时调用LiveData的setValue才会通知观察者
-     * liveData在ViewModel(Presenter)创建,然后提供方法给Activity获取,方便取消观察
-     * 由于使用了AspectJ,这个变量名和属性不能改动,否则AspectJ会拿不到值
-     */
-    public MutableLiveData<DataResult> liveData = new MutableLiveData<DataResult>();
-
-    public MutableLiveData<DataResult> getLiveData() {
-        return liveData;
-    }
-
-    /**
-     * 由于使用了AspectJ,这个方法名不能改动
-     * 对弹出对话框此时进行计数,归零才dismiss
-     */
-    public void showLoading() {
-        showLoading("");
-    }
-
-    public void showLoading(String message) {
-        if (liveData == null) {
-            return;
-        }
-        liveData.postValue(new DataResult(0, message, null, BaseMvpSource.DIALOG_SHOW));
-    }
-
-    public void dismissLoading() {
-        if (liveData == null) {
-            return;
-        }
-        liveData.postValue(new DataResult(0, null, null, BaseMvpSource.DIALOG_DISMISS));
-    }
-
-    public void post(int responseCode, String msg, Object dataBean, int sourceCode) {
-        if (liveData == null) {
-            return;
-        }
-
-        liveData.postValue(new DataResult(responseCode, msg, dataBean, sourceCode));
-    }
-
-    public void post(int responseCode, String msg, Object dataBean) {
-        post(responseCode, msg, dataBean, BaseMvpSource.COMMON);
-    }
-
-    public void post(int responseCode, Object dataBean) {
-        post(responseCode, "", dataBean, BaseMvpSource.COMMON);
-    }
-
-    public void post(int responseCode, Object dataBean, int sourceCode) {
-        post(responseCode, "", dataBean, sourceCode);
-    }
-
-    public void postSuccess(Object dataBean) {
-        post(BaseMvpResponse.COMMON_SUCCESS, "", dataBean, BaseMvpSource.COMMON);
-    }
-
-    public void postSuccess(Object dataBean, int sourceCode) {
-        post(BaseMvpResponse.COMMON_SUCCESS, "", dataBean, sourceCode);
-    }
-
-    public void postSuccess(String msg, Object dataBean) {
-        post(BaseMvpResponse.COMMON_SUCCESS, msg, dataBean, BaseMvpSource.COMMON);
-    }
-
-    public void postSuccess(String msg, Object dataBean, int sourceCode) {
-        post(BaseMvpResponse.COMMON_SUCCESS, msg, dataBean, sourceCode);
-    }
-
-    public void postFail(Object dataBean) {
-        post(BaseMvpResponse.COMMON_FAIL, "", dataBean, BaseMvpSource.COMMON);
-    }
-
-    public void postFail(Object dataBean, int sourceCode) {
-        if (liveData == null) {
-            return;
-        }
-
-        liveData.postValue(new DataResult(BaseMvpResponse.COMMON_FAIL, "", dataBean, sourceCode));
-    }
-
-    public void postFail(String msg, Object dataBean) {
-        post(BaseMvpResponse.COMMON_FAIL, msg, dataBean, BaseMvpSource.COMMON);
-    }
-
-    public void postFail(String msg, Object dataBean, int sourceCode) {
-        post(BaseMvpResponse.COMMON_FAIL, msg, dataBean, sourceCode);
-    }
-
-    public void detachView() {
-        liveData = null;
-        onTaskCancel();
-    }
-
-
-    public abstract void onTaskCancel();
-}

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

@@ -12,7 +12,7 @@ import java.lang.annotation.Target;
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.FIELD)
-public @interface InjectViewModel {
+public @interface InjectPresenter {
     /**
      * @return 运行类型,默认在Activity活动生命周期的时候才触发回调,如果是persist则在后台也能触发回调
      */

+ 13 - 173
mvp/src/main/java/com/miekir/mvp/view/BaseMvpActivity.java

@@ -2,20 +2,11 @@ package com.miekir.mvp.view;
 
 
 import android.os.Bundle;
-import android.text.TextUtils;
-
-import androidx.lifecycle.MutableLiveData;
-import androidx.lifecycle.Observer;
 
 import com.miekir.mvp.base.BaseActivity;
 import com.miekir.mvp.bean.DataResult;
-import com.miekir.mvp.constant.BaseMvpResponse;
-import com.miekir.mvp.constant.BaseMvpSource;
-import com.miekir.mvp.presenter.BaseViewModel;
-import com.miekir.mvp.presenter.DataMethod;
-import com.miekir.mvp.presenter.InjectViewModel;
+import com.miekir.mvp.presenter.BasePresenter;
 
-import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
@@ -26,9 +17,13 @@ import java.util.List;
  */
 public abstract class BaseMvpActivity extends BaseActivity implements IView {
     private List<Method> mDataMethodList = new ArrayList<>();
-    private List<BaseViewModel> mInjectPresenters = new ArrayList<>();
+    private List<BasePresenter> mInjectPresenters = new ArrayList<>();
 
+    /**
+     * 对话框相关
+     */
     private volatile int mLoadingNum;
+    @Override
     public synchronized int onLoadTimeChange(boolean isAdd, String message) {
         if (isAdd) {
             mLoadingNum = mLoadingNum +1;
@@ -48,7 +43,7 @@ public abstract class BaseMvpActivity extends BaseActivity implements IView {
     @Override
     public void onTaskCancel() {
         mLoadingNum = 0;
-        for (BaseViewModel viewModel : mInjectPresenters) {
+        for (BasePresenter viewModel : mInjectPresenters) {
             viewModel.onTaskCancel();
         }
     }
@@ -57,180 +52,25 @@ public abstract class BaseMvpActivity extends BaseActivity implements IView {
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        initVariables();
-        initCallbacks();
+        ViewHelper.initVariables(mInjectPresenters, this, this);
+        ViewHelper.initCallbacks(mDataMethodList, getClass());
         initViews(savedInstanceState);
     }
 
-    /**
-     * 初始化添加注解的变量
-     */
-    private void initVariables() {
-        clearPresenters();
-        // 这里可以获取到子类的成员变量
-        Field[] fields = this.getClass().getDeclaredFields();
-        for (Field field : fields) {
-            // 获取变量上面的注解类型
-            InjectViewModel injectViewModel = field.getAnnotation(InjectViewModel.class);
-            if (injectViewModel == null) {
-                continue;
-            }
-
-            try {
-                field.setAccessible(true);
-
-                // 父类引用指向子类对象
-                Class<? extends BaseViewModel> type = (Class<? extends BaseViewModel>) field.getType();
-                BaseViewModel presenter = type.newInstance();
-                // 下面这种方法是单例形式,会造成重复回调的问题
-                //BaseViewModel presenter = new ViewModelProvider(this).get(type);
-
-                // 创建一个观察者去更新UI
-                final Observer<DataResult> observer = new Observer<DataResult>() {
-                    @Override
-                    public void onChanged(final DataResult result) {
-                        // 回调是在主线程
-                        // Log.i("Thread", String.valueOf(Thread.currentThread() == Looper.getMainLooper().getThread()));
-                        if (result.getSourceCode() == BaseMvpSource.DIALOG_SHOW) {
-                            onLoadTimeChange(true, result.getMessage());
-                        } else if (result.getSourceCode() == BaseMvpSource.DIALOG_DISMISS) {
-                            onLoadTimeChange(false, result.getMessage());
-                        } else {
-                            onDataResult(result);
-                        }
-                    }
-                };
-                if (injectViewModel.isPersist()) {
-                    presenter.getLiveData().observeForever(observer);
-                } else {
-                    presenter.getLiveData().observe(this, observer);
-                }
-
-                field.set(this, presenter);
-                mInjectPresenters.add(presenter);
-            } catch (IllegalAccessException | InstantiationException e) {
-                e.printStackTrace();
-            } catch (ClassCastException e) {
-                e.printStackTrace();
-                throw new RuntimeException(InjectViewModel.class.getName() + "注解修饰的类必须继承自:" + BaseViewModel.class.getName());
-            }
-        }
-    }
-
-    /**
-     * 初始化获取需要回调的注解方法
-     */
-    private void initCallbacks() {
-        // 查找回调方法
-        mDataMethodList.clear();
-
-        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().getMethods();
-            } catch (LinkageError error) {
-                error.printStackTrace();
-            }
-        }
-
-        // 参数校验
-        if (methods == null || methods.length == 0) {
-            return;
-        }
-
-        String methodAnnotationName = DataMethod.class.getName();
-        for (Method method : methods) {
-            DataMethod dataMethod = method.getAnnotation(DataMethod.class);
-            if (dataMethod == null) {
-                continue;
-            }
-
-            int length = method.getParameterTypes().length;
-            if (length != 4) {
-                throw new AssertionError(methodAnnotationName + "修饰的方法参数数量必须为4个");
-            }
-
-            // 响应结果,必须为int或者boolean
-            String firstType = method.getParameterTypes()[0].getSimpleName();
-            String resultCodeType = int.class.getSimpleName();
-            String resultStatusType = boolean.class.getSimpleName();
-            if (!TextUtils.equals(resultCodeType, firstType) && !TextUtils.equals(resultStatusType, firstType)) {
-                throw new AssertionError(methodAnnotationName + "修饰的方法第1个参数必须为" + resultCodeType + "或" + resultStatusType);
-            }
-
-            // 响应消息
-            String secondType = method.getParameterTypes()[1].getSimpleName();
-            String messageType = String.class.getSimpleName();
-            if (!TextUtils.equals(messageType, secondType)) {
-                throw new AssertionError(methodAnnotationName + "修饰的方法第2个参数必须为" + messageType);
-            }
-
-            // 数据来源
-            String fourthType = method.getParameterTypes()[3].getSimpleName();
-            String sourceCodeType = int.class.getSimpleName();
-            if (!TextUtils.equals(fourthType, sourceCodeType)) {
-                throw new AssertionError(methodAnnotationName + "修饰的方法第4个参数必须为" + sourceCodeType);
-            }
-
-            method.setAccessible(true);
-            mDataMethodList.add(method);
-        }
-    }
-
     @Override
     protected void onDestroy() {
         super.onDestroy();
 
-        clearPresenters();
+        ViewHelper.clearPresenters(mInjectPresenters, this);
         mDataMethodList.clear();
     }
 
-    private void clearPresenters() {
-        if (mInjectPresenters.size() > 0) {
-            for (BaseViewModel presenter : mInjectPresenters) {
-                if (presenter == null) {
-                    continue;
-                }
-
-                MutableLiveData<DataResult> liveData = presenter.getLiveData();
-                if (liveData == null) {
-                    continue;
-                }
-                liveData.removeObservers(this);
-                presenter.detachView();
-            }
-            mInjectPresenters.clear();
-        }
-    }
-
     /**
      * 回调
      * @param result
      */
-    private void onDataResult(DataResult result) {
-        Class objParamClass = result.getBean().getClass();
-        for (Method method : mDataMethodList) {
-            Class methodParamClass = method.getParameterTypes()[2];
-            // 判断方法的第二个参数类型是否是回调对象的父类
-            if (!methodParamClass.isAssignableFrom(objParamClass)) {
-                continue;
-            }
-
-            try {
-                method.invoke(this, result.getResponseCode(), result.getMessage(), result.getBean(), result.getSourceCode());
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-
-            try {
-                method.invoke(this, result.getResponseCode() == BaseMvpResponse.COMMON_SUCCESS, result.getMessage(), result.getBean(), result.getSourceCode());
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        }
+    @Override
+    public void onDataResult(DataResult result) {
+        ViewHelper.handleDataResult(this, mDataMethodList, result);
     }
 }

+ 6 - 0
mvp/src/main/java/com/miekir/mvp/view/IView.java

@@ -1,9 +1,15 @@
 package com.miekir.mvp.view;
 
+import com.miekir.mvp.bean.DataResult;
+
 public interface IView {
     void showLoading();
 
     void showLoading(String msg);
 
     void dismissLoading();
+
+    void onDataResult(DataResult result);
+
+    int onLoadTimeChange(boolean isAdd, String message);
 }

+ 218 - 0
mvp/src/main/java/com/miekir/mvp/view/ViewHelper.java

@@ -0,0 +1,218 @@
+package com.miekir.mvp.view;
+
+import android.text.TextUtils;
+
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.Observer;
+
+import com.miekir.mvp.base.BaseActivity;
+import com.miekir.mvp.bean.DataResult;
+import com.miekir.mvp.constant.BaseMvpResponse;
+import com.miekir.mvp.constant.DataSource;
+import com.miekir.mvp.constant.DialogAction;
+import com.miekir.mvp.presenter.BasePresenter;
+import com.miekir.mvp.model.DataMethod;
+import com.miekir.mvp.presenter.InjectPresenter;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/11/14 13:32
+ * Description:
+ */
+public class ViewHelper {
+    private ViewHelper() {}
+
+    /**
+     * 界面销毁时,清理Presenter
+     * @param mInjectPresenters
+     * @param owner
+     */
+    public static void clearPresenters(List<BasePresenter> mInjectPresenters, final LifecycleOwner owner) {
+        if (mInjectPresenters.size() > 0) {
+            for (BasePresenter presenter : mInjectPresenters) {
+                if (presenter == null) {
+                    continue;
+                }
+
+                MutableLiveData<DataResult> liveData = presenter.getLiveData();
+                MutableLiveData<DataResult> dialogData = presenter.getDialogLiveData();
+                if (dialogData != null) {
+                    dialogData.removeObservers(owner);
+                }
+                if (liveData != null) {
+                    liveData.removeObservers(owner);
+                }
+                presenter.detachView();
+            }
+            mInjectPresenters.clear();
+        }
+    }
+
+    /**
+     * 初始化获取需要回调的注解方法
+     */
+    public static void initCallbacks(List<Method> mDataMethodList, Class<? extends BaseActivity> getClass) {
+        // 查找回调方法
+        mDataMethodList.clear();
+
+        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.getMethods();
+            } catch (LinkageError error) {
+                error.printStackTrace();
+            }
+        }
+
+        // 参数校验
+        if (methods == null || methods.length == 0) {
+            return;
+        }
+
+        String methodAnnotationName = DataMethod.class.getName();
+        for (Method method : methods) {
+            DataMethod dataMethod = method.getAnnotation(DataMethod.class);
+            if (dataMethod == null) {
+                continue;
+            }
+
+            int length = method.getParameterTypes().length;
+            if (length != 3) {
+                throw new AssertionError(methodAnnotationName + "修饰的方法参数数量必须为3个");
+            }
+
+            // 响应结果,必须为int或者boolean
+            String firstType = method.getParameterTypes()[0].getSimpleName();
+            String resultCodeType = int.class.getSimpleName();
+            String resultStatusType = boolean.class.getSimpleName();
+            if (!TextUtils.equals(resultCodeType, firstType) && !TextUtils.equals(resultStatusType, firstType)) {
+                throw new AssertionError(methodAnnotationName + "修饰的方法第1个参数必须为" + resultCodeType + "或" + resultStatusType);
+            }
+
+            // 响应消息
+            String secondType = method.getParameterTypes()[1].getSimpleName();
+            String messageType = String.class.getSimpleName();
+            if (!TextUtils.equals(messageType, secondType)) {
+                throw new AssertionError(methodAnnotationName + "修饰的方法第2个参数必须为" + messageType);
+            }
+
+            method.setAccessible(true);
+            mDataMethodList.add(method);
+        }
+    }
+
+    /**
+     * 初始化添加注解的变量
+     * final Class<? extends IView> getClass,可以代表接口的实现类
+     */
+    public static void initVariables(List<BasePresenter> mInjectPresenters, final LifecycleOwner owner, final IView iView) {
+        ViewHelper.clearPresenters(mInjectPresenters, owner);
+        // 这里可以获取到子类的成员变量
+        Field[] fields = iView.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            // 获取变量上面的注解类型
+            InjectPresenter injectViewModel = field.getAnnotation(InjectPresenter.class);
+            if (injectViewModel == null) {
+                continue;
+            }
+
+            try {
+                field.setAccessible(true);
+
+                // 父类引用指向子类对象
+                Class<? extends BasePresenter> type = (Class<? extends BasePresenter>) field.getType();
+                BasePresenter presenter = type.newInstance();
+                // 下面这种方法是单例形式,会造成重复回调的问题
+                //BaseViewModel presenter = new ViewModelProvider(this).get(type);
+
+                // 创建一个观察者去更新UI
+                final Observer<DataResult> observer = new Observer<DataResult>() {
+                    @Override
+                    public void onChanged(final DataResult result) {
+                        // 回调是在主线程
+                        // Log.i("Thread", String.valueOf(Thread.currentThread() == Looper.getMainLooper().getThread()));
+                        iView.onDataResult(result);
+                    }
+                };
+
+                final Observer<DataResult> dialogObserver = new Observer<DataResult>() {
+                    @Override
+                    public void onChanged(final DataResult result) {
+                        if (result.getSourceCode() == DialogAction.DIALOG_SHOW) {
+                            iView.onLoadTimeChange(true, result.getMessage());
+                        } else if (result.getSourceCode() == DialogAction.DIALOG_DISMISS) {
+                            iView.onLoadTimeChange(false, result.getMessage());
+                        }
+                    }
+                };
+
+                if (injectViewModel.isPersist()) {
+                    presenter.getLiveData().observeForever(observer);
+                    presenter.getDialogLiveData().observeForever(dialogObserver);
+                } else {
+                    presenter.getLiveData().observe(owner, observer);
+                    presenter.getDialogLiveData().observe(owner, dialogObserver);
+                }
+
+                field.set(iView, presenter);
+                mInjectPresenters.add(presenter);
+            } catch (IllegalAccessException | InstantiationException e) {
+                e.printStackTrace();
+            } catch (ClassCastException e) {
+                e.printStackTrace();
+                throw new RuntimeException(InjectPresenter.class.getName() + "注解修饰的类必须继承自:" + BasePresenter.class.getName());
+            }
+        }
+    }
+
+    /**
+     * 分发回调的数据
+     * @param object
+     * @param mDataMethodList
+     * @param result
+     */
+    public static void handleDataResult(Object object, List<Method> mDataMethodList, DataResult result) {
+        Class objParamClass = result.getBean().getClass();
+        for (Method method : mDataMethodList) {
+
+            // 判断方法的第三个参数类型是否是回调对象的父类
+            Class methodParamClass = method.getParameterTypes()[2];
+            if (!methodParamClass.isAssignableFrom(objParamClass)) {
+                continue;
+            }
+
+            // 判断数据来源是否一致
+            int dataSource = DataSource.DEFAULT;
+            DataMethod dataMethod = method.getAnnotation(DataMethod.class);
+            if (dataMethod != null) {
+                dataSource = dataMethod.dataSource();
+            }
+            if (dataSource != result.getSourceCode()) {
+                continue;
+            }
+
+            try {
+                method.invoke(object, result.getResponseCode(), result.getMessage(), result.getBean());
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+            try {
+                method.invoke(object, result.getResponseCode() == BaseMvpResponse.SUCCESS, result.getMessage(), result.getBean());
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}

+ 4 - 7
network/src/main/java/com/miekir/network/core/impl/LoadingObserver.java

@@ -1,12 +1,9 @@
 package com.miekir.network.core.impl;
 
-import android.content.Context;
-
 import com.miekir.common.utils.ContextManager;
-import com.miekir.mvp.presenter.BaseViewModel;
+import com.miekir.mvp.presenter.BasePresenter;
 import com.miekir.network.R;
 import com.miekir.network.core.base.BaseObserver;
-import com.miekir.network.widget.CustomProgressDialog;
 
 import io.reactivex.annotations.NonNull;
 import io.reactivex.disposables.Disposable;
@@ -18,14 +15,14 @@ import io.reactivex.disposables.Disposable;
  * @author Miekir
  */
 public abstract class LoadingObserver<T> extends BaseObserver<T> {
-    private BaseViewModel mViewModel;
+    private BasePresenter mViewModel;
     private String mText;
 
-    public LoadingObserver(BaseViewModel viewModel) {
+    public LoadingObserver(BasePresenter viewModel) {
         this(viewModel, ContextManager.getInstance().getContext().getString(R.string.network_loading));
     }
 
-    private LoadingObserver(BaseViewModel viewModel, String text) {
+    private LoadingObserver(BasePresenter viewModel, String text) {
         this.mViewModel = viewModel;
         this.mText = text;
     }