├── .idea
├── .name
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── vcs.xml
├── modules.xml
├── runConfigurations.xml
├── compiler.xml
├── gradle.xml
└── misc.xml
├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ └── styles.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── values-w820dp
│ │ │ │ └── dimens.xml
│ │ │ ├── drawable
│ │ │ │ └── iconfont_shouqi.xml
│ │ │ └── layout
│ │ │ │ └── activity_main.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── lpf
│ │ │ │ └── mvptest
│ │ │ │ ├── base
│ │ │ │ ├── BaseBean.java
│ │ │ │ ├── BaseModel.java
│ │ │ │ ├── MyApplication.java
│ │ │ │ ├── IBasePresenter.java
│ │ │ │ ├── IBaseView.java
│ │ │ │ └── BasePresenterImpl.java
│ │ │ │ ├── view
│ │ │ │ ├── PhoneNumInfoView.java
│ │ │ │ └── ui
│ │ │ │ │ └── MainActivity.java
│ │ │ │ ├── utils
│ │ │ │ ├── AppContextUtil.java
│ │ │ │ └── NetUtil.java
│ │ │ │ ├── service
│ │ │ │ └── PhoneNunInfoService.java
│ │ │ │ ├── presenter
│ │ │ │ └── PhonePresenterImpl.java
│ │ │ │ ├── model
│ │ │ │ ├── PhoneModelImpl.java
│ │ │ │ └── PhoneNumInfo.java
│ │ │ │ └── helper
│ │ │ │ └── RetrofitManager.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── lpf
│ │ │ └── mvptest
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── lpf
│ │ └── mvptest
│ │ └── ApplicationTest.java
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── gradle.properties
├── gradlew.bat
├── gradlew
└── README.md
/.idea/.name:
--------------------------------------------------------------------------------
1 | MVPTest
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | MVPTest
3 |
4 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/183619962/MVPTest/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/183619962/MVPTest/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/183619962/MVPTest/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/183619962/MVPTest/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/183619962/MVPTest/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/183619962/MVPTest/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Feb 19 21:36:54 CST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lpf/mvptest/base/BaseBean.java:
--------------------------------------------------------------------------------
1 | package com.lpf.mvptest.base;
2 |
3 | /**
4 | * 接口的公共协议头
5 | */
6 | public class BaseBean {
7 |
8 | public String success;
9 |
10 | public String getSuccess() {
11 | return success;
12 | }
13 |
14 | public void setSuccess(String success) {
15 | this.success = success;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lpf/mvptest/base/BaseModel.java:
--------------------------------------------------------------------------------
1 | package com.lpf.mvptest.base;
2 |
3 |
4 | import com.lpf.mvptest.helper.RetrofitManager;
5 |
6 | /**
7 | * 业务对象的基类
8 | */
9 | public class BaseModel {
10 | //retrofit请求数据的管理类
11 | public RetrofitManager retrofitManager;
12 |
13 | public BaseModel() {
14 | retrofitManager = RetrofitManager.builder();
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/test/java/com/lpf/mvptest/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.lpf.mvptest;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/lpf/mvptest/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.lpf.mvptest;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/lpf/mvptest/view/PhoneNumInfoView.java:
--------------------------------------------------------------------------------
1 | package com.lpf.mvptest.view;
2 |
3 | import com.lpf.mvptest.base.IBaseView;
4 | import com.lpf.mvptest.model.PhoneNumInfo;
5 |
6 | /**
7 | * 号码归属地查询的View
8 | * 如果没有什么特殊的动作,可以不用定义这个view,在activity里面直接实现IBaseView接口即可
9 | *
10 | */
11 | public interface PhoneNumInfoView extends IBaseView {
12 | //这里这么写的目的是为了明确view的作用,如果这里的view有更多的操作,可以在这里定义更多的接口
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lpf/mvptest/utils/AppContextUtil.java:
--------------------------------------------------------------------------------
1 | package com.lpf.mvptest.utils;
2 |
3 | import android.content.Context;
4 |
5 | public class AppContextUtil {
6 | private static Context sContext;
7 |
8 | private AppContextUtil() {
9 |
10 | }
11 |
12 | public static void init(Context context) {
13 | sContext = context;
14 | }
15 |
16 | public static Context getInstance() {
17 | if (sContext == null) {
18 | throw new NullPointerException("the context is null,please init AppContextUtil in Application first.");
19 | }
20 | return sContext;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lpf/mvptest/base/MyApplication.java:
--------------------------------------------------------------------------------
1 | package com.lpf.mvptest.base;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 |
6 | import com.lpf.mvptest.utils.AppContextUtil;
7 |
8 | /**
9 | * Created by laucherish on 16/3/17.
10 | */
11 | public class MyApplication extends Application {
12 |
13 | private static Context mApplicationContext;
14 |
15 | @Override
16 | public void onCreate() {
17 | super.onCreate();
18 | AppContextUtil.init(this);
19 | mApplicationContext = this;
20 | }
21 |
22 | // 获取ApplicationContext
23 | public static Context getContext() {
24 | return mApplicationContext;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in E:\bf\sdk_20160316\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lpf/mvptest/base/IBasePresenter.java:
--------------------------------------------------------------------------------
1 | package com.lpf.mvptest.base;
2 |
3 | /**
4 | * 控制器的基础回调接口
5 | * Presenter用于接受model获取(加载)数据后的回调
6 | * Created by Administrator on 2016/3/23.
7 | */
8 | public interface IBasePresenter {
9 | /**
10 | * 开始请求之前
11 | */
12 | void beforeRequest(int requestTag);
13 |
14 | /**
15 | * 请求失败
16 | *
17 | * @param e 失败的原因
18 | */
19 | void requestError(Throwable e, int requestTag);
20 |
21 | /**
22 | * 请求结束
23 | */
24 | void requestComplete(int requestTag);
25 |
26 | /**
27 | * 请求成功
28 | *
29 | * @param callBack 根据业务返回相应的数据
30 | */
31 | void retuestSuccess(T callBack, int requestTag);
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/iconfont_shouqi.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | ## Project-wide Gradle settings.
2 | #
3 | # For more details on how to configure your build environment visit
4 | # http://www.gradle.org/docs/current/userguide/build_environment.html
5 | #
6 | # Specifies the JVM arguments used for the daemon process.
7 | # The setting is particularly useful for tweaking memory settings.
8 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
10 | #
11 | # When configured, Gradle will run in incubating parallel mode.
12 | # This option should only be used with decoupled projects. More details, visit
13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
14 | # org.gradle.parallel=true
15 | #Sun Apr 03 23:17:02 CST 2016
16 | systemProp.http.proxyHost=sdk.gdgshanghai.com
17 | systemProp.http.proxyPort=8000
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lpf/mvptest/base/IBaseView.java:
--------------------------------------------------------------------------------
1 | package com.lpf.mvptest.base;
2 |
3 | /**
4 | * 视图(View层)基础回调接口
5 | */
6 | public interface IBaseView {
7 | /**
8 | * 通过toast提示用户
9 | *
10 | * @param msg 提示的信息
11 | * @param requestTag 请求标识
12 | */
13 | void toast(String msg, int requestTag);
14 |
15 | /**
16 | * 显示进度
17 | *
18 | * @param requestTag 请求标识
19 | */
20 | void showProgress(int requestTag);
21 |
22 | /**
23 | * 隐藏进度
24 | *
25 | * @param requestTag 请求标识
26 | */
27 | void hideProgress(int requestTag);
28 |
29 | /**
30 | * 基础的请求的返回
31 | *
32 | * @param data
33 | * @param requestTag 请求标识
34 | */
35 | void loadDataSuccess(T data, int requestTag);
36 |
37 | /**
38 | * 基础请求的错误
39 | *
40 | * @param e
41 | * @param requestTag 请求标识
42 | */
43 | void loadDataError(Throwable e, int requestTag);
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lpf/mvptest/service/PhoneNunInfoService.java:
--------------------------------------------------------------------------------
1 | package com.lpf.mvptest.service;
2 |
3 | import com.lpf.mvptest.helper.RetrofitManager;
4 | import com.lpf.mvptest.model.PhoneNumInfo;
5 |
6 | import retrofit2.http.GET;
7 | import retrofit2.http.Headers;
8 | import retrofit2.http.POST;
9 | import retrofit2.http.Path;
10 | import retrofit2.http.Query;
11 | import rx.Observable;
12 |
13 | /**
14 | * 归属地请求的服务
15 | */
16 | public interface PhoneNunInfoService {
17 | //http://api.k780.com:88/?app=phone.get&phone={phoneNum}&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json
18 | @Headers(RetrofitManager.CACHE_CONTROL_AGE + RetrofitManager.CACHE_STALE_LONG)
19 | @GET("/")
20 | Observable getBeforeNews(@Query("app") String app
21 | , @Query("phone") String phone
22 | , @Query("appkey") String appkey
23 | , @Query("sign") String sign
24 | , @Query("format") String format);
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lpf/mvptest/presenter/PhonePresenterImpl.java:
--------------------------------------------------------------------------------
1 | package com.lpf.mvptest.presenter;
2 |
3 | import android.content.Context;
4 |
5 | import com.lpf.mvptest.base.BasePresenterImpl;
6 | import com.lpf.mvptest.model.PhoneModelImpl;
7 | import com.lpf.mvptest.model.PhoneNumInfo;
8 | import com.lpf.mvptest.view.PhoneNumInfoView;
9 |
10 |
11 | /**
12 | * Presenter的实现,协调model去加载数据,获取model加载完成时候的回调,控制界面加载框的显示与隐藏
13 | */
14 | public class PhonePresenterImpl extends BasePresenterImpl {
15 | private PhoneModelImpl phoneModel;
16 | private Context mContext;
17 |
18 |
19 | public PhonePresenterImpl(PhoneNumInfoView phoneNumInfoView, Context context) {
20 | super(phoneNumInfoView);
21 | this.mContext = context;
22 | phoneModel = new PhoneModelImpl(mContext);
23 | }
24 |
25 | /**
26 | * 获取归属地信息
27 | *
28 | * @param phoneNum 电话号码
29 | * @param requestTag 请求标识
30 | */
31 | public void getPhoneNumInfo(String phoneNum, int requestTag) {
32 | phoneModel.loadPhoneNumInfo(phoneNum, this, requestTag);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lpf/mvptest/base/BasePresenterImpl.java:
--------------------------------------------------------------------------------
1 | package com.lpf.mvptest.base;
2 |
3 | /**
4 | * 代理对象的基础实现
5 | *
6 | * @param 视图接口对象(view) 具体业务各自继承自IBaseView
7 | * @param 业务请求返回的具体对象
8 | */
9 | public class BasePresenterImpl implements IBasePresenter {
10 | public IBaseView iView;
11 |
12 | /**
13 | * 构造方法
14 | *
15 | * @param view 具体业务的接口对象
16 | */
17 | public BasePresenterImpl(T view) {
18 | this.iView = view;
19 | }
20 |
21 | @Override
22 | public void beforeRequest(int requestTag) {
23 | //显示LOading
24 | iView.showProgress(requestTag);
25 | }
26 |
27 | @Override
28 | public void requestError(Throwable e, int requestTag) {
29 | //通知UI具体的错误信息
30 | iView.loadDataError(e,requestTag);
31 | }
32 |
33 | @Override
34 | public void requestComplete(int requestTag) {
35 | //隐藏Loading
36 | iView.hideProgress(requestTag);
37 | }
38 |
39 | @Override
40 | public void retuestSuccess(V callBack, int requestTag) {
41 | //将获取的数据回调给UI(activity或者fragment)
42 | iView.loadDataSuccess(callBack, requestTag);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.2"
6 |
7 | defaultConfig {
8 | applicationId "com.lpf.mvptest"
9 | minSdkVersion 10
10 | targetSdkVersion 23
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | testCompile 'junit:junit:4.12'
25 | compile 'com.android.support:appcompat-v7:23.2.1'
26 | // retrofit2 + okhttp3
27 | compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
28 | compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'
29 | compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
30 | compile 'com.squareup.okhttp3:okhttp:3.2.0'
31 | compile 'com.squareup.okhttp3:logging-interceptor:3.2.0'
32 | // rxjava
33 | compile 'io.reactivex:rxandroid:1.1.0'
34 | compile 'io.reactivex:rxjava:1.1.0'
35 | // stetho
36 | compile 'com.facebook.stetho:stetho:1.3.1'
37 | compile 'com.facebook.stetho:stetho-okhttp3:1.3.1'
38 |
39 | compile 'com.jakewharton:butterknife:7.0.1'
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
16 |
17 |
21 |
22 |
27 |
28 |
29 |
30 |
35 |
36 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lpf/mvptest/model/PhoneModelImpl.java:
--------------------------------------------------------------------------------
1 | package com.lpf.mvptest.model;
2 |
3 | import android.content.Context;
4 |
5 | import com.lpf.mvptest.base.BaseModel;
6 | import com.lpf.mvptest.base.IBasePresenter;
7 | import com.lpf.mvptest.service.PhoneNunInfoService;
8 |
9 | import rx.Subscriber;
10 | import rx.android.schedulers.AndroidSchedulers;
11 | import rx.schedulers.Schedulers;
12 |
13 | /**
14 | * 获取号码归属地的具体Model实现
15 | */
16 | public class PhoneModelImpl extends BaseModel {
17 | private Context mContext;
18 | private PhoneNunInfoService phoneNunInfoService;
19 |
20 | public PhoneModelImpl(Context context) {
21 | super();
22 | this.mContext = context;
23 | phoneNunInfoService = retrofitManager.getService();
24 | }
25 |
26 | public void loadPhoneNumInfo(String phoneNum, final IBasePresenter callBack, final int requestTag) {
27 | phoneNunInfoService.getBeforeNews("phone.get", phoneNum, "10003", "b59bc3ef6191eb9f747dd4e83c99f2a4", "json")
28 | .subscribeOn(Schedulers.io())
29 | .observeOn(AndroidSchedulers.mainThread())
30 | .subscribe(new Subscriber() {
31 | @Override
32 | public void onStart() {
33 | super.onStart();
34 | callBack.beforeRequest(requestTag);
35 | }
36 |
37 | @Override
38 | public void onCompleted() {
39 | callBack.requestComplete(requestTag);
40 | }
41 |
42 | @Override
43 | public void onError(Throwable e) {
44 | callBack.requestError(e, requestTag);
45 | }
46 |
47 | @Override
48 | public void onNext(PhoneNumInfo phoneNumInfo) {
49 | if (null != phoneNumInfo && phoneNumInfo.getSuccess().equals("1"))
50 | callBack.retuestSuccess(phoneNumInfo, requestTag);
51 | else if (null != phoneNumInfo && phoneNumInfo.getSuccess().equals("0"))
52 | callBack.requestError(new Exception(phoneNumInfo.getMsg()), requestTag);
53 | else
54 | callBack.requestError(new Exception("获取数据错误,请重试!"), requestTag);
55 | }
56 | });
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lpf/mvptest/utils/NetUtil.java:
--------------------------------------------------------------------------------
1 | package com.lpf.mvptest.utils;
2 |
3 | import android.content.Context;
4 | import android.net.ConnectivityManager;
5 | import android.net.NetworkInfo;
6 |
7 | public class NetUtil {
8 |
9 | private NetUtil() {
10 | }
11 |
12 | public static boolean isNetworkConnected() {
13 | if (AppContextUtil.getInstance() != null) {
14 | ConnectivityManager mConnectivityManager = (ConnectivityManager) AppContextUtil.getInstance()
15 | .getSystemService(Context.CONNECTIVITY_SERVICE);
16 | NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
17 | if (mNetworkInfo != null) {
18 | return mNetworkInfo.isAvailable();
19 | }
20 | }
21 | return false;
22 | }
23 |
24 | public static boolean isWifiConnected() {
25 | if (AppContextUtil.getInstance() != null) {
26 | ConnectivityManager mConnectivityManager = (ConnectivityManager) AppContextUtil.getInstance()
27 | .getSystemService(Context.CONNECTIVITY_SERVICE);
28 | NetworkInfo mWiFiNetworkInfo = mConnectivityManager
29 | .getNetworkInfo(ConnectivityManager.TYPE_WIFI);
30 | if (mWiFiNetworkInfo != null) {
31 | return mWiFiNetworkInfo.isAvailable();
32 | }
33 | }
34 | return false;
35 | }
36 |
37 | public static boolean isMobileConnected() {
38 | if (AppContextUtil.getInstance() != null) {
39 | ConnectivityManager mConnectivityManager = (ConnectivityManager) AppContextUtil.getInstance()
40 | .getSystemService(Context.CONNECTIVITY_SERVICE);
41 | NetworkInfo mMobileNetworkInfo = mConnectivityManager
42 | .getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
43 | if (mMobileNetworkInfo != null) {
44 | return mMobileNetworkInfo.isAvailable();
45 | }
46 | }
47 | return false;
48 | }
49 |
50 | public static int getConnectedType() {
51 | if (AppContextUtil.getInstance() != null) {
52 | ConnectivityManager mConnectivityManager = (ConnectivityManager) AppContextUtil.getInstance()
53 | .getSystemService(Context.CONNECTIVITY_SERVICE);
54 | NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
55 | if (mNetworkInfo != null && mNetworkInfo.isAvailable()) {
56 | return mNetworkInfo.getType();
57 | }
58 | }
59 | return -1;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lpf/mvptest/view/ui/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.lpf.mvptest.view.ui;
2 |
3 | import android.app.ProgressDialog;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.os.Bundle;
6 | import android.view.View;
7 | import android.widget.Button;
8 | import android.widget.EditText;
9 | import android.widget.TextView;
10 |
11 | import com.lpf.mvptest.R;
12 | import com.lpf.mvptest.base.IBaseView;
13 | import com.lpf.mvptest.model.PhoneNumInfo;
14 | import com.lpf.mvptest.presenter.PhonePresenterImpl;
15 | import com.lpf.mvptest.view.PhoneNumInfoView;
16 |
17 | public class MainActivity extends AppCompatActivity implements View.OnClickListener, PhoneNumInfoView {
18 | //获取归属地的请求标识,用回页面多个地方请求的时候,标识是那一个完成并回调了
19 | private static final int REQUESTMSG = 0;
20 |
21 | //电话号码的EditText
22 | private EditText phoneNum;
23 | //获取归属地的按钮
24 | private Button getPhoneInfo;
25 | //用于显示最后获取的结果
26 | private TextView msg;
27 | //Loading弹框
28 | private ProgressDialog progressDialog;
29 | //获取归属地的代理对象
30 | private PhonePresenterImpl phonePresenter;
31 |
32 | @Override
33 | protected void onCreate(Bundle savedInstanceState) {
34 | super.onCreate(savedInstanceState);
35 | setContentView(R.layout.activity_main);
36 |
37 | initView();
38 |
39 | }
40 |
41 | private void initView() {
42 | //初始化控件
43 | phoneNum = (EditText) findViewById(R.id.phonenum);
44 | getPhoneInfo = (Button) findViewById(R.id.getphoneinfo);
45 | msg = (TextView) findViewById(R.id.msg);
46 | getPhoneInfo.setOnClickListener(this);
47 |
48 | //初始化Loading
49 | progressDialog = new ProgressDialog(this);
50 | progressDialog.setMessage("Loading");
51 |
52 | //初始化代理对象
53 | phonePresenter = new PhonePresenterImpl(this, this);
54 | }
55 |
56 | @Override
57 | public void toast(String msg, int requestTag) {
58 |
59 | }
60 |
61 | @Override
62 | public void showProgress(int requestTag) {
63 | if (null != progressDialog && !progressDialog.isShowing()) {
64 | progressDialog.show();
65 | }
66 | }
67 |
68 | @Override
69 | public void hideProgress(int requestTag) {
70 | if (null != progressDialog && progressDialog.isShowing()) {
71 | progressDialog.dismiss();
72 | }
73 | }
74 |
75 | @Override
76 | public void loadDataSuccess(PhoneNumInfo phoneNumInfo, int requestTag) {
77 | msg.setText(phoneNumInfo.toString());
78 | }
79 |
80 | @Override
81 | public void loadDataError(Throwable e, int requestTag) {
82 | msg.setText(e.getMessage());
83 | }
84 |
85 | @Override
86 | public void onClick(View v) {
87 | switch (v.getId()) {
88 | case R.id.getphoneinfo:
89 | phonePresenter.getPhoneNumInfo(phoneNum.getText().toString(), REQUESTMSG);
90 | break;
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lpf/mvptest/helper/RetrofitManager.java:
--------------------------------------------------------------------------------
1 | package com.lpf.mvptest.helper;
2 |
3 | import com.facebook.stetho.okhttp3.StethoInterceptor;
4 | import com.lpf.mvptest.base.MyApplication;
5 | import com.lpf.mvptest.service.PhoneNunInfoService;
6 | import com.lpf.mvptest.utils.NetUtil;
7 |
8 | import java.io.File;
9 | import java.io.IOException;
10 | import java.util.concurrent.TimeUnit;
11 |
12 | import okhttp3.Cache;
13 | import okhttp3.CacheControl;
14 | import okhttp3.Interceptor;
15 | import okhttp3.OkHttpClient;
16 | import okhttp3.Request;
17 | import okhttp3.Response;
18 | import okhttp3.logging.HttpLoggingInterceptor;
19 | import retrofit2.Retrofit;
20 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
21 | import retrofit2.converter.gson.GsonConverterFactory;
22 |
23 | /**
24 | * Retrofit管理类
25 |
26 | */
27 | public class RetrofitManager {
28 |
29 | //地址
30 | public static final String BASE_PHONENUMINFO_URL = "http://api.k780.com:88";
31 |
32 | //短缓存有效期为1分钟
33 | public static final int CACHE_STALE_SHORT = 60;
34 | //长缓存有效期为7天
35 | public static final int CACHE_STALE_LONG = 60 * 60 * 24 * 7;
36 |
37 | public static final String CACHE_CONTROL_AGE = "Cache-Control: public, max-age=";
38 |
39 | //查询缓存的Cache-Control设置,为if-only-cache时只查询缓存而不会请求服务器,max-stale可以配合设置缓存失效时间
40 | public static final String CACHE_CONTROL_CACHE = "only-if-cached, max-stale=" + CACHE_STALE_LONG;
41 | //查询网络的Cache-Control设置,头部Cache-Control设为max-age=0时则不会使用缓存而请求服务器
42 | public static final String CACHE_CONTROL_NETWORK = "max-age=0";
43 | private static OkHttpClient mOkHttpClient;
44 | private final PhoneNunInfoService phoneNunInfoService;
45 |
46 | public static RetrofitManager builder() {
47 | return new RetrofitManager();
48 | }
49 |
50 | public PhoneNunInfoService getService() {
51 | return phoneNunInfoService;
52 | }
53 |
54 | private RetrofitManager() {
55 | initOkHttpClient();
56 |
57 | Retrofit retrofit = new Retrofit.Builder()
58 | .baseUrl(BASE_PHONENUMINFO_URL)
59 | .client(mOkHttpClient)
60 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
61 | .addConverterFactory(GsonConverterFactory.create())
62 | .build();
63 | phoneNunInfoService = retrofit.create(PhoneNunInfoService.class);
64 | }
65 |
66 | private void initOkHttpClient() {
67 | HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
68 | interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
69 | if (mOkHttpClient == null) {
70 | synchronized (RetrofitManager.class) {
71 | if (mOkHttpClient == null) {
72 |
73 | // 指定缓存路径,缓存大小100Mb
74 | Cache cache = new Cache(new File(MyApplication.getContext().getCacheDir(), "HttpCache"),
75 | 1024 * 1024 * 100);
76 |
77 | mOkHttpClient = new OkHttpClient.Builder()
78 | .cache(cache)
79 | .addInterceptor(mRewriteCacheControlInterceptor)
80 | .addNetworkInterceptor(mRewriteCacheControlInterceptor)
81 | .addInterceptor(interceptor)
82 | .addNetworkInterceptor(new StethoInterceptor())
83 | .retryOnConnectionFailure(true)
84 | .connectTimeout(15, TimeUnit.SECONDS)
85 | .build();
86 | }
87 | }
88 | }
89 | }
90 |
91 | // 云端响应头拦截器,用来配置缓存策略
92 | private Interceptor mRewriteCacheControlInterceptor = new Interceptor() {
93 | @Override
94 | public Response intercept(Chain chain) throws IOException {
95 | Request request = chain.request();
96 | if (!NetUtil.isNetworkConnected()) {
97 | request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();
98 | }
99 | Response originalResponse = chain.proceed(request);
100 | if (NetUtil.isNetworkConnected()) {
101 | //有网的时候读接口上的@Headers里的配置,你可以在这里进行统一的设置
102 | String cacheControl = request.cacheControl().toString();
103 | return originalResponse.newBuilder().header("Cache-Control", cacheControl)
104 | .removeHeader("Pragma").build();
105 | } else {
106 | return originalResponse.newBuilder()
107 | .header("Cache-Control", "public, only-if-cached, max-stale=" + CACHE_STALE_LONG)
108 | .removeHeader("Pragma").build();
109 | }
110 | }
111 | };
112 | }
113 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lpf/mvptest/model/PhoneNumInfo.java:
--------------------------------------------------------------------------------
1 | package com.lpf.mvptest.model;
2 |
3 |
4 | import com.lpf.mvptest.base.BaseBean;
5 |
6 | /**
7 | * 电话号码的归属地及其他信息的对象
8 | * Created by Administrator on 2016/3/23.
9 | */
10 | public class PhoneNumInfo extends BaseBean {
11 |
12 |
13 | /**
14 | * success : 1
15 | * result : {"status":"ALREADY_ATT","phone":"13828824552","area":"0755","postno":"518000","att":"中国,广东,深圳","ctype":"中国移动138卡","par":"1382882","prefix":"138","operators":"中国移动","style_simcall":"中国,广东,深圳","style_citynm":"中华人民共和国,广东省,深圳市"}
16 | */
17 |
18 | /**
19 | * status : ALREADY_ATT
20 | * phone : 13828824552
21 | * area : 0755
22 | * postno : 518000
23 | * att : 中国,广东,深圳
24 | * ctype : 中国移动138卡
25 | * par : 1382882
26 | * prefix : 138
27 | * operators : 中国移动
28 | * style_simcall : 中国,广东,深圳
29 | * style_citynm : 中华人民共和国,广东省,深圳市
30 | */
31 |
32 | private ResultEntity result;
33 | /**
34 | * msg : 手机号码不正确
35 | * msgid : 1000801
36 | */
37 |
38 | private String msg;
39 |
40 | private String msgid;
41 |
42 | public ResultEntity getResult() {
43 | return result;
44 | }
45 |
46 | public void setResult(ResultEntity result) {
47 | this.result = result;
48 | }
49 |
50 | public String getMsg() {
51 | return msg;
52 | }
53 |
54 | public void setMsg(String msg) {
55 | this.msg = msg;
56 | }
57 |
58 | public String getMsgid() {
59 | return msgid;
60 | }
61 |
62 | public void setMsgid(String msgid) {
63 | this.msgid = msgid;
64 | }
65 |
66 | public static class ResultEntity {
67 | private String status;
68 | private String phone;
69 | private String area;
70 | private String postno;
71 | private String att;
72 | private String ctype;
73 | private String par;
74 | private String prefix;
75 | private String operators;
76 | private String style_simcall;
77 | private String style_citynm;
78 |
79 | public String getStatus() {
80 | return status;
81 | }
82 |
83 | public void setStatus(String status) {
84 | this.status = status;
85 | }
86 |
87 | public String getPhone() {
88 | return phone;
89 | }
90 |
91 | public void setPhone(String phone) {
92 | this.phone = phone;
93 | }
94 |
95 | public String getArea() {
96 | return area;
97 | }
98 |
99 | public void setArea(String area) {
100 | this.area = area;
101 | }
102 |
103 | public String getPostno() {
104 | return postno;
105 | }
106 |
107 | public void setPostno(String postno) {
108 | this.postno = postno;
109 | }
110 |
111 | public String getAtt() {
112 | return att;
113 | }
114 |
115 | public void setAtt(String att) {
116 | this.att = att;
117 | }
118 |
119 | public String getCtype() {
120 | return ctype;
121 | }
122 |
123 | public void setCtype(String ctype) {
124 | this.ctype = ctype;
125 | }
126 |
127 | public String getPar() {
128 | return par;
129 | }
130 |
131 | public void setPar(String par) {
132 | this.par = par;
133 | }
134 |
135 | public String getPrefix() {
136 | return prefix;
137 | }
138 |
139 | public void setPrefix(String prefix) {
140 | this.prefix = prefix;
141 | }
142 |
143 | public String getOperators() {
144 | return operators;
145 | }
146 |
147 | public void setOperators(String operators) {
148 | this.operators = operators;
149 | }
150 |
151 | public String getStyle_simcall() {
152 | return style_simcall;
153 | }
154 |
155 | public void setStyle_simcall(String style_simcall) {
156 | this.style_simcall = style_simcall;
157 | }
158 |
159 | public String getStyle_citynm() {
160 | return style_citynm;
161 | }
162 |
163 | public void setStyle_citynm(String style_citynm) {
164 | this.style_citynm = style_citynm;
165 | }
166 |
167 | @Override
168 | public String toString() {
169 | return "ResultEntity{" +
170 | "status='" + status + '\'' +
171 | ", phone='" + phone + '\'' +
172 | ", area='" + area + '\'' +
173 | ", postno='" + postno + '\'' +
174 | ", att='" + att + '\'' +
175 | ", ctype='" + ctype + '\'' +
176 | ", par='" + par + '\'' +
177 | ", prefix='" + prefix + '\'' +
178 | ", operators='" + operators + '\'' +
179 | ", style_simcall='" + style_simcall + '\'' +
180 | ", style_citynm='" + style_citynm + '\'' +
181 | '}';
182 | }
183 | }
184 |
185 | @Override
186 | public String toString() {
187 | return "PhoneNumInfo{" +
188 | "success='" + success + '\'' +
189 | ", result=" + result +
190 | '}';
191 | }
192 | }
193 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [toc]
2 |
3 |
4 | **转载请指明出处:[http://blog.csdn.net/lupengfei1009/article/details/50989066](http://blog.csdn.net/lupengfei1009/article/details/50989066)**
5 |
6 | 这段时间看了不少基于MVP设计模式,然后结合RxJava+Retrofit写的开源项目,深受感触,为了能让更多像我这种基层码畜也能够体验一把大神们的世界,下面分享一点学习经验。
7 |
8 | ##什么是MVP
9 | - **model**
10 | 处理业务逻辑,主要是数据读写,或者与后台通信,说通俗点就是取数据的地方。
11 |
12 | - **view**
13 | 用于更新UI,由于Android中与用户交互的只要是activity或fragment,所以,view一般就是值activity或fragment
14 |
15 | - **presenter**
16 | 代理,用于协调管理model和view,通知model获取数据,model获取数据完之后,通知view更新界面
17 |
18 |
19 |
20 | ##为什么要用MVP
21 | 使用有一个最大的好处就是解耦,view就只负责更新UI,显示控件,完成与用户的交互;model的职责呢就是去加载数据;具体的model什么时候去获取数据,获取完了之后ui什么时候去更新,这一切都是由presenter去完成。这样做,一方面适合团队协作去开发,另一方面也方便测试,各个模块之间互不干扰。还有更多的好处和优点请自行百度。
22 |
23 |
24 | ##怎么去完成一个MVP的设计呢
25 | 所谓的MVP,其实说通俗一点就是将功能拆分成各个模块,各自完成之后通过回调去做数据交互。前端(activity且已经实现了view接口)在实例化presenter的时候会将自己的view接口回调告诉它(presenter),此时UI的管理权就交给了presenter;presenter在实例化model对象的实例的时候,会将自己的接口回调传递给model对象(有人会说,这样就其实是把管理presenter的管理权交给了model,为什么这么写呢,因为网络请求都是需要耗时的,如果在presenter里面去调用model方法,并等待返回的话,会造成线程阻塞;如果不是耗时的操作,那么就可以在model中暴露方法让presenter去获取数据),model在获取完数据之后,通过presenter的回调告诉他,presenter在接受到model的数据之后又通过先前持有的view的回调将数据或者提示等信息告知UI并更新。如下图:
26 |
27 | 
28 |
29 | ---
30 |
31 | >接下来,我以一个通过接口**获取号码归属地**的例子去剖析一下MVP,同时简单结合RxJava+Retrofit,最终效果如下图。
32 | 
33 |
34 | ##demo实例,功能虽小,五脏俱全
35 |
36 | ###准备工作
37 |
38 | - 项目目录结构,如下图
39 | 
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | - 获取号码归属地的接口及回复的说明
49 | >接口地址:http://api.k780.com:88/?app=phone.get&phone=13888888888&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json
50 | >成功返回数据如下:
51 | >{
52 | "success": "1",
53 | "result": {
54 | "status": "ALREADY_ATT",
55 | "phone": "13888888888",
56 | "area": "0871",
57 | "postno": "650000",
58 | "att": "中国,云南,昆明",
59 | "ctype": "中国移动138卡",
60 | "par": "1388888",
61 | "prefix": "138",
62 | "operators": "中国移动",
63 | "style_simcall": "中国,云南,昆明",
64 | "style_citynm": "中华人民共和国,云南省,昆明市"
65 | }
66 | }
67 | >
68 | >失败返回:
69 | >{
70 | "success": "0",
71 | "msgid": "1000801",
72 | "msg": "手机号码不正确"
73 | }
74 | 注:以上测试电话号码为任意输入的测试号码,无任何其他用意,还请机主能谅解。
75 |
76 |
77 | - 定义收据归属地的实体类
78 | >以下的Bean是**GsonFormat**插件自动生成,还没有使用的朋友可以尝试一下,很不错的一款android studio插件
79 |
80 | ```
81 | import com.lpf.mvptest.base.BaseBean;
82 |
83 | /**
84 | * 电话号码的归属地及其他信息的对象
85 | * Created by Administrator on 2016/3/23.
86 | */
87 | public class PhoneNumInfo extends BaseBean {
88 |
89 | private ResultEntity result;
90 | /**
91 | * msg : 手机号码不正确
92 | * msgid : 1000801
93 | */
94 |
95 | private String msg;
96 |
97 | private String msgid;
98 |
99 | public ResultEntity getResult() {
100 | return result;
101 | }
102 |
103 | public void setResult(ResultEntity result) {
104 | this.result = result;
105 | }
106 |
107 | public String getMsg() {
108 | return msg;
109 | }
110 |
111 | public void setMsg(String msg) {
112 | this.msg = msg;
113 | }
114 |
115 | public String getMsgid() {
116 | return msgid;
117 | }
118 |
119 | public void setMsgid(String msgid) {
120 | this.msgid = msgid;
121 | }
122 |
123 | public static class ResultEntity {
124 | private String status;
125 | private String phone;
126 | private String area;
127 | private String postno;
128 | private String att;
129 | private String ctype;
130 | private String par;
131 | private String prefix;
132 | private String operators;
133 | private String style_simcall;
134 | private String style_citynm;
135 |
136 | public String getStatus() {
137 | return status;
138 | }
139 |
140 | public void setStatus(String status) {
141 | this.status = status;
142 | }
143 |
144 | public String getPhone() {
145 | return phone;
146 | }
147 |
148 | public void setPhone(String phone) {
149 | this.phone = phone;
150 | }
151 |
152 | public String getArea() {
153 | return area;
154 | }
155 |
156 | public void setArea(String area) {
157 | this.area = area;
158 | }
159 |
160 | public String getPostno() {
161 | return postno;
162 | }
163 |
164 | public void setPostno(String postno) {
165 | this.postno = postno;
166 | }
167 |
168 | public String getAtt() {
169 | return att;
170 | }
171 |
172 | public void setAtt(String att) {
173 | this.att = att;
174 | }
175 |
176 | public String getCtype() {
177 | return ctype;
178 | }
179 |
180 | public void setCtype(String ctype) {
181 | this.ctype = ctype;
182 | }
183 |
184 | public String getPar() {
185 | return par;
186 | }
187 |
188 | public void setPar(String par) {
189 | this.par = par;
190 | }
191 |
192 | public String getPrefix() {
193 | return prefix;
194 | }
195 |
196 | public void setPrefix(String prefix) {
197 | this.prefix = prefix;
198 | }
199 |
200 | public String getOperators() {
201 | return operators;
202 | }
203 |
204 | public void setOperators(String operators) {
205 | this.operators = operators;
206 | }
207 |
208 | public String getStyle_simcall() {
209 | return style_simcall;
210 | }
211 |
212 | public void setStyle_simcall(String style_simcall) {
213 | this.style_simcall = style_simcall;
214 | }
215 |
216 | public String getStyle_citynm() {
217 | return style_citynm;
218 | }
219 |
220 | public void setStyle_citynm(String style_citynm) {
221 | this.style_citynm = style_citynm;
222 | }
223 |
224 | @Override
225 | public String toString() {
226 | return "ResultEntity{" +
227 | "status='" + status + '\'' +
228 | ", phone='" + phone + '\'' +
229 | ", area='" + area + '\'' +
230 | ", postno='" + postno + '\'' +
231 | ", att='" + att + '\'' +
232 | ", ctype='" + ctype + '\'' +
233 | ", par='" + par + '\'' +
234 | ", prefix='" + prefix + '\'' +
235 | ", operators='" + operators + '\'' +
236 | ", style_simcall='" + style_simcall + '\'' +
237 | ", style_citynm='" + style_citynm + '\'' +
238 | '}';
239 | }
240 | }
241 |
242 | @Override
243 | public String toString() {
244 | return "PhoneNumInfo{" +
245 | "success='" + success + '\'' +
246 | ", result=" + result +
247 | '}';
248 | }
249 | }
250 | ```
251 |
252 |
253 | ####View的基类
254 | - 构建view的基础接口,一个界面,请求一次数据基本都分为下面几个步骤:**显示加载框-->加载数据成功(加载失败)-->更新UI(提示用户)-->关闭正在加载的框**这么5个事情,那么我们就定义一个需要做这5件事儿的接口,由于是基类,所以返回的对象由具体的业务子类去定义就好。最终这个类的实现我们在activity或者fragment中去完成,以下为view接口的基类
255 | ```
256 | /**
257 | * 视图(View层)基础回调接口
258 | */
259 | public interface IBaseView {
260 | /**
261 | * 通过toast提示用户
262 | *
263 | * @param msg 提示的信息
264 | * @param requestTag 请求标识
265 | */
266 | void toast(String msg, int requestTag);
267 |
268 | /**
269 | * 显示进度
270 | *
271 | * @param requestTag 请求标识
272 | */
273 | void showProgress(int requestTag);
274 |
275 | /**
276 | * 隐藏进度
277 | *
278 | * @param requestTag 请求标识
279 | */
280 | void hideProgress(int requestTag);
281 |
282 | /**
283 | * 基础的请求的返回
284 | *
285 | * @param data
286 | * @param requestTag 请求标识
287 | */
288 | void loadDataSuccess(T data, int requestTag);
289 |
290 | /**
291 | * 基础请求的错误
292 | *
293 | * @param e
294 | * @param requestTag 请求标识
295 | */
296 | void loadDataError(Throwable e, int requestTag);
297 | }
298 | ```
299 |
300 | ####presenter的基类
301 | - 定义代理(presenter)回调接口
302 | ```
303 | /**
304 | * 请求数据的回调
305 | * Presenter用于接受model获取(加载)数据后的回调
306 | * Created by Administrator on 2016/3/23.
307 | */
308 | public interface IBasePresenter {
309 | /**
310 | * 开始请求之前
311 | */
312 | void beforeRequest(int requestTag);
313 |
314 | /**
315 | * 请求失败
316 | *
317 | * @param e 失败的原因
318 | */
319 | void requestError(Throwable e, int requestTag);
320 |
321 | /**
322 | * 请求结束
323 | */
324 | void requestComplete(int requestTag);
325 |
326 | /**
327 | * 请求成功
328 | *
329 | * @param callBack 根据业务返回相应的数据
330 | */
331 | void retuestSuccess(T callBack, int requestTag);
332 | }
333 | ```
334 |
335 | - 写一个presenter的具体实现的基础类**BasePresenterImpl**
336 | > 或许会问,具体的实现放到具体的presenter的业务中去写不就好了嘛,何必要在这里写一遍呢,又做不了什么事情。NO!NO!NO!你想错了,是否还记得前面定义的IBaseView,里面定义了一些基本的UI操作;在这个BasePresenterImpl中,我们可以做一些基础的事情(所有请求都会有的,比如:打开Loading弹框、加载失败后的错误提示),那么就不用在每个子类里面都要去写一次。同时这个类接受2个泛型T,用于分别指定View视图(T)及请求返回的结果(V)
337 |
338 | ```
339 | /**
340 | * 代理对象的基础实现
341 | *
342 | * @param 视图接口对象(view) 具体业务各自继承自IBaseView
343 | * @param 业务请求返回的具体对象
344 | */
345 | public class BasePresenterImpl implements IBasePresenter {
346 | public IBaseView iView;
347 |
348 | /**
349 | * 构造方法
350 | *
351 | * @param view 具体业务的接口对象
352 | */
353 | public BasePresenterImpl(T view) {
354 | this.iView = view;
355 | }
356 |
357 | @Override
358 | public void beforeRequest(int requestTag) {
359 | //显示LOading
360 | iView.showProgress(requestTag);
361 | }
362 |
363 | @Override
364 | public void requestError(Throwable e, int requestTag) {
365 | //通知UI具体的错误信息
366 | iView.loadDataError(e,requestTag);
367 | }
368 |
369 | @Override
370 | public void requestComplete(int requestTag) {
371 | //隐藏Loading
372 | iView.hideProgress(requestTag);
373 | }
374 |
375 | @Override
376 | public void retuestSuccess(V callBack, int requestTag) {
377 | //将获取的数据回调给UI(activity或者fragment)
378 | iView.loadDataSuccess(callBack, requestTag);
379 | }
380 | }
381 | ```
382 |
383 | >代码中可以看到,加载前的弹框,加载成功回调给UI,加载失败通知UI错误信息,加载完成关闭弹框等都已经在这里做了一个基础的实现。如果其中的方法不能满足你的业务需求,你可以在具体业务的presenter实现中去重写相应方法添加具体缺失的实现。
384 |
385 | ####Model的基类
386 | - 业务(model)类的基类
387 | >其中有写到RetrofitManager这个类,在下面将会介绍,这是一个用于初始化retrofit和service的类,也就是model的辅助对象。
388 |
389 | ```
390 | /**
391 | * 业务对象的基类
392 | */
393 | public class BaseModel {
394 | //retrofit请求数据的管理类
395 | public RetrofitManager retrofitManager;
396 |
397 | public BaseModel() {
398 | //初始化retrofit
399 | retrofitManager = RetrofitManager.builder();
400 | }
401 |
402 | }
403 | ```
404 |
405 |
406 | - 定义一个请求归属地的服务
407 |
408 | ```
409 |
410 | /**
411 | * 归属地请求的服务
412 | */
413 | public interface PhoneNunInfoService {
414 | //http://api.k780.com:88/?app=phone.get&phone={phoneNum}&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json
415 | @Headers(RetrofitManager.CACHE_CONTROL_AGE + RetrofitManager.CACHE_STALE_LONG)
416 | @GET("/")
417 | Observable getBeforeNews(@Query("app") String app
418 | , @Query("phone") String phone
419 | , @Query("appkey") String appkey
420 | , @Query("sign") String sign
421 | , @Query("format") String format);
422 |
423 | }
424 | ```
425 |
426 | - 创建RetrofitManager对象,他的作用就是初始化retrofit、service以及添加缓存机制(如果不理解可以不关注他,将那一块的代码注释掉依然是可以运行的)
427 | ```
428 | /**
429 | * Retrofit管理类
430 |
431 | */
432 | public class RetrofitManager {
433 |
434 | //地址
435 | public static final String BASE_PHONENUMINFO_URL = "http://api.k780.com:88";
436 |
437 | //短缓存有效期为1分钟
438 | public static final int CACHE_STALE_SHORT = 60;
439 | //长缓存有效期为7天
440 | public static final int CACHE_STALE_LONG = 60 * 60 * 24 * 7;
441 |
442 | public static final String CACHE_CONTROL_AGE = "Cache-Control: public, max-age=";
443 |
444 | //查询缓存的Cache-Control设置,为if-only-cache时只查询缓存而不会请求服务器,max-stale可以配合设置缓存失效时间
445 | public static final String CACHE_CONTROL_CACHE = "only-if-cached, max-stale=" + CACHE_STALE_LONG;
446 | //查询网络的Cache-Control设置,头部Cache-Control设为max-age=0时则不会使用缓存而请求服务器
447 | public static final String CACHE_CONTROL_NETWORK = "max-age=0";
448 | private static OkHttpClient mOkHttpClient;
449 | private final PhoneNunInfoService phoneNunInfoService;
450 |
451 | public static RetrofitManager builder() {
452 | return new RetrofitManager();
453 | }
454 |
455 | public PhoneNunInfoService getService() {
456 | return phoneNunInfoService;
457 | }
458 |
459 | private RetrofitManager() {
460 | initOkHttpClient();
461 |
462 | Retrofit retrofit = new Retrofit.Builder()
463 | .baseUrl(BASE_PHONENUMINFO_URL)
464 | .client(mOkHttpClient)
465 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
466 | .addConverterFactory(GsonConverterFactory.create())
467 | .build();
468 | phoneNunInfoService = retrofit.create(PhoneNunInfoService.class);
469 | }
470 |
471 | private void initOkHttpClient() {
472 | HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
473 | interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
474 | if (mOkHttpClient == null) {
475 | synchronized (RetrofitManager.class) {
476 | if (mOkHttpClient == null) {
477 |
478 | // 指定缓存路径,缓存大小100Mb
479 | Cache cache = new Cache(new File(MyApplication.getContext().getCacheDir(), "HttpCache"),
480 | 1024 * 1024 * 100);
481 |
482 | mOkHttpClient = new OkHttpClient.Builder()
483 | .cache(cache)
484 | .addInterceptor(mRewriteCacheControlInterceptor)
485 | .addNetworkInterceptor(mRewriteCacheControlInterceptor)
486 | .addInterceptor(interceptor)
487 | .addNetworkInterceptor(new StethoInterceptor())
488 | .retryOnConnectionFailure(true)
489 | .connectTimeout(15, TimeUnit.SECONDS)
490 | .build();
491 | }
492 | }
493 | }
494 | }
495 |
496 | // 云端响应头拦截器,用来配置缓存策略
497 | private Interceptor mRewriteCacheControlInterceptor = new Interceptor() {
498 | @Override
499 | public Response intercept(Chain chain) throws IOException {
500 | Request request = chain.request();
501 | if (!NetUtil.isNetworkConnected()) {
502 | request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();
503 | }
504 | Response originalResponse = chain.proceed(request);
505 | if (NetUtil.isNetworkConnected()) {
506 | //有网的时候读接口上的@Headers里的配置,你可以在这里进行统一的设置
507 | String cacheControl = request.cacheControl().toString();
508 | return originalResponse.newBuilder().header("Cache-Control", cacheControl)
509 | .removeHeader("Pragma").build();
510 | } else {
511 | return originalResponse.newBuilder()
512 | .header("Cache-Control", "public, only-if-cached, max-stale=" + CACHE_STALE_LONG)
513 | .removeHeader("Pragma").build();
514 | }
515 | }
516 | };
517 | }
518 | ```
519 | >**到此,基础的东西已经完成了,这样的事情,虽然说在实现这样的小功能中确实是显的有些多余了,但是在实际的开发过程中,我们并不是只做一件事,只做一个请求,只显示一个界面,因此,这样往上抽一层还是很有必要的。下面将回归到真正写号码归属地的实际业务中来**
520 |
521 |
522 |
523 |
524 | ###具体的业务实现
525 | - 查询号码归属地的view
526 | >由于基础的view接口已经可以满足号码归属地查询的ui更新使用了,同时也为了项目方便管理,便于理解,我们新建一个PhoneNumInfoView,继承IBaseView,并告诉baseView请求成功后需要返回一个PhoneNumInfo的对象。
527 | ```
528 | /**
529 | * 号码归属地查询的View
530 | */
531 | public interface PhoneNumInfoView extends IBaseView{
532 | }
533 | ```
534 |
535 | - 定义获取归属地的Model
536 |
537 | ```
538 | /**
539 | * 获取号码归属地的具体Model实现
540 | */
541 | public class PhoneModelImpl extends BaseModel {
542 | private Context mContext;
543 | private PhoneNunInfoService phoneNunInfoService;
544 |
545 | public PhoneModelImpl(Context context) {
546 | super();
547 | this.mContext = context;
548 | phoneNunInfoService = retrofitManager.getService();
549 | }
550 |
551 | public void loadPhoneNumInfo(String phoneNum, final IBasePresenter callBack, final int requestTag) {
552 | phoneNunInfoService.getBeforeNews("phone.get", phoneNum, "10003", "b59bc3ef6191eb9f747dd4e83c99f2a4", "json")
553 | .subscribeOn(Schedulers.io())
554 | .observeOn(AndroidSchedulers.mainThread())
555 | .subscribe(new Subscriber() {
556 | @Override
557 | public void onStart() {
558 | super.onStart();
559 | callBack.beforeRequest(requestTag);
560 | }
561 |
562 | @Override
563 | public void onCompleted() {
564 | callBack.requestComplete(requestTag);
565 | }
566 |
567 | @Override
568 | public void onError(Throwable e) {
569 | callBack.requestError(e, requestTag);
570 | }
571 |
572 | @Override
573 | public void onNext(PhoneNumInfo phoneNumInfo) {
574 | if (null != phoneNumInfo && phoneNumInfo.getSuccess().equals("1"))
575 | callBack.retuestSuccess(phoneNumInfo, requestTag);
576 | else if (null != phoneNumInfo && phoneNumInfo.getSuccess().equals("0"))
577 | callBack.requestError(new Exception(phoneNumInfo.getMsg()), requestTag);
578 | else
579 | callBack.requestError(new Exception("获取数据错误,请重试!"), requestTag);
580 | }
581 | });
582 | }
583 | }
584 | ```
585 | - 定义一个用于获取号码归属地的代理对象(presenter)
586 | >在实例化代理对象的时候拿到前端(activity或者fragment)的view实例,并初始化Model对象,同时对外提供一个获取数据的方法,方便activity去获取数据。
587 |
588 | ```
589 | /**
590 | * Presenter的实现,协调model去加载数据,获取model加载完成时候的回调,控制界面加载框的显示与隐藏
591 | */
592 | public class PhonePresenterImpl extends BasePresenterImpl {
593 | private PhoneModelImpl phoneModel;
594 | private Context mContext;
595 |
596 |
597 | public PhonePresenterImpl(PhoneNumInfoView phoneNumInfoView, Context context) {
598 | super(phoneNumInfoView);
599 | this.mContext = context;
600 | phoneModel = new PhoneModelImpl(mContext);
601 | }
602 |
603 | /**
604 | * 获取归属地信息
605 | *
606 | * @param phoneNum 电话号码
607 | * @param requestTag 请求标识
608 | */
609 | public void getPhoneNumInfo(String phoneNum, int requestTag) {
610 | phoneModel.loadPhoneNumInfo(phoneNum, this, requestTag);
611 | }
612 | }
613 | ```
614 |
615 | - 实现activity中相关的代码
616 | >前端activity的代码并不多,就是实现PhoneNumInfoView的相应接口,然后最基础的获取控件,实例化presenter,把当前的view实例以参数的形式传递给presenter;接口的实现也就是要显示Loading的地方把框show出来,在获取数据成功的地方显示数据等等,各负其职。然后在按钮的点击事件的地方调用presenter中相应的获取数据的方法。具体的什么时候显示Loading,什么时候执行加载完成的操作等,就不需要activity去管了,安安心心的全权交个presenter去做就好了。代码如下:
617 | ```
618 | public class MainActivity extends AppCompatActivity implements View.OnClickListener, PhoneNumInfoView {
619 | //获取归属地的请求标识,用回页面多个地方请求的时候,标识是那一个完成并回调了
620 | private static final int REQUESTMSG = 0;
621 |
622 | //电话号码的EditText
623 | private EditText phoneNum;
624 | //获取归属地的按钮
625 | private Button getPhoneInfo;
626 | //用于显示最后获取的结果
627 | private TextView msg;
628 | //Loading弹框
629 | private ProgressDialog progressDialog;
630 | //获取归属地的代理对象
631 | private PhonePresenterImpl phonePresenter;
632 |
633 | @Override
634 | protected void onCreate(Bundle savedInstanceState) {
635 | super.onCreate(savedInstanceState);
636 | setContentView(R.layout.activity_main);
637 |
638 | initView();
639 |
640 | }
641 |
642 | private void initView() {
643 | //初始化控件
644 | phoneNum = (EditText) findViewById(R.id.phonenum);
645 | getPhoneInfo = (Button) findViewById(R.id.getphoneinfo);
646 | msg = (TextView) findViewById(R.id.msg);
647 | getPhoneInfo.setOnClickListener(this);
648 |
649 | //初始化Loading
650 | progressDialog = new ProgressDialog(this);
651 | progressDialog.setMessage("Loading");
652 |
653 | //初始化代理对象
654 | phonePresenter = new PhonePresenterImpl(this, this);
655 | }
656 |
657 | @Override
658 | public void toast(String msg, int requestTag) {
659 |
660 | }
661 |
662 | @Override
663 | public void showProgress(int requestTag) {
664 | if (null != progressDialog && !progressDialog.isShowing()) {
665 | progressDialog.show();
666 | }
667 | }
668 |
669 | @Override
670 | public void hideProgress(int requestTag) {
671 | if (null != progressDialog && progressDialog.isShowing()) {
672 | progressDialog.dismiss();
673 | }
674 | }
675 |
676 | @Override
677 | public void loadDataSuccess(PhoneNumInfo phoneNumInfo, int requestTag) {
678 | msg.setText(phoneNumInfo.toString());
679 | }
680 |
681 | @Override
682 | public void loadDataError(Throwable e, int requestTag) {
683 | msg.setText(e.getMessage());
684 | }
685 |
686 | @Override
687 | public void onClick(View v) {
688 | switch (v.getId()) {
689 | case R.id.getphoneinfo:
690 | phonePresenter.getPhoneNumInfo(phoneNum.getText().toString(), REQUESTMSG);
691 | break;
692 | }
693 | }
694 | }
695 | ```
696 |
697 | - 效果图
698 | - 成功
699 | 
700 |
701 | - 失败
702 | 
703 |
704 | >到这里,一个基于MVP的DEMO就写完了,其中有用到RxJava和Retrofit,但是没有做明确的说明,如果想了解可以阅读:[RxJava 与 Retrofit 结合的最佳实践](http://gank.io/post/56e80c2c677659311bed9841)
705 | >
706 | > 源码下载地址[戳这里](https://github.com/183619962/MVPTest)
707 |
708 | >2017年2月19日,去掉冗余代码,简化了流程。
--------------------------------------------------------------------------------