詹子聪 5 роки тому
батько
коміт
6008b5dcdd
22 змінених файлів з 704 додано та 0 видалено
  1. 80 0
      network/build.gradle
  2. 27 0
      network/src/androidTest/java/com/miekir/network/ExampleInstrumentedTest.java
  3. 10 0
      network/src/main/AndroidManifest.xml
  4. 17 0
      network/src/main/java/com/miekir/network/constant/Code.java
  5. 16 0
      network/src/main/java/com/miekir/network/constant/RequestConst.java
  6. 58 0
      network/src/main/java/com/miekir/network/core/RetrofitInstaller.java
  7. 53 0
      network/src/main/java/com/miekir/network/core/base/BaseObserver.java
  8. 56 0
      network/src/main/java/com/miekir/network/core/base/BaseResponse.java
  9. 9 0
      network/src/main/java/com/miekir/network/core/base/CommonBean.java
  10. 46 0
      network/src/main/java/com/miekir/network/core/base/CommonObserver.java
  11. 53 0
      network/src/main/java/com/miekir/network/core/impl/LoadingObserver.java
  12. 62 0
      network/src/main/java/com/miekir/network/core/impl/ProgressObserver.java
  13. 46 0
      network/src/main/java/com/miekir/network/utils/ExceptionUtil.java
  14. 44 0
      network/src/main/java/com/miekir/network/utils/JsonTool.java
  15. 42 0
      network/src/main/java/com/miekir/network/widget/CustomProgressDialog.java
  16. 8 0
      network/src/main/res/drawable/bg_dialog_net_loading.xml
  17. 32 0
      network/src/main/res/layout/dialog_net_loading.xml
  18. 4 0
      network/src/main/res/values-zh-rCN/strings.xml
  19. 4 0
      network/src/main/res/values/strings.xml
  20. 19 0
      network/src/main/res/values/styles.xml
  21. 17 0
      network/src/test/java/com/miekir/network/ExampleUnitTest.java
  22. 1 0
      settings.gradle

+ 80 - 0
network/build.gradle

@@ -0,0 +1,80 @@
+apply plugin: 'com.android.library'
+
+android {
+    compileSdkVersion versions.compileSdk
+    buildToolsVersion versions.buildTools
+
+    defaultConfig {
+        minSdkVersion versions.minSdk
+        targetSdkVersion versions.targetSdk
+        versionCode 1
+        versionName "1.0"
+
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+        consumerProguardFiles 'consumer-rules.pro'
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled false
+            buildConfigField("boolean", "IS_DEBUG_MODE", "false")
+        }
+
+        debug {
+            minifyEnabled false
+            buildConfigField("boolean", "IS_DEBUG_MODE", "true")
+        }
+    }
+
+    // 开发与发布的URL
+    flavorDimensions "url"
+    productFlavors {
+        dev {
+            // 开发环境宿舍服务器
+            buildConfigField("String", "BASE_URL", '"http://192.168.0.190:8080/"')
+            buildConfigField("String", "HOST_STATIC_RESOURCE_IMAGE", '"http://192.168.0.190/"')
+        }
+
+        rel {
+            // 正式上线
+            buildConfigField("String", "BASE_URL", '"http://app.icsmabc.cyou:8856/"')
+            buildConfigField("String", "HOST_STATIC_RESOURCE_IMAGE", '"http://icsmabc.cyou/eden/images/"')
+        }
+
+        company {
+            // 开发2
+            buildConfigField("String", "BASE_URL", '"http://10.16.0.153:8080/"')
+            buildConfigField("String", "HOST_STATIC_RESOURCE_IMAGE", '"http://10.16.0.153/"')
+        }
+    }
+}
+
+dependencies {
+    api project(path: ':mvp')
+    api project(path: ':common')
+    implementation fileTree(dir: 'libs', include: ['*.jar'])
+
+    implementation 'androidx.appcompat:appcompat:1.3.0-alpha01'
+    testImplementation 'junit:junit:4.12'
+    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+
+    // 使用 retrofit + rx + gson 实现网络请求与解析start---->
+    // 导入 retrofit
+    api 'com.squareup.retrofit2:retrofit:2.7.1'
+    // 导入 rxjava,此处一定要注意使用RxJava2的版本
+    api "io.reactivex.rxjava2:rxjava:2.2.17"
+    // 导入 rxandroid
+    api 'io.reactivex.rxjava2:rxandroid:2.1.1'
+
+    // 衔接 retrofit 和 rxjava
+    api 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
+    // 衔接 retrofit 和 gson
+    api 'com.squareup.retrofit2:converter-gson:2.2.0'
+    // 使用 retrofit + rx + gson 实现网络请求与解析end<-----
+
+    // 打印网络请求日志框架
+    //implementation 'com.orhanobut:logger:2.2.0'
+
+    api "com.squareup.okhttp3:logging-interceptor:3.6.0"
+}

+ 27 - 0
network/src/androidTest/java/com/miekir/network/ExampleInstrumentedTest.java

@@ -0,0 +1,27 @@
+package com.miekir.network;
+
+import android.content.Context;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+    @Test
+    public void useAppContext() {
+        // Context of the app under test.
+        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+        assertEquals("com.itant.network.test", appContext.getPackageName());
+    }
+}

+ 10 - 0
network/src/main/AndroidManifest.xml

@@ -0,0 +1,10 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.miekir.network">
+    <application>
+        <!--authorities需要是唯一的,随着包名变化而变化,否则一个手机只能有一个项目引入这个库-->
+        <provider
+            android:name=".core.RetrofitInstaller"
+            android:authorities="${applicationId}.network"
+            android:exported="false" />
+    </application>
+</manifest>

+ 17 - 0
network/src/main/java/com/miekir/network/constant/Code.java

@@ -0,0 +1,17 @@
+package com.miekir.network.constant;
+
+/**
+ * 请求码
+ * @author Miekir
+ */
+
+public class Code {
+
+    public static final int COMMON = -1;
+    public static final int SUCCESS = 0;
+
+    /**
+     * 登录token超时
+     */
+    public static final int TOKEN_TIMEOUT = 10005;
+}

+ 16 - 0
network/src/main/java/com/miekir/network/constant/RequestConst.java

@@ -0,0 +1,16 @@
+package com.miekir.network.constant;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/1/19 11:27
+ * Description: 请求相关的常量
+ */
+public interface RequestConst {
+    /**
+     * 请求域名
+     * RetrofitHelper.getInstance().setRequestHost()
+     */
+    String BASE_URL = "http://192.168.0.190:8080";
+}

+ 58 - 0
network/src/main/java/com/miekir/network/core/RetrofitInstaller.java

@@ -0,0 +1,58 @@
+package com.miekir.network.core;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.Objects;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/1/19 11:37
+ * Description: 初始化入口
+ */
+public class RetrofitInstaller extends ContentProvider {
+    public static Context mInstallerContext;
+
+    @Override
+    public boolean onCreate() {
+        mInstallerContext = Objects.requireNonNull(getContext()).getApplicationContext();
+        //RetrofitHelper.initClient(Objects.requireNonNull(getContext()).getApplicationContext());
+        return false;
+    }
+
+    @Nullable
+    @Override
+    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
+        return null;
+    }
+
+    @Nullable
+    @Override
+    public String getType(@NonNull Uri uri) {
+        return null;
+    }
+
+    @Nullable
+    @Override
+    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
+        return null;
+    }
+
+    @Override
+    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
+        return 0;
+    }
+
+    @Override
+    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
+        return 0;
+    }
+}

+ 53 - 0
network/src/main/java/com/miekir/network/core/base/BaseObserver.java

@@ -0,0 +1,53 @@
+package com.miekir.network.core.base;
+
+import com.miekir.network.constant.Code;
+import com.miekir.network.utils.ExceptionUtil;
+
+import io.reactivex.Observer;
+import io.reactivex.annotations.NonNull;
+import io.reactivex.disposables.Disposable;
+
+/**
+ * 返回结果处理
+ * @author Miekir
+ */
+
+public abstract class BaseObserver<T> implements Observer<BaseResponse<T>> {
+
+    @Override
+    public void onNext(@NonNull BaseResponse<T> response) {
+        try {
+            if (response.getCode() == Code.SUCCESS) {
+                onSuccess(response.getCode(), response.getContent());
+            } else if (response.getCode() == Code.TOKEN_TIMEOUT) {
+                // 重新登录
+            } else {
+                onFailure(response.getCode(), new Exception(response.getMessage()), response.getMessage());
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            onFailure(Code.COMMON, new Exception("null"), null);
+        }
+    }
+
+    @Override
+    public void onError(@NonNull Throwable e) {
+
+        e.printStackTrace();
+        onFailure(Code.COMMON, e, ExceptionUtil.exceptionHandler(e));
+    }
+
+    @Override
+    public void onComplete() {
+
+    }
+
+    @Override
+    public void onSubscribe(@NonNull Disposable d) {
+
+    }
+
+    public abstract void onSuccess(int code, T result);
+
+    public abstract void onFailure(int code, Throwable e, String errMsg);
+}

+ 56 - 0
network/src/main/java/com/miekir/network/core/base/BaseResponse.java

@@ -0,0 +1,56 @@
+package com.miekir.network.core.base;
+
+/**
+ * 统一返回封装
+ * @author Miekir
+ */
+
+public class BaseResponse<T> {
+    private int code;
+    private String message;
+    private String extra;
+    private T content;
+
+    /**
+     *
+     * @return 返回状态代码
+     */
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    /**
+     * @return 返回数据
+     */
+    public T getContent() {
+        return content;
+    }
+
+    public void setContent(T content) {
+        this.content = content;
+    }
+
+    /**
+     *
+     * @return 返回信息
+     */
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public String getExtra() {
+        return extra;
+    }
+
+    public void setExtra(String extra) {
+        this.extra = extra;
+    }
+}

+ 9 - 0
network/src/main/java/com/miekir/network/core/base/CommonBean.java

@@ -0,0 +1,9 @@
+package com.miekir.network.core.base;
+
+/**
+ * 公共返回内容
+ * @author Miekir
+ */
+
+public class CommonBean {
+}

+ 46 - 0
network/src/main/java/com/miekir/network/core/base/CommonObserver.java

@@ -0,0 +1,46 @@
+package com.miekir.network.core.base;
+
+import com.miekir.network.constant.Code;
+import com.miekir.network.utils.ExceptionUtil;
+
+import io.reactivex.Observer;
+import io.reactivex.annotations.NonNull;
+import io.reactivex.disposables.Disposable;
+
+/**
+ * 返回结果处理
+ * @author Miekir
+ */
+
+public abstract class CommonObserver<T> implements Observer<T> {
+
+    @Override
+    public void onNext(@NonNull T response) {
+        try {
+            onSuccess(response);
+        } catch (Exception e) {
+            e.printStackTrace();
+            onFailure(Code.COMMON, new Exception("null"), null);
+        }
+    }
+
+    @Override
+    public void onError(@NonNull Throwable e) {
+        e.printStackTrace();
+        onFailure(Code.COMMON, e, ExceptionUtil.exceptionHandler(e));
+    }
+
+    @Override
+    public void onComplete() {
+
+    }
+
+    @Override
+    public void onSubscribe(@NonNull Disposable d) {
+
+    }
+
+    public abstract void onSuccess(T result);
+
+    public abstract void onFailure(int code, Throwable e, String errMsg);
+}

+ 53 - 0
network/src/main/java/com/miekir/network/core/impl/LoadingObserver.java

@@ -0,0 +1,53 @@
+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.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;
+
+/**
+ * 带加载框的观察者
+ * 需要加载框时,调用onSubscribe同时显示加载框,
+ * 流程走到onComplete/onError时隐藏加载框。
+ * @author Miekir
+ */
+public abstract class LoadingObserver<T> extends BaseObserver<T> {
+    private BaseViewModel mViewModel;
+    private String mText;
+
+    public LoadingObserver(BaseViewModel viewModel) {
+        this(viewModel, ContextManager.getInstance().getContext().getString(R.string.network_loading));
+    }
+
+    public LoadingObserver(BaseViewModel viewModel, String text) {
+        this.mViewModel = viewModel;
+        this.mText = text;
+    }
+
+    @Override
+    public void onSubscribe(@NonNull Disposable d) {
+        super.onSubscribe(d);
+        if (d.isDisposed()) {
+            return;
+        }
+        mViewModel.showLoading(mText);
+    }
+
+    @Override
+    public void onComplete() {
+        super.onComplete();
+        mViewModel.dismissLoading();
+    }
+
+    @Override
+    public void onError(@NonNull Throwable e) {
+        super.onError(e);
+        mViewModel.dismissLoading();
+    }
+}

+ 62 - 0
network/src/main/java/com/miekir/network/core/impl/ProgressObserver.java

@@ -0,0 +1,62 @@
+package com.miekir.network.core.impl;
+
+import android.content.Context;
+
+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;
+
+/**
+ * 进度条观察者
+ * 需要进度条时,调用onSubscribe同时显示进度条,
+ * 流程走到onComplete/onError时隐藏进度条。
+ * @author Miekir
+ */
+
+public abstract class ProgressObserver<T> extends BaseObserver<T> {
+    private CustomProgressDialog mProgressDialog;
+    private Context mContext;
+    private String mText;
+
+    public ProgressObserver(Context context) {
+        this(context, context.getString(R.string.network_loading));
+    }
+
+    public ProgressObserver(Context context, String text) {
+        this.mContext = context;
+        this.mText = text;
+    }
+
+    @Override
+    public void onSubscribe(@NonNull Disposable d) {
+        super.onSubscribe(d);
+        if (d.isDisposed()) {
+            return;
+        }
+        if (mProgressDialog == null) {
+            mProgressDialog = new CustomProgressDialog(mContext, mText);
+            mProgressDialog.setCancelable(true);
+            mProgressDialog.setCanceledOnTouchOutside(false);
+        }
+        mProgressDialog.show();
+    }
+
+    @Override
+    public void onComplete() {
+        super.onComplete();
+        if (mProgressDialog != null) {
+            mProgressDialog.dismiss();
+        }
+    }
+
+    @Override
+    public void onError(@NonNull Throwable e) {
+        super.onError(e);
+        if (mProgressDialog != null) {
+            mProgressDialog.dismiss();
+        }
+    }
+}

+ 46 - 0
network/src/main/java/com/miekir/network/utils/ExceptionUtil.java

@@ -0,0 +1,46 @@
+package com.miekir.network.utils;
+
+import android.net.ParseException;
+
+import org.json.JSONException;
+
+import java.net.SocketTimeoutException;
+import java.net.UnknownHostException;
+
+import retrofit2.HttpException;
+
+/**
+ * 异常信息
+ * @author Miekir
+ */
+
+public class ExceptionUtil {
+    public static String exceptionHandler(Throwable e) {
+        String errorMsg = "未知错误";
+        if (e instanceof UnknownHostException) {
+            errorMsg = "网络不可用";
+        } else if (e instanceof SocketTimeoutException) {
+            errorMsg = "请求网络超时";
+        } else if (e instanceof HttpException) {
+            HttpException httpException = (HttpException) e;
+            errorMsg = convertStatusCode(httpException);
+        } else if (e instanceof ParseException || e instanceof JSONException) {
+            errorMsg = "数据解析错误";
+        }
+        return errorMsg;
+    }
+
+    public static String convertStatusCode(HttpException httpException) {
+        String msg;
+        if (httpException.code() >= 500 && httpException.code() < 600) {
+            msg = "服务器处理请求出错";
+        } else if (httpException.code() >= 400 && httpException.code() < 500) {
+            msg = "服务器无法处理请求";
+        } else if (httpException.code() >= 300 && httpException.code() < 400) {
+            msg = "请求被重定向到其他页面";
+        } else {
+            msg = httpException.message();
+        }
+        return msg;
+    }
+}

+ 44 - 0
network/src/main/java/com/miekir/network/utils/JsonTool.java

@@ -0,0 +1,44 @@
+package com.miekir.network.utils;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.google.gson.reflect.TypeToken;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 网络工具类
+ * @author Miekir
+ */
+public class JsonTool {
+
+    /**
+     * @param params  请求参数
+     * @return 请求体
+     */
+    public static JsonObject getJsonFromKeyValueList(Map<String, Object> params) {
+        JsonObject contentObject = new JsonObject();
+        if (params == null || params.size() == 0) {
+            return contentObject;
+        }
+
+        for (Map.Entry<String, Object> entry : params.entrySet()) {
+            if (entry.getValue() instanceof String) {
+                contentObject.addProperty(entry.getKey(), String.valueOf(entry.getValue()));
+            } else if (entry.getValue() instanceof Number) {
+                contentObject.addProperty(entry.getKey(), (Number) entry.getValue());
+            } else if (entry.getValue() instanceof Boolean) {
+                contentObject.addProperty(entry.getKey(), (Boolean) entry.getValue());
+            } else if (entry.getValue() instanceof List<?>) {
+                List<?> list = (List<?>) entry.getValue();
+                JsonArray jsonArray = new Gson().toJsonTree(list, new TypeToken<List<?>>() {
+                }.getType()).getAsJsonArray();
+                contentObject.add(entry.getKey(), jsonArray);
+            }
+        }
+
+        return contentObject;
+    }
+}

+ 42 - 0
network/src/main/java/com/miekir/network/widget/CustomProgressDialog.java

@@ -0,0 +1,42 @@
+package com.miekir.network.widget;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.view.Gravity;
+import android.widget.TextView;
+
+import com.miekir.network.R;
+
+/**
+ * 网络请求进度条
+ * @author Miekir
+ */
+
+public class CustomProgressDialog extends Dialog {
+    private static final String TAG = "CustomProgressDialog";
+
+    public CustomProgressDialog(Context context, String strMessage) {
+        this(context, R.style.NetworkCustomProgressDialog, strMessage);
+    }
+
+    private CustomProgressDialog(Context context, int theme, String strMessage) {
+        super(context, theme);
+        this.setContentView(R.layout.dialog_net_loading);
+        this.getWindow().getAttributes().gravity = Gravity.CENTER;
+        TextView tvMsg = (TextView) this.findViewById(R.id.network_progress_text);
+        if (tvMsg != null) {
+            tvMsg.setText(strMessage);
+        }
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+    }
+
+    public void setMessage(String msg) {
+        TextView tvMsg = (TextView) this.findViewById(R.id.network_progress_text);
+        if (tvMsg != null) {
+            tvMsg.setText(msg);
+        }
+    }
+}

+ 8 - 0
network/src/main/res/drawable/bg_dialog_net_loading.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+
+    <corners android:radius="10dp" />
+    <solid android:color="#ffffff" />
+
+</shape>

+ 32 - 0
network/src/main/res/layout/dialog_net_loading.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:background="@drawable/bg_dialog_net_loading"
+    android:gravity="center"
+    android:minWidth="110dp"
+    android:orientation="vertical"
+    android:paddingBottom="5dp"
+    android:paddingLeft="10dp"
+    android:paddingRight="10dp"
+    android:paddingTop="10dp">
+
+    <!-- 暂时去掉
+        android:indeterminateDrawable="@drawable/loading_progress_pic_list_bg"该代码 -->
+    <ProgressBar
+        android:id="@+id/network_progress_bar"
+        style="?android:attr/progressBarStyleLarge"
+        android:layout_width="50dp"
+        android:layout_height="50dp"
+        android:layout_gravity="center" />
+
+    <TextView
+        android:id="@+id/network_progress_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:padding="5dp"
+        android:text="@string/network_loading"
+        android:textColor="#999999"
+        android:textSize="15sp"
+        android:visibility="gone"/>
+</LinearLayout>

+ 4 - 0
network/src/main/res/values-zh-rCN/strings.xml

@@ -0,0 +1,4 @@
+<resources>
+    <string name="app_name">network</string>
+    <string name="network_loading">加载中…</string>
+</resources>

+ 4 - 0
network/src/main/res/values/strings.xml

@@ -0,0 +1,4 @@
+<resources>
+    <string name="app_name">network</string>
+    <string name="network_loading">Loading…</string>
+</resources>

+ 19 - 0
network/src/main/res/values/styles.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <style name="NetworkMyDialogStyle" parent="Theme.AppCompat.Light.NoActionBar">
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:windowFrame">@null</item>
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowIsFloating">true</item>
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowContentOverlay">@null</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
+        <item name="android:backgroundDimEnabled">true</item>
+    </style>
+
+    <!--进度条提示框-->
+    <style name="NetworkCustomProgressDialog" parent="@style/NetworkMyDialogStyle">
+        <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
+    </style>
+</resources>

+ 17 - 0
network/src/test/java/com/miekir/network/ExampleUnitTest.java

@@ -0,0 +1,17 @@
+package com.miekir.network;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+public class ExampleUnitTest {
+    @Test
+    public void addition_isCorrect() {
+        assertEquals(4, 2 + 2);
+    }
+}

+ 1 - 0
settings.gradle

@@ -1,2 +1,3 @@
+include ':network'
 include ':app', ':mvp', ':common'
 rootProject.name='NewMvp'