├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── Mvp ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── r │ │ └── mvp │ │ └── cn │ │ ├── MvpActivity.java │ │ ├── MvpAppCompatActivity.java │ │ ├── MvpFragment.java │ │ ├── MvpFragmentActivity.java │ │ ├── MvpPresenter.java │ │ ├── MvpView.java │ │ ├── delegate │ │ ├── ActivityMvpDelegate.java │ │ ├── ActivityMvpDelegateImpl.java │ │ ├── FragmentMvpDelegate.java │ │ ├── FragmentMvpDelegateImpl.java │ │ └── MvpDelegateCallback.java │ │ ├── model │ │ ├── ModelCallback.java │ │ └── ModelFactory.java │ │ ├── proxy │ │ └── MvpViewProxy.java │ │ └── root │ │ ├── IMvpModel.java │ │ ├── IMvpPresenter.java │ │ └── IMvpView.java │ └── res │ └── values │ └── strings.xml ├── README.md ├── RHttp.md ├── RHttp ├── .gitignore ├── build.gradle ├── libs │ └── lite-orm-1.9.2.jar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── r │ │ └── http │ │ └── cn │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── r │ │ │ └── http │ │ │ └── cn │ │ │ ├── RDownLoad.java │ │ │ ├── RHttp.java │ │ │ ├── api │ │ │ └── Api.java │ │ │ ├── callback │ │ │ ├── BaseCallback.java │ │ │ ├── HttpCallback.java │ │ │ └── UploadCallback.java │ │ │ ├── cancel │ │ │ ├── RequestCancel.java │ │ │ ├── RequestManager.java │ │ │ └── RequestManagerImpl.java │ │ │ ├── exception │ │ │ ├── ApiException.java │ │ │ ├── ExceptionEngine.java │ │ │ └── ServerException.java │ │ │ ├── function │ │ │ ├── HttpResultFunction.java │ │ │ └── ServerResultFunction.java │ │ │ ├── helper │ │ │ └── ParseHelper.java │ │ │ ├── load │ │ │ ├── download │ │ │ │ ├── DownloadCallback.java │ │ │ │ ├── DownloadInterceptor.java │ │ │ │ ├── DownloadObserver.java │ │ │ │ ├── DownloadProgressCallback.java │ │ │ │ └── DownloadResponseBody.java │ │ │ └── upload │ │ │ │ ├── UploadProgressCallback.java │ │ │ │ └── UploadRequestBody.java │ │ │ ├── model │ │ │ └── Download.java │ │ │ ├── observer │ │ │ ├── HttpObservable.java │ │ │ └── HttpObserver.java │ │ │ ├── retrofit │ │ │ ├── HttpsUtils.java │ │ │ ├── Method.java │ │ │ └── RetrofitUtils.java │ │ │ └── utils │ │ │ ├── ComputeUtils.java │ │ │ ├── DBHelper.java │ │ │ ├── LogUtils.java │ │ │ ├── RequestUtils.java │ │ │ ├── ResponseUtils.java │ │ │ └── ThreadUtils.java │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── r │ └── http │ └── cn │ └── ExampleUnitTest.java ├── RHttp_demo.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── rx │ │ └── mvp │ │ └── cn │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── rx │ │ │ └── mvp │ │ │ └── cn │ │ │ ├── base │ │ │ ├── BaseActivity.java │ │ │ ├── BaseBiz.java │ │ │ ├── BaseFragment.java │ │ │ ├── BaseFragmentActivity.java │ │ │ ├── BasePagerAdapter.java │ │ │ └── BizFactory.java │ │ │ ├── core │ │ │ ├── bitmap │ │ │ │ └── ImageLoaderUtils.java │ │ │ └── net │ │ │ │ └── http │ │ │ │ ├── RHttpCallback.java │ │ │ │ └── RUploadCallback.java │ │ │ ├── manager │ │ │ └── ActivityStackManager.java │ │ │ ├── model │ │ │ ├── GlobalConstants.java │ │ │ ├── MainActivity.java │ │ │ ├── RApp.java │ │ │ ├── Response.java │ │ │ ├── account │ │ │ │ ├── activity │ │ │ │ │ └── LoginActivity.java │ │ │ │ ├── biz │ │ │ │ │ └── UserBiz.java │ │ │ │ ├── contract │ │ │ │ │ └── AccountContract.java │ │ │ │ ├── entity │ │ │ │ │ └── UserBean.java │ │ │ │ ├── fragment │ │ │ │ │ └── LoginFragment.java │ │ │ │ ├── model │ │ │ │ │ └── AccountModel.java │ │ │ │ └── presenter │ │ │ │ │ └── LoginPresenter.java │ │ │ ├── load │ │ │ │ ├── download │ │ │ │ │ ├── DownloadActivity.java │ │ │ │ │ └── DownloadBean.java │ │ │ │ ├── upload │ │ │ │ │ └── UploadActivity.java │ │ │ │ └── 特殊包说明.txt │ │ │ ├── multiple │ │ │ │ ├── MultipleActivity.java │ │ │ │ └── MultipleFragment.java │ │ │ └── phone │ │ │ │ ├── activity │ │ │ │ └── PhoneAddressActivity.java │ │ │ │ ├── biz │ │ │ │ └── PhoneBiz.java │ │ │ │ ├── contract │ │ │ │ └── PhoneContract.java │ │ │ │ ├── entity │ │ │ │ └── PhoneAddressBean.java │ │ │ │ ├── fragment │ │ │ │ └── PhoneAddressFragment.java │ │ │ │ ├── model │ │ │ │ └── PhoneModel.java │ │ │ │ └── presenter │ │ │ │ └── PhoneAddressPresenter.java │ │ │ ├── sample │ │ │ ├── HttpSample.java │ │ │ └── mvp │ │ │ │ ├── AccountActivity.java │ │ │ │ ├── AccountContract.java │ │ │ │ ├── AccountFragment.java │ │ │ │ ├── AccountModel.java │ │ │ │ └── AccountPresenter.java │ │ │ ├── utils │ │ │ ├── LogUtils.java │ │ │ ├── SpUtils.java │ │ │ └── ToastUtils.java │ │ │ └── widget │ │ │ └── RLoadingDialog.java │ └── res │ │ ├── layout │ │ ├── activity_download.xml │ │ ├── activity_login.xml │ │ ├── activity_main.xml │ │ ├── activity_phone_address.xml │ │ ├── activity_upload.xml │ │ ├── item_download.xml │ │ ├── multiple_activity.xml │ │ └── multiple_fragment.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 │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── rx │ └── mvp │ └── cn │ └── ExampleUnitTest.java ├── build.gradle ├── download.gif ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── package.png ├── package_core.png ├── package_model.png ├── rxmvp.jks ├── settings.gradle └── upload.gif /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Mvp/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /Mvp/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 28 5 | buildToolsVersion '28.0.2' 6 | 7 | defaultConfig { 8 | minSdkVersion 14 9 | targetSdkVersion 28 10 | versionCode 1 11 | versionName "1.0" 12 | 13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 14 | 15 | } 16 | buildTypes { 17 | official { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | debug { 22 | minifyEnabled false 23 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 24 | } 25 | intranet { 26 | minifyEnabled false 27 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 28 | } 29 | extranet { 30 | minifyEnabled false 31 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 32 | } 33 | } 34 | } 35 | 36 | dependencies { 37 | implementation fileTree(include: ['*.jar'], dir: 'libs') 38 | testImplementation 'junit:junit:4.12' 39 | implementation 'com.android.support:appcompat-v7:28.0.0' 40 | //implementation 'com.android.support:support-annotations:28.0.0' 41 | //implementation 'com.android.support:support-v4:28.0.0' 42 | //implementation 'com.android.support:support-annotations:25.3.1' 43 | 44 | /*RxLifecycle基础库*/ 45 | implementation 'com.trello.rxlifecycle2:rxlifecycle:2.1.0' 46 | implementation 'com.trello.rxlifecycle2:rxlifecycle-components:2.1.0' 47 | } 48 | -------------------------------------------------------------------------------- /Mvp/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 D:\android-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 | -------------------------------------------------------------------------------- /Mvp/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Mvp/src/main/java/com/r/mvp/cn/MvpActivity.java: -------------------------------------------------------------------------------- 1 | package com.r.mvp.cn; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.NonNull; 5 | import android.view.View; 6 | 7 | import com.r.mvp.cn.delegate.ActivityMvpDelegate; 8 | import com.r.mvp.cn.delegate.ActivityMvpDelegateImpl; 9 | import com.r.mvp.cn.delegate.MvpDelegateCallback; 10 | import com.r.mvp.cn.root.IMvpPresenter; 11 | import com.r.mvp.cn.root.IMvpView; 12 | import com.trello.rxlifecycle2.components.RxActivity; 13 | 14 | 15 | /** 16 | * MVPActivity 17 | * 备注: 18 | * 1.XXActivity 继承 MvpActivity,当页面存在 Presenter 时,具体 Activity 需要调用 setPresenter(P... presenter) 19 | * 2.由于此框架集合了 RxLifecycle 因此本 Activity 继承自 RxActivity (开发者也可以直接继承 Activity) 20 | * 3.支持一个 Activity 存在多个 Presenter 21 | * 22 | * @param 23 | * @param

24 | */ 25 | public abstract class MvpActivity> extends RxActivity implements IMvpView, MvpDelegateCallback { 26 | 27 | protected ActivityMvpDelegate mvpDelegate; 28 | 29 | /** 30 | * 获取 Presenter 数组 31 | */ 32 | protected abstract P[] getPresenterArray(); 33 | 34 | @Override 35 | public P[] getPresenter() { 36 | return getPresenterArray(); 37 | } 38 | 39 | @Override 40 | public V[] getMvpView() { 41 | V[] view = null; 42 | P[] pArray = getPresenter(); 43 | if (pArray != null) { 44 | view = (V[]) new IMvpView[pArray.length]; 45 | for (int i = 0; i < pArray.length; i++) { 46 | view[i] = (V) this; 47 | } 48 | } 49 | return view; 50 | } 51 | 52 | @NonNull 53 | protected ActivityMvpDelegate getMvpDelegate() { 54 | if (mvpDelegate == null) { 55 | mvpDelegate = new ActivityMvpDelegateImpl(this, this); 56 | } 57 | return mvpDelegate; 58 | } 59 | 60 | @Override 61 | protected void onCreate(Bundle savedInstanceState) { 62 | super.onCreate(savedInstanceState); 63 | getMvpDelegate().onCreate(savedInstanceState); 64 | } 65 | 66 | @Override 67 | protected void onDestroy() { 68 | super.onDestroy(); 69 | getMvpDelegate().onDestroy(); 70 | } 71 | 72 | @Override 73 | protected void onSaveInstanceState(Bundle outState) { 74 | super.onSaveInstanceState(outState); 75 | getMvpDelegate().onSaveInstanceState(outState); 76 | } 77 | 78 | @Override 79 | protected void onPause() { 80 | super.onPause(); 81 | getMvpDelegate().onPause(); 82 | } 83 | 84 | @Override 85 | protected void onResume() { 86 | super.onResume(); 87 | getMvpDelegate().onResume(); 88 | } 89 | 90 | @Override 91 | protected void onStart() { 92 | super.onStart(); 93 | getMvpDelegate().onStart(); 94 | } 95 | 96 | @Override 97 | protected void onStop() { 98 | super.onStop(); 99 | getMvpDelegate().onStop(); 100 | } 101 | 102 | @Override 103 | protected void onRestart() { 104 | super.onRestart(); 105 | getMvpDelegate().onRestart(); 106 | } 107 | 108 | @Override 109 | public void onContentChanged() { 110 | super.onContentChanged(); 111 | getMvpDelegate().onContentChanged(); 112 | } 113 | 114 | @Override 115 | protected void onPostCreate(Bundle savedInstanceState) { 116 | super.onPostCreate(savedInstanceState); 117 | getMvpDelegate().onPostCreate(savedInstanceState); 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /Mvp/src/main/java/com/r/mvp/cn/MvpAppCompatActivity.java: -------------------------------------------------------------------------------- 1 | package com.r.mvp.cn; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.NonNull; 5 | import android.util.Log; 6 | 7 | import com.r.mvp.cn.delegate.ActivityMvpDelegate; 8 | import com.r.mvp.cn.delegate.ActivityMvpDelegateImpl; 9 | import com.r.mvp.cn.delegate.MvpDelegateCallback; 10 | import com.r.mvp.cn.root.IMvpPresenter; 11 | import com.r.mvp.cn.root.IMvpView; 12 | import com.trello.rxlifecycle2.components.support.RxAppCompatActivity; 13 | 14 | import java.lang.reflect.ParameterizedType; 15 | 16 | 17 | /** 18 | * MvpAppCompatActivity 19 | * 备注: 20 | * 1.XXActivity 继承 MvpActivity,当页面存在 Presenter 时,具体 Activity 需要调用 setPresenter(P... presenter) 21 | * 2.由于此框架集合了 RxLifecycle 因此本 Activity 继承自 RxActivity (开发者也可以直接继承 Activity) 22 | * 3.支持一个 Activity 存在多个 Presenter 23 | * 24 | * @param 25 | * @param

26 | */ 27 | public abstract class MvpAppCompatActivity> extends RxAppCompatActivity implements IMvpView, MvpDelegateCallback { 28 | 29 | protected ActivityMvpDelegate mvpDelegate; 30 | 31 | /** 32 | * 获取 Presenter 数组 33 | */ 34 | protected abstract P[] getPresenterArray(); 35 | 36 | @Override 37 | public P[] getPresenter() { 38 | return getPresenterArray(); 39 | } 40 | 41 | @Override 42 | public V[] getMvpView() { 43 | V[] view = null; 44 | P[] pArray = getPresenter(); 45 | if (pArray != null) { 46 | view = (V[]) new IMvpView[pArray.length]; 47 | for (int i = 0; i < pArray.length; i++) { 48 | view[i] = (V) this; 49 | } 50 | } 51 | return view; 52 | } 53 | 54 | 55 | @NonNull 56 | protected ActivityMvpDelegate getMvpDelegate() { 57 | if (mvpDelegate == null) { 58 | mvpDelegate = new ActivityMvpDelegateImpl(this, this); 59 | } 60 | return mvpDelegate; 61 | } 62 | 63 | @Override 64 | protected void onCreate(Bundle savedInstanceState) { 65 | super.onCreate(savedInstanceState); 66 | getMvpDelegate().onCreate(savedInstanceState); 67 | } 68 | 69 | @Override 70 | protected void onDestroy() { 71 | super.onDestroy(); 72 | getMvpDelegate().onDestroy(); 73 | } 74 | 75 | @Override 76 | protected void onSaveInstanceState(Bundle outState) { 77 | super.onSaveInstanceState(outState); 78 | getMvpDelegate().onSaveInstanceState(outState); 79 | } 80 | 81 | @Override 82 | protected void onPause() { 83 | super.onPause(); 84 | getMvpDelegate().onPause(); 85 | } 86 | 87 | @Override 88 | protected void onResume() { 89 | super.onResume(); 90 | getMvpDelegate().onResume(); 91 | } 92 | 93 | @Override 94 | protected void onStart() { 95 | super.onStart(); 96 | getMvpDelegate().onStart(); 97 | } 98 | 99 | @Override 100 | protected void onStop() { 101 | super.onStop(); 102 | getMvpDelegate().onStop(); 103 | } 104 | 105 | @Override 106 | protected void onRestart() { 107 | super.onRestart(); 108 | getMvpDelegate().onRestart(); 109 | } 110 | 111 | @Override 112 | public void onContentChanged() { 113 | super.onContentChanged(); 114 | getMvpDelegate().onContentChanged(); 115 | } 116 | 117 | @Override 118 | protected void onPostCreate(Bundle savedInstanceState) { 119 | super.onPostCreate(savedInstanceState); 120 | getMvpDelegate().onPostCreate(savedInstanceState); 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /Mvp/src/main/java/com/r/mvp/cn/MvpFragment.java: -------------------------------------------------------------------------------- 1 | package com.r.mvp.cn; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.support.annotation.NonNull; 6 | import android.support.annotation.Nullable; 7 | import android.view.View; 8 | 9 | import com.r.mvp.cn.delegate.ActivityMvpDelegate; 10 | import com.r.mvp.cn.delegate.ActivityMvpDelegateImpl; 11 | import com.r.mvp.cn.delegate.FragmentMvpDelegate; 12 | import com.r.mvp.cn.delegate.FragmentMvpDelegateImpl; 13 | import com.r.mvp.cn.delegate.MvpDelegateCallback; 14 | import com.r.mvp.cn.root.IMvpPresenter; 15 | import com.r.mvp.cn.root.IMvpView; 16 | import com.trello.rxlifecycle2.components.support.RxFragment; 17 | 18 | 19 | /** 20 | * MVPFragment 21 | * 备注: 22 | * 1.XXFragment 继承 MvpFragment,当页面存在 Presenter 时,具体 Fragment 需要调用 setPresenter(P... presenter) 23 | * 2.由于此框架集合了 RxLifecycle 因此本 Fragment 继承自 RxFragment (开发者也可以直接继承 Fragment) 24 | * 3.支持一个 Fragment 存在多个 Presenter 25 | * 26 | * @param 27 | * @param

28 | */ 29 | public abstract class MvpFragment> extends RxFragment implements IMvpView, MvpDelegateCallback { 30 | 31 | protected FragmentMvpDelegate mvpDelegate; 32 | 33 | /** 34 | * 获取 Presenter 数组 35 | */ 36 | protected abstract P[] getPresenterArray(); 37 | 38 | @Override 39 | public P[] getPresenter() { 40 | return getPresenterArray(); 41 | } 42 | 43 | @Override 44 | public V[] getMvpView() { 45 | V[] view = null; 46 | P[] pArray = getPresenter(); 47 | if (pArray != null) { 48 | view = (V[]) new IMvpView[pArray.length]; 49 | for (int i = 0; i < pArray.length; i++) { 50 | view[i] = (V) this; 51 | } 52 | } 53 | return view; 54 | } 55 | 56 | @NonNull 57 | protected FragmentMvpDelegate getMvpDelegate() { 58 | if (mvpDelegate == null) { 59 | mvpDelegate = new FragmentMvpDelegateImpl(this, this); 60 | } 61 | return mvpDelegate; 62 | } 63 | 64 | @Override 65 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 66 | super.onViewCreated(view, savedInstanceState); 67 | getMvpDelegate().onViewCreated(view, savedInstanceState); 68 | } 69 | 70 | @Override 71 | public void onDestroyView() { 72 | super.onDestroyView(); 73 | getMvpDelegate().onDestroyView(); 74 | } 75 | 76 | @Override 77 | public void onCreate(Bundle savedInstanceState) { 78 | super.onCreate(savedInstanceState); 79 | getMvpDelegate().onCreate(savedInstanceState); 80 | } 81 | 82 | @Override 83 | public void onDestroy() { 84 | super.onDestroy(); 85 | getMvpDelegate().onDestroy(); 86 | } 87 | 88 | @Override 89 | public void onPause() { 90 | super.onPause(); 91 | getMvpDelegate().onPause(); 92 | } 93 | 94 | @Override 95 | public void onResume() { 96 | super.onResume(); 97 | getMvpDelegate().onResume(); 98 | } 99 | 100 | @Override 101 | public void onStart() { 102 | super.onStart(); 103 | getMvpDelegate().onStart(); 104 | } 105 | 106 | @Override 107 | public void onStop() { 108 | super.onStop(); 109 | getMvpDelegate().onStop(); 110 | } 111 | 112 | @Override 113 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 114 | super.onActivityCreated(savedInstanceState); 115 | getMvpDelegate().onActivityCreated(savedInstanceState); 116 | } 117 | 118 | @Override 119 | public void onAttach(Activity activity) { 120 | super.onAttach(activity); 121 | getMvpDelegate().onAttach(activity); 122 | } 123 | 124 | @Override 125 | public void onDetach() { 126 | super.onDetach(); 127 | getMvpDelegate().onDetach(); 128 | } 129 | 130 | @Override 131 | public void onSaveInstanceState(Bundle outState) { 132 | super.onSaveInstanceState(outState); 133 | getMvpDelegate().onSaveInstanceState(outState); 134 | } 135 | } 136 | 137 | 138 | -------------------------------------------------------------------------------- /Mvp/src/main/java/com/r/mvp/cn/MvpFragmentActivity.java: -------------------------------------------------------------------------------- 1 | package com.r.mvp.cn; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.NonNull; 5 | 6 | import com.r.mvp.cn.delegate.ActivityMvpDelegate; 7 | import com.r.mvp.cn.delegate.ActivityMvpDelegateImpl; 8 | import com.r.mvp.cn.delegate.MvpDelegateCallback; 9 | import com.r.mvp.cn.root.IMvpPresenter; 10 | import com.r.mvp.cn.root.IMvpView; 11 | import com.trello.rxlifecycle2.components.support.RxFragmentActivity; 12 | 13 | 14 | /** 15 | * MvpFragmentActivity 16 | * 备注: 17 | * 1.XXActivity 继承 MvpActivity,当页面存在 Presenter 时,具体 Activity 需要调用 setPresenter(P... presenter) 18 | * 2.由于此框架集合了 RxLifecycle 因此本 Activity 继承自 RxActivity (开发者也可以直接继承 Activity) 19 | * 3.支持一个 Activity 存在多个 Presenter 20 | * 21 | * @param 22 | * @param

23 | */ 24 | public abstract class MvpFragmentActivity> extends RxFragmentActivity implements IMvpView, MvpDelegateCallback { 25 | 26 | protected ActivityMvpDelegate mvpDelegate; 27 | 28 | /** 29 | * 获取 Presenter 数组 30 | */ 31 | protected abstract P[] getPresenterArray(); 32 | 33 | @Override 34 | public P[] getPresenter() { 35 | return getPresenterArray(); 36 | } 37 | 38 | @Override 39 | public V[] getMvpView() { 40 | V[] view = null; 41 | P[] pArray = getPresenter(); 42 | if (pArray != null) { 43 | view = (V[]) new IMvpView[pArray.length]; 44 | for (int i = 0; i < pArray.length; i++) { 45 | view[i] = (V) this; 46 | } 47 | } 48 | return view; 49 | } 50 | 51 | @NonNull 52 | protected ActivityMvpDelegate getMvpDelegate() { 53 | if (mvpDelegate == null) { 54 | mvpDelegate = new ActivityMvpDelegateImpl(this, this); 55 | } 56 | return mvpDelegate; 57 | } 58 | 59 | @Override 60 | protected void onCreate(Bundle savedInstanceState) { 61 | super.onCreate(savedInstanceState); 62 | getMvpDelegate().onCreate(savedInstanceState); 63 | } 64 | 65 | @Override 66 | protected void onDestroy() { 67 | super.onDestroy(); 68 | getMvpDelegate().onDestroy(); 69 | } 70 | 71 | @Override 72 | protected void onSaveInstanceState(Bundle outState) { 73 | super.onSaveInstanceState(outState); 74 | getMvpDelegate().onSaveInstanceState(outState); 75 | } 76 | 77 | @Override 78 | protected void onPause() { 79 | super.onPause(); 80 | getMvpDelegate().onPause(); 81 | } 82 | 83 | @Override 84 | protected void onResume() { 85 | super.onResume(); 86 | getMvpDelegate().onResume(); 87 | } 88 | 89 | @Override 90 | protected void onStart() { 91 | super.onStart(); 92 | getMvpDelegate().onStart(); 93 | } 94 | 95 | @Override 96 | protected void onStop() { 97 | super.onStop(); 98 | getMvpDelegate().onStop(); 99 | } 100 | 101 | @Override 102 | protected void onRestart() { 103 | super.onRestart(); 104 | getMvpDelegate().onRestart(); 105 | } 106 | 107 | @Override 108 | public void onContentChanged() { 109 | super.onContentChanged(); 110 | getMvpDelegate().onContentChanged(); 111 | } 112 | 113 | @Override 114 | protected void onPostCreate(Bundle savedInstanceState) { 115 | super.onPostCreate(savedInstanceState); 116 | getMvpDelegate().onPostCreate(savedInstanceState); 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /Mvp/src/main/java/com/r/mvp/cn/MvpPresenter.java: -------------------------------------------------------------------------------- 1 | 2 | package com.r.mvp.cn; 3 | 4 | import android.support.annotation.UiThread; 5 | 6 | import com.r.mvp.cn.proxy.MvpViewProxy; 7 | import com.r.mvp.cn.root.IMvpPresenter; 8 | import com.r.mvp.cn.root.IMvpView; 9 | 10 | /** 11 | * Presenter基础实现 12 | * 13 | * @param 14 | */ 15 | public abstract class MvpPresenter implements IMvpPresenter { 16 | 17 | protected V mView; 18 | 19 | //View代理对象 20 | protected MvpViewProxy mMvpViewProxy; 21 | 22 | /** 23 | * 获取view 24 | * 25 | * @return 26 | */ 27 | @UiThread 28 | public V getView() { 29 | return mView; 30 | } 31 | 32 | /** 33 | * 判断View是否已经添加 34 | * 35 | * @return 36 | */ 37 | @UiThread 38 | public boolean isViewAttached() { 39 | return mView != null; 40 | } 41 | 42 | /** 43 | * 绑定View 44 | * 45 | * @param view 46 | */ 47 | @UiThread 48 | @Override 49 | public void attachView(V view) { 50 | mMvpViewProxy = new MvpViewProxy(); 51 | mView = (V) mMvpViewProxy.newProxyInstance(view); 52 | } 53 | 54 | /** 55 | * 移除View 56 | */ 57 | @Override 58 | public void detachView() { 59 | if (mMvpViewProxy != null) { 60 | mMvpViewProxy.detachView(); 61 | } 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /Mvp/src/main/java/com/r/mvp/cn/MvpView.java: -------------------------------------------------------------------------------- 1 | 2 | package com.r.mvp.cn; 3 | 4 | import android.app.Activity; 5 | import android.support.annotation.NonNull; 6 | import android.support.annotation.UiThread; 7 | 8 | import com.r.mvp.cn.root.IMvpView; 9 | import com.trello.rxlifecycle2.LifecycleProvider; 10 | 11 | /** 12 | * 基础View接口 13 | */ 14 | public interface MvpView extends IMvpView { 15 | 16 | /** 17 | * RxLifecycle用于绑定组件生命周期 18 | * 19 | * @return 20 | */ 21 | LifecycleProvider getRxLifecycle(); 22 | 23 | /** 24 | * 获取Activity实例 25 | * 26 | * @return 27 | */ 28 | Activity getActivity(); 29 | 30 | /** 31 | * 展示吐司 32 | * 33 | * @param msg 吐司文本 34 | */ 35 | @UiThread 36 | void showToast(@NonNull String msg); 37 | 38 | /** 39 | * 显示进度View 40 | */ 41 | @UiThread 42 | void showProgressView(); 43 | 44 | /** 45 | * 隐藏进度View 46 | */ 47 | @UiThread 48 | void dismissProgressView(); 49 | 50 | } 51 | -------------------------------------------------------------------------------- /Mvp/src/main/java/com/r/mvp/cn/delegate/ActivityMvpDelegate.java: -------------------------------------------------------------------------------- 1 | package com.r.mvp.cn.delegate; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | 6 | import com.r.mvp.cn.root.IMvpPresenter; 7 | import com.r.mvp.cn.root.IMvpView; 8 | 9 | /** 10 | * Activity生命周期 11 | * 12 | * @param 13 | * @param

14 | */ 15 | public interface ActivityMvpDelegate> { 16 | 17 | /** 18 | * This method must be called from {@link Activity#onCreate(Bundle)}. 19 | * This method internally creates the presenter and attaches the view to it. 20 | */ 21 | void onCreate(Bundle bundle); 22 | 23 | /** 24 | * This method must be called from {@link Activity#onDestroy()}}. 25 | * This method internally detaches the view from presenter 26 | */ 27 | void onDestroy(); 28 | 29 | /** 30 | * This method must be called from {@link Activity#onPause()} 31 | */ 32 | void onPause(); 33 | 34 | /** 35 | * This method must be called from {@link Activity#onResume()} 36 | */ 37 | void onResume(); 38 | 39 | /** 40 | * This method must be called from {@link Activity#onStart()} 41 | */ 42 | void onStart(); 43 | 44 | /** 45 | * This method must be called from {@link Activity#onStop()} 46 | */ 47 | void onStop(); 48 | 49 | /** 50 | * This method must be called from {@link Activity#onRestart()} 51 | */ 52 | void onRestart(); 53 | 54 | /** 55 | * This method must be called from {@link Activity#onContentChanged()} 56 | */ 57 | void onContentChanged(); 58 | 59 | /** 60 | * This method must be called from {@link Activity#onSaveInstanceState(Bundle)} 61 | */ 62 | void onSaveInstanceState(Bundle outState); 63 | 64 | /** 65 | * This method must be called from {@link Activity#onPostCreate(Bundle)} 66 | */ 67 | void onPostCreate(Bundle savedInstanceState); 68 | 69 | } 70 | -------------------------------------------------------------------------------- /Mvp/src/main/java/com/r/mvp/cn/delegate/ActivityMvpDelegateImpl.java: -------------------------------------------------------------------------------- 1 | package com.r.mvp.cn.delegate; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.util.Log; 6 | 7 | import com.r.mvp.cn.root.IMvpPresenter; 8 | import com.r.mvp.cn.root.IMvpView; 9 | 10 | import java.lang.reflect.ParameterizedType; 11 | 12 | /** 13 | * Activity媒介 14 | * 备注:主要是连接 Activity 的生命周期与 Presenter 实现特定生命周期绑定与解除 V 15 | * 16 | * @author ZhongDaFeng 17 | */ 18 | public class ActivityMvpDelegateImpl> implements ActivityMvpDelegate { 19 | 20 | /** 21 | * Activity 22 | */ 23 | protected Activity activity; 24 | 25 | /** 26 | * V & P 27 | */ 28 | private MvpDelegateCallback delegateCallback; 29 | 30 | public ActivityMvpDelegateImpl(Activity activity, MvpDelegateCallback delegateCallback) { 31 | if (activity == null) { 32 | throw new NullPointerException("Activity is null!"); 33 | } 34 | if (delegateCallback == null) { 35 | throw new NullPointerException("MvpDelegateCallback is null!"); 36 | } 37 | this.activity = activity; 38 | this.delegateCallback = delegateCallback; 39 | } 40 | 41 | /** 42 | * 是否保留V&P实例 43 | * 44 | * @return 45 | */ 46 | private static boolean retainVPInstance(Activity activity) { 47 | return activity.isChangingConfigurations() || !activity.isFinishing(); 48 | } 49 | 50 | @Override 51 | public void onCreate(Bundle bundle) { 52 | 53 | P[] pArray = delegateCallback.getPresenter(); 54 | if (pArray != null) { 55 | V[] vArray = delegateCallback.getMvpView(); 56 | P presenter; 57 | V view; 58 | for (int i = 0; i < pArray.length; i++) { 59 | presenter = pArray[i]; 60 | view = vArray[i]; 61 | if (presenter != null && view != null) { 62 | //关联view 63 | presenter.attachView(view); 64 | } 65 | } 66 | } 67 | } 68 | 69 | 70 | @Override 71 | public void onDestroy() { 72 | P[] pArray = delegateCallback.getPresenter(); 73 | if (pArray != null) { 74 | P presenter; 75 | for (int i = 0; i < pArray.length; i++) { 76 | presenter = pArray[i]; 77 | if (presenter != null) { 78 | //解除View 79 | presenter.detachView(); 80 | if (!retainVPInstance(activity)) { 81 | //销毁 V & P 实例 82 | presenter.destroy(); 83 | } 84 | } 85 | } 86 | } 87 | } 88 | 89 | @Override 90 | public void onPause() { 91 | 92 | } 93 | 94 | @Override 95 | public void onResume() { 96 | 97 | } 98 | 99 | @Override 100 | public void onStart() { 101 | 102 | } 103 | 104 | @Override 105 | public void onStop() { 106 | 107 | } 108 | 109 | @Override 110 | public void onRestart() { 111 | 112 | } 113 | 114 | @Override 115 | public void onContentChanged() { 116 | 117 | } 118 | 119 | @Override 120 | public void onSaveInstanceState(Bundle outState) { 121 | 122 | } 123 | 124 | @Override 125 | public void onPostCreate(Bundle savedInstanceState) { 126 | 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /Mvp/src/main/java/com/r/mvp/cn/delegate/FragmentMvpDelegate.java: -------------------------------------------------------------------------------- 1 | package com.r.mvp.cn.delegate; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.view.View; 8 | 9 | import com.r.mvp.cn.root.IMvpPresenter; 10 | import com.r.mvp.cn.root.IMvpView; 11 | 12 | /** 13 | * Fragment生命周期 14 | * 15 | * @param 16 | * @param

17 | */ 18 | public interface FragmentMvpDelegate> { 19 | 20 | /** 21 | * Must be called from {@link Fragment#onCreate(Bundle)} 22 | * 23 | * @param saved The bundle 24 | */ 25 | void onCreate(Bundle saved); 26 | 27 | /** 28 | * Must be called from {@link Fragment#onDestroy()} 29 | */ 30 | void onDestroy(); 31 | 32 | /** 33 | * Must be called from {@link Fragment#onViewCreated(View, Bundle)} 34 | * 35 | * @param view The inflated view 36 | * @param savedInstanceState the bundle 37 | */ 38 | void onViewCreated(View view, @Nullable Bundle savedInstanceState); 39 | 40 | /** 41 | * Must be called from {@link Fragment#onDestroyView()} 42 | */ 43 | void onDestroyView(); 44 | 45 | /** 46 | * Must be called from {@link Fragment#onPause()} 47 | */ 48 | void onPause(); 49 | 50 | /** 51 | * Must be called from {@link Fragment#onResume()} 52 | */ 53 | void onResume(); 54 | 55 | /** 56 | * Must be called from {@link Fragment#onStart()} 57 | */ 58 | void onStart(); 59 | 60 | /** 61 | * Must be called from {@link Fragment#onStop()} 62 | */ 63 | void onStop(); 64 | 65 | /** 66 | * Must be called from {@link Fragment#onActivityCreated(Bundle)} 67 | * 68 | * @param savedInstanceState The saved bundle 69 | */ 70 | void onActivityCreated(Bundle savedInstanceState); 71 | 72 | /** 73 | * Must be called from {@link Fragment#onAttach(Activity)} 74 | * 75 | * @param activity The activity the fragment is attached to 76 | */ 77 | void onAttach(Activity activity); 78 | 79 | /** 80 | * Must be called from {@link Fragment#onDetach()} 81 | */ 82 | void onDetach(); 83 | 84 | /** 85 | * Must be called from {@link Fragment#onSaveInstanceState(Bundle)} 86 | */ 87 | void onSaveInstanceState(Bundle outState); 88 | } 89 | -------------------------------------------------------------------------------- /Mvp/src/main/java/com/r/mvp/cn/delegate/FragmentMvpDelegateImpl.java: -------------------------------------------------------------------------------- 1 | package com.r.mvp.cn.delegate; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.view.View; 8 | 9 | import com.r.mvp.cn.root.IMvpPresenter; 10 | import com.r.mvp.cn.root.IMvpView; 11 | 12 | /** 13 | * Fragment 媒介 14 | * 备注:主要是连接 Fragment 的生命周期与 Presenter 实现特定生命周期绑定与解除 V 15 | * 16 | * @author ZhongDaFeng 17 | */ 18 | public class FragmentMvpDelegateImpl> implements FragmentMvpDelegate { 19 | 20 | /** 21 | * Fragment 22 | */ 23 | protected Fragment fragment; 24 | 25 | /** 26 | * V & P 27 | */ 28 | private MvpDelegateCallback delegateCallback; 29 | 30 | public FragmentMvpDelegateImpl(Fragment fragment, MvpDelegateCallback delegateCallback) { 31 | if (fragment == null) { 32 | throw new NullPointerException("Fragment is null!"); 33 | } 34 | if (delegateCallback == null) { 35 | throw new NullPointerException("MvpDelegateCallback is null!"); 36 | } 37 | this.fragment = fragment; 38 | this.delegateCallback = delegateCallback; 39 | } 40 | 41 | /** 42 | * 是否保留V&P实例 43 | * 44 | * @return 45 | */ 46 | private static boolean retainVPInstance(Activity activity, Fragment fragment) { 47 | if (activity.isChangingConfigurations()) { 48 | return false; 49 | } 50 | if (activity.isFinishing()) { 51 | return false; 52 | } 53 | return !fragment.isRemoving(); 54 | } 55 | 56 | 57 | /** 58 | * 获取Activity 59 | * 60 | * @return 61 | */ 62 | private Activity getActivity() { 63 | Activity activity = fragment.getActivity(); 64 | if (activity == null) { 65 | throw new NullPointerException("Activity returned by Fragment.getActivity() is null. Fragment is " + fragment); 66 | } 67 | return activity; 68 | } 69 | 70 | @Override 71 | public void onCreate(Bundle saved) { 72 | P[] pArray = delegateCallback.getPresenter(); 73 | if (pArray != null) { 74 | V[] vArray = delegateCallback.getMvpView(); 75 | P p; 76 | V v; 77 | for (int i = 0; i < pArray.length; i++) { 78 | p = pArray[i]; 79 | v = vArray[i]; 80 | if (p != null && v != null) { 81 | //关联view 82 | p.attachView(v); 83 | } 84 | } 85 | } 86 | } 87 | 88 | @Override 89 | public void onDestroy() { 90 | Activity activity = getActivity(); 91 | P[] pArray = delegateCallback.getPresenter(); 92 | if (pArray != null) { 93 | P presenter; 94 | for (int i = 0; i < pArray.length; i++) { 95 | presenter = pArray[i]; 96 | if (presenter != null) { 97 | if (!retainVPInstance(activity, fragment)) { 98 | //销毁 V & P 实例 99 | presenter.destroy(); 100 | } 101 | } 102 | } 103 | } 104 | } 105 | 106 | @Override 107 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 108 | } 109 | 110 | @Override 111 | public void onDestroyView() { 112 | P[] pArray = delegateCallback.getPresenter(); 113 | if (pArray != null) { 114 | P presenter; 115 | for (int i = 0; i < pArray.length; i++) { 116 | presenter = pArray[i]; 117 | if (presenter != null) { 118 | //解除View 119 | presenter.detachView(); 120 | } 121 | } 122 | } 123 | } 124 | 125 | @Override 126 | public void onPause() { 127 | 128 | } 129 | 130 | @Override 131 | public void onResume() { 132 | 133 | } 134 | 135 | @Override 136 | public void onStart() { 137 | 138 | } 139 | 140 | @Override 141 | public void onStop() { 142 | 143 | } 144 | 145 | @Override 146 | public void onActivityCreated(Bundle savedInstanceState) { 147 | 148 | } 149 | 150 | @Override 151 | public void onAttach(Activity activity) { 152 | 153 | } 154 | 155 | @Override 156 | public void onDetach() { 157 | 158 | } 159 | 160 | @Override 161 | public void onSaveInstanceState(Bundle outState) { 162 | 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /Mvp/src/main/java/com/r/mvp/cn/delegate/MvpDelegateCallback.java: -------------------------------------------------------------------------------- 1 | package com.r.mvp.cn.delegate; 2 | 3 | import com.r.mvp.cn.root.IMvpPresenter; 4 | import com.r.mvp.cn.root.IMvpView; 5 | 6 | /** 7 | * V/P 媒介 8 | * 9 | * @param 10 | * @param

11 | */ 12 | public interface MvpDelegateCallback> { 13 | 14 | /** 15 | * Gets the presenter. 16 | */ 17 | P[] getPresenter(); 18 | 19 | /** 20 | * Gets the MvpView for the presenter 21 | * 22 | * @return The view associated with the presenter 23 | */ 24 | V[] getMvpView(); 25 | 26 | } 27 | 28 | -------------------------------------------------------------------------------- /Mvp/src/main/java/com/r/mvp/cn/model/ModelCallback.java: -------------------------------------------------------------------------------- 1 | package com.r.mvp.cn.model; 2 | 3 | /** 4 | * 模块数据回调接口 5 | * 6 | * @author ZhongDaFeng 7 | */ 8 | public interface ModelCallback { 9 | 10 | /** 11 | * 网络数据回调,泛指http 12 | * 13 | * @param 14 | */ 15 | interface Http { 16 | 17 | public void onSuccess(T object); 18 | 19 | public void onError(int code, String desc); 20 | 21 | public void onCancel(); 22 | } 23 | 24 | /** 25 | * 其他数据回调<本地数据,数据库等> 26 | * 27 | * @param 28 | */ 29 | interface Data { 30 | 31 | public void onSuccess(T object); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /Mvp/src/main/java/com/r/mvp/cn/model/ModelFactory.java: -------------------------------------------------------------------------------- 1 | package com.r.mvp.cn.model; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import com.r.mvp.cn.root.IMvpModel; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | /** 11 | * Model工厂类 12 | * 13 | * @author ZhongDaFeng 14 | */ 15 | public class ModelFactory { 16 | 17 | /** 18 | * 全局存储Model 19 | */ 20 | private static Map modelMap = new HashMap<>(); 21 | 22 | /** 23 | * 获取model 24 | * 查询Map中是否存在model实例,不存在时动态创建 25 | * 26 | * @param cls 类 27 | * @param model 28 | * @return 29 | */ 30 | public static T getModel(@NonNull Class cls) { 31 | String className = cls.getName();//类名 32 | T model = (T) modelMap.get(className); 33 | if (model == null) {//不存在 34 | model = getModelReflex(className); 35 | modelMap.put(className, model); 36 | } 37 | return model; 38 | } 39 | 40 | /** 41 | * 反射获取Model 42 | * 43 | * @param className 包含完整路径的类名称 com.ruffian.cn.User 44 | * @param 45 | * @return 46 | */ 47 | private static T getModelReflex(@NonNull String className) { 48 | T result = null; 49 | try { 50 | result = (T) Class.forName(className).newInstance(); 51 | } catch (Exception e) { 52 | e.printStackTrace(); 53 | } 54 | return result; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /Mvp/src/main/java/com/r/mvp/cn/proxy/MvpViewProxy.java: -------------------------------------------------------------------------------- 1 | package com.r.mvp.cn.proxy; 2 | 3 | import com.r.mvp.cn.root.IMvpView; 4 | 5 | import java.lang.reflect.InvocationHandler; 6 | import java.lang.reflect.Method; 7 | import java.lang.reflect.Proxy; 8 | 9 | /** 10 | * MvpView 代理 11 | *

12 | * 目的:MvpView 对象需要在 activity/fragment 组件销毁时清空,目的是异步回调时不再处理 MvpView 的方法 13 | * 原理:通过代理,将 MvpView 的方法调用放在代理类中实现,通过判断代理中 MvpView 是否为空判断是否需要回调方法,同时避免 P 中每次调用 MvpView 都要判空的麻烦 14 | * 15 | * @author ZhongDaFeng 16 | */ 17 | public class MvpViewProxy implements InvocationHandler { 18 | 19 | private V mView; 20 | 21 | //创建代理(接受委托) 22 | public Object newProxyInstance(V view) { 23 | this.mView = view; 24 | return Proxy.newProxyInstance(view.getClass().getClassLoader(), view.getClass().getInterfaces(), this); 25 | } 26 | 27 | @Override 28 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 29 | // V 为空直接返回 null 不再继续调用函数 30 | if (mView == null) { 31 | return null; 32 | } 33 | //调用目标方法 34 | Object temp = method.invoke(mView, args); 35 | return temp; 36 | } 37 | 38 | /** 39 | * 解绑View 40 | */ 41 | public void detachView() { 42 | mView = null; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /Mvp/src/main/java/com/r/mvp/cn/root/IMvpModel.java: -------------------------------------------------------------------------------- 1 | package com.r.mvp.cn.root; 2 | 3 | /** 4 | * MVP 根Model 5 | * MvpModel创建之后全局静态持有,因此不能持有短生命周期的对象,避免内存泄漏 6 | * 7 | * @author ZhongDaFeng 8 | */ 9 | public interface IMvpModel { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /Mvp/src/main/java/com/r/mvp/cn/root/IMvpPresenter.java: -------------------------------------------------------------------------------- 1 | package com.r.mvp.cn.root; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.annotation.UiThread; 5 | 6 | /** 7 | * MVP 根Presenter 8 | * 9 | * @author ZhongDaFeng 10 | */ 11 | public interface IMvpPresenter { 12 | 13 | /** 14 | * 将 View 添加到当前 Presenter 15 | */ 16 | @UiThread 17 | void attachView(@NonNull V view); 18 | 19 | /** 20 | * 将 View 从 Presenter 移除 21 | */ 22 | @UiThread 23 | void detachView(); 24 | 25 | /** 26 | * 销毁 V 实例 27 | */ 28 | @UiThread 29 | void destroy(); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Mvp/src/main/java/com/r/mvp/cn/root/IMvpView.java: -------------------------------------------------------------------------------- 1 | package com.r.mvp.cn.root; 2 | 3 | /** 4 | * MVP 根视图 5 | * 6 | * @author ZhongDaFeng 7 | */ 8 | public interface IMvpView { 9 | } 10 | -------------------------------------------------------------------------------- /Mvp/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /RHttp/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /RHttp/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 28 5 | buildToolsVersion '28.0.2' 6 | 7 | defaultConfig { 8 | minSdkVersion 14 9 | targetSdkVersion 28 10 | versionCode 1 11 | versionName "1.0" 12 | 13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 14 | 15 | } 16 | buildTypes { 17 | official { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | debug { 22 | minifyEnabled false 23 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 24 | } 25 | intranet { 26 | minifyEnabled false 27 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 28 | } 29 | extranet { 30 | minifyEnabled false 31 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 32 | } 33 | } 34 | 35 | } 36 | 37 | dependencies { 38 | implementation fileTree(include: ['*.jar'], dir: 'libs') 39 | testImplementation 'junit:junit:4.12' 40 | /*RxLifecycle基础库*/ 41 | api 'com.trello.rxlifecycle2:rxlifecycle:2.1.0' 42 | api 'com.trello.rxlifecycle2:rxlifecycle-components:2.1.0' 43 | /*网络请求框架*/ 44 | api 'com.squareup.retrofit2:retrofit:2.3.0' 45 | api 'com.squareup.retrofit2:converter-gson:2.3.0' 46 | api 'com.squareup.retrofit2:adapter-rxjava2:2.3.0' 47 | api 'com.squareup.okhttp3:logging-interceptor:3.8.0' 48 | /*RxJava&RxAndroid*/ 49 | api 'io.reactivex.rxjava2:rxjava:2.1.0' 50 | api 'io.reactivex.rxjava2:rxandroid:2.0.1' 51 | 52 | } 53 | -------------------------------------------------------------------------------- /RHttp/libs/lite-orm-1.9.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RuffianZhong/Rx-Mvp/6fe60642c3ed1aca8b6990ec5c25abc90e68683d/RHttp/libs/lite-orm-1.9.2.jar -------------------------------------------------------------------------------- /RHttp/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 D:\android-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 | -------------------------------------------------------------------------------- /RHttp/src/androidTest/java/com/r/http/cn/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.r.http.cn.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /RHttp/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/api/Api.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.api; 2 | 3 | import com.google.gson.JsonElement; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import io.reactivex.Observable; 9 | import okhttp3.MultipartBody; 10 | import okhttp3.RequestBody; 11 | import okhttp3.ResponseBody; 12 | import retrofit2.http.Body; 13 | import retrofit2.http.DELETE; 14 | import retrofit2.http.FieldMap; 15 | import retrofit2.http.FormUrlEncoded; 16 | import retrofit2.http.GET; 17 | import retrofit2.http.HTTP; 18 | import retrofit2.http.Header; 19 | import retrofit2.http.HeaderMap; 20 | import retrofit2.http.Multipart; 21 | import retrofit2.http.POST; 22 | import retrofit2.http.PUT; 23 | import retrofit2.http.Part; 24 | import retrofit2.http.PartMap; 25 | import retrofit2.http.QueryMap; 26 | import retrofit2.http.Streaming; 27 | import retrofit2.http.Url; 28 | 29 | /** 30 | * Api接口 31 | * 32 | * @author ZhongDaFeng 33 | */ 34 | public interface Api { 35 | 36 | /** 37 | * GET 请求 38 | * 39 | * @param url api接口url 40 | * @param parameter 请求参数map 41 | * @param header 请求头map 42 | * @return 43 | */ 44 | @GET 45 | Observable get(@Url String url, @QueryMap Map parameter, @HeaderMap Map header); 46 | 47 | 48 | /** 49 | * POST 请求 50 | * 51 | * @param url api接口url 52 | * @param parameter 请求参数map 53 | * @param header 请求头map 54 | * @return 55 | */ 56 | @FormUrlEncoded 57 | @POST 58 | Observable post(@Url String url, @FieldMap Map parameter, @HeaderMap Map header); 59 | 60 | 61 | /** 62 | * @param requestBody 用于String/JSON格式数据 63 | */ 64 | @POST 65 | Observable post(@Url String url, @Body RequestBody requestBody, @HeaderMap Map header); 66 | 67 | 68 | /** 69 | * DELETE 请求 70 | * 71 | * @param url api接口url 72 | * @param parameter 请求参数map 73 | * @param header 请求头map 74 | * @return 75 | */ 76 | @DELETE 77 | Observable delete(@Url String url, @QueryMap Map parameter, @HeaderMap Map header); 78 | 79 | 80 | /** 81 | * PUT 请求 82 | * 83 | * @param url api接口url 84 | * @param parameter 请求参数map 85 | * @param header 请求头map 86 | * @return 87 | */ 88 | @FormUrlEncoded 89 | @PUT 90 | Observable put(@Url String url, @FieldMap Map parameter, @HeaderMap Map header); 91 | 92 | 93 | /** 94 | * 多文件上传 95 | * 96 | * @param url api接口url 97 | * @param parameter 请求接口参数 98 | * @param header 请求头map 99 | * @param fileList 文件列表 100 | * @return 101 | * @Multipart 文件上传注解 multipart/form-data 102 | */ 103 | @Multipart 104 | @POST 105 | Observable upload(@Url String url, @PartMap Map parameter, @HeaderMap Map header, @Part List fileList); 106 | 107 | 108 | /** 109 | * 断点续传下载 110 | * 111 | * @param range 断点下载范围 bytes= start - end 112 | * @param url 下载地址 113 | * @param header 请求头map 114 | * @return 115 | * @Streaming 防止内容写入内存, 大文件通过此注解避免OOM 116 | */ 117 | @Streaming 118 | @GET 119 | Observable download(@Header("RANGE") String range, @Url String url, @HeaderMap Map header); 120 | 121 | 122 | } 123 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/callback/BaseCallback.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.callback; 2 | 3 | import com.r.http.cn.RHttp; 4 | import com.r.http.cn.exception.ApiException; 5 | import com.r.http.cn.exception.ExceptionEngine; 6 | import com.r.http.cn.observer.HttpObserver; 7 | import com.r.http.cn.utils.ThreadUtils; 8 | 9 | import java.lang.reflect.ParameterizedType; 10 | 11 | import io.reactivex.annotations.NonNull; 12 | 13 | /** 14 | * Http请求基础回调接口 15 | * 备注:处理基本逻辑 16 | * 17 | * @author ZhongDaFeng 18 | */ 19 | public abstract class BaseCallback extends HttpObserver { 20 | 21 | @Override 22 | public void onNext(@NonNull T value) { 23 | super.onNext(value); 24 | inSuccess(value); 25 | } 26 | 27 | @Override 28 | public void onError(Throwable e) { 29 | super.onError(e); 30 | if (e instanceof ApiException) { 31 | ApiException exception = (ApiException) e; 32 | inError(exception.getCode(), exception.getMsg()); 33 | } else { 34 | inError(ExceptionEngine.UN_KNOWN_ERROR, "未知错误"); 35 | } 36 | } 37 | 38 | @Override 39 | public void onCanceled() { 40 | onCanceledLogic(); 41 | } 42 | 43 | /** 44 | * 请求成功 45 | * 46 | * @param t 47 | */ 48 | public abstract void inSuccess(T t); 49 | 50 | /** 51 | * 请求出错 52 | * 53 | * @param code 54 | * @param desc 55 | */ 56 | public abstract void inError(int code, String desc); 57 | 58 | /** 59 | * 请求取消 60 | */ 61 | public abstract void inCancel(); 62 | 63 | /** 64 | * Http被取消回调处理逻辑 65 | */ 66 | private void onCanceledLogic() { 67 | if (!ThreadUtils.isMainThread()) { 68 | RHttp.Configure.get().getHandler().post(new Runnable() { 69 | @Override 70 | public void run() { 71 | inCancel(); 72 | } 73 | }); 74 | } else { 75 | inCancel(); 76 | } 77 | } 78 | 79 | @Deprecated 80 | private void getTypeClass() { 81 | /** 82 | * 获取当前类泛型(暂时保留) 83 | */ 84 | ParameterizedType ptClass = (ParameterizedType) getClass().getGenericSuperclass(); 85 | Class mClass; 86 | if (ptClass != null) { 87 | mClass = (Class) ptClass.getActualTypeArguments()[0]; 88 | //LogUtils.e("当前类泛型:" + mClass); 89 | } 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/callback/HttpCallback.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.callback; 2 | 3 | import com.r.http.cn.exception.ExceptionEngine; 4 | import com.r.http.cn.helper.ParseHelper; 5 | 6 | /** 7 | * Http请求回调 8 | * 9 | * @author ZhongDaFeng 10 | */ 11 | public abstract class HttpCallback extends BaseCallback implements ParseHelper { 12 | 13 | /** 14 | * 是否回调成功函数 15 | */ 16 | private boolean callSuccess = true; 17 | 18 | @Override 19 | public T parse(String data) { 20 | T t = null; 21 | try { 22 | t = onConvert(data); 23 | callSuccess = true; 24 | } catch (Exception e) { 25 | callSuccess = false; 26 | e.printStackTrace(); 27 | onError(ExceptionEngine.ANALYTIC_CLIENT_DATA_ERROR, "解析数据出错"); 28 | } 29 | return t; 30 | } 31 | 32 | 33 | @Override 34 | public void inSuccess(T value) { 35 | T result = parse((String) value); 36 | if (callSuccess && isBusinessOk()) { 37 | onSuccess(result); 38 | } 39 | } 40 | 41 | @Override 42 | public void inError(int code, String desc) { 43 | onError(code, desc); 44 | } 45 | 46 | @Override 47 | public void inCancel() { 48 | onCancel(); 49 | } 50 | 51 | /** 52 | * 数据转换/解析数据 53 | * 54 | * @param data 55 | * @return 56 | */ 57 | public abstract T onConvert(String data) throws Exception; 58 | 59 | /** 60 | * 成功回调 61 | * 62 | * @param value 63 | */ 64 | public abstract void onSuccess(T value); 65 | 66 | /** 67 | * 失败回调 68 | * 69 | * @param code 70 | * @param desc 71 | */ 72 | public abstract void onError(int code, String desc); 73 | 74 | /** 75 | * 取消回调 76 | */ 77 | public abstract void onCancel(); 78 | 79 | /** 80 | * 业务逻辑是否成功 81 | * 82 | * @return 83 | */ 84 | public abstract boolean isBusinessOk(); 85 | 86 | } 87 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/callback/UploadCallback.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.callback; 2 | 3 | import com.r.http.cn.load.upload.UploadProgressCallback; 4 | 5 | import java.io.File; 6 | 7 | /** 8 | * 上传回调接口 9 | * 10 | * @author ZhongDaFeng 11 | */ 12 | public abstract class UploadCallback extends HttpCallback implements UploadProgressCallback { 13 | 14 | 15 | @Override 16 | public void progress(File file, long currentSize, long totalSize, float progress, int currentIndex, int totalFile) { 17 | onProgress(file, currentSize, totalSize, progress, currentIndex, totalFile); 18 | } 19 | 20 | /** 21 | * 上传回调 22 | * 23 | * @param file 24 | * @param currentSize 25 | * @param totalSize 26 | * @param progress 27 | * @param currentIndex 28 | * @param totalFile 29 | */ 30 | public abstract void onProgress(File file, long currentSize, long totalSize, float progress, int currentIndex, int totalFile); 31 | 32 | /** 33 | * 数据转换/解析数据 34 | * 35 | * @param data 36 | * @return 37 | */ 38 | public abstract T onConvert(String data); 39 | 40 | /** 41 | * 成功回调 42 | * 43 | * @param value 44 | */ 45 | public abstract void onSuccess(T value); 46 | 47 | /** 48 | * 失败回调 49 | * 50 | * @param code 51 | * @param desc 52 | */ 53 | public abstract void onError(int code, String desc); 54 | 55 | /** 56 | * 取消回调 57 | */ 58 | public abstract void onCancel(); 59 | 60 | } 61 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/cancel/RequestCancel.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.cancel; 2 | 3 | /** 4 | * 请求取消接口 5 | * 6 | * @author ZhongDaFeng 7 | */ 8 | public interface RequestCancel { 9 | 10 | /** 11 | * 取消请求 12 | */ 13 | void cancel(); 14 | 15 | /** 16 | * 请求被取消 17 | */ 18 | void onCanceled(); 19 | } 20 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/cancel/RequestManager.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.cancel; 2 | 3 | import io.reactivex.disposables.Disposable; 4 | 5 | /** 6 | * Http请求管理接口 7 | * 8 | * @author ZhongDaFeng 9 | */ 10 | public interface RequestManager { 11 | /** 12 | * 添加 13 | * 14 | * @param tag 15 | * @param disposable 16 | */ 17 | void add(T tag, Disposable disposable); 18 | 19 | /** 20 | * 移除 21 | * 22 | * @param tag 23 | */ 24 | void remove(T tag); 25 | 26 | /** 27 | * 取消 28 | * 29 | * @param tag 30 | */ 31 | void cancel(T tag); 32 | 33 | /** 34 | * 取消全部 35 | */ 36 | void cancelAll(); 37 | 38 | } -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/cancel/RequestManagerImpl.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.cancel; 2 | 3 | import android.annotation.TargetApi; 4 | import android.os.Build; 5 | import android.support.v4.util.ArrayMap; 6 | 7 | import java.util.Set; 8 | 9 | import io.reactivex.disposables.Disposable; 10 | 11 | /** 12 | * Http请求管理实现类 13 | * 14 | * @author ZhongDaFeng 15 | */ 16 | public class RequestManagerImpl implements RequestManager { 17 | 18 | private static volatile RequestManagerImpl mInstance; 19 | private ArrayMap mMaps;//处理,请求列表 20 | 21 | public static RequestManagerImpl getInstance() { 22 | if (mInstance == null) { 23 | synchronized (RequestManagerImpl.class) { 24 | if (mInstance == null) { 25 | mInstance = new RequestManagerImpl(); 26 | } 27 | } 28 | } 29 | return mInstance; 30 | } 31 | 32 | @TargetApi(Build.VERSION_CODES.KITKAT) 33 | private RequestManagerImpl() { 34 | mMaps = new ArrayMap<>(); 35 | } 36 | 37 | @TargetApi(Build.VERSION_CODES.KITKAT) 38 | @Override 39 | public void add(Object tag, Disposable disposable) { 40 | mMaps.put(tag, disposable); 41 | } 42 | 43 | @TargetApi(Build.VERSION_CODES.KITKAT) 44 | @Override 45 | public void remove(Object tag) { 46 | if (!mMaps.isEmpty()) { 47 | mMaps.remove(tag); 48 | } 49 | } 50 | 51 | @TargetApi(Build.VERSION_CODES.KITKAT) 52 | @Override 53 | public void cancel(Object tag) { 54 | if (mMaps.isEmpty()) { 55 | return; 56 | } 57 | if (mMaps.get(tag) == null) { 58 | return; 59 | } 60 | if (!mMaps.get(tag).isDisposed()) { 61 | mMaps.get(tag).dispose(); 62 | } 63 | mMaps.remove(tag); 64 | } 65 | 66 | @Override 67 | public void cancelAll() { 68 | if (mMaps.isEmpty()) { 69 | return; 70 | } 71 | //遍历取消请求 72 | Disposable disposable; 73 | Set keySet = mMaps.keySet(); 74 | for (Object key : keySet) { 75 | disposable = mMaps.get(key); 76 | if (!disposable.isDisposed()) { 77 | disposable.dispose(); 78 | } 79 | } 80 | mMaps.clear(); 81 | } 82 | 83 | 84 | /** 85 | * 判断是否取消了请求 86 | * 87 | * @param tag 88 | * @return 89 | */ 90 | public boolean isDisposed(Object tag) { 91 | if (mMaps.isEmpty() || mMaps.get(tag) == null) return true; 92 | return mMaps.get(tag).isDisposed(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/exception/ApiException.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.exception; 2 | 3 | /** 4 | * api接口错误/异常统一处理类 5 | * 6 | * @author ZhongDaFeng 7 | */ 8 | public class ApiException extends Exception { 9 | private int code;//错误码 10 | private String msg;//错误信息 11 | 12 | public ApiException(Throwable throwable, int code) { 13 | super(throwable); 14 | this.code = code; 15 | } 16 | 17 | public ApiException(int code, String msg) { 18 | this.code = code; 19 | this.msg = msg; 20 | } 21 | 22 | public int getCode() { 23 | return code; 24 | } 25 | 26 | public void setCode(int code) { 27 | this.code = code; 28 | } 29 | 30 | public String getMsg() { 31 | return msg; 32 | } 33 | 34 | public void setMsg(String msg) { 35 | this.msg = msg; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/exception/ExceptionEngine.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.exception; 2 | 3 | import com.google.gson.JsonParseException; 4 | import com.google.gson.stream.MalformedJsonException; 5 | 6 | import org.json.JSONException; 7 | 8 | import java.net.ConnectException; 9 | import java.net.SocketTimeoutException; 10 | import java.net.UnknownHostException; 11 | import java.text.ParseException; 12 | 13 | import javax.net.ssl.SSLHandshakeException; 14 | 15 | import retrofit2.HttpException; 16 | 17 | 18 | /** 19 | * 错误/异常处理工具 20 | * 21 | * @author ZhongDaFeng 22 | */ 23 | public class ExceptionEngine { 24 | 25 | public static final int UN_KNOWN_ERROR = 1000;//未知错误 26 | public static final int ANALYTIC_SERVER_DATA_ERROR = 1001;//解析(服务器)数据错误 27 | public static final int ANALYTIC_CLIENT_DATA_ERROR = 1002;//解析(客户端)数据错误 28 | public static final int CONNECT_ERROR = 1003;//网络连接错误 29 | public static final int TIME_OUT_ERROR = 1004;//网络连接超时 30 | 31 | public static ApiException handleException(Throwable e) { 32 | ApiException ex; 33 | if (e instanceof HttpException) { //HTTP错误 34 | HttpException httpExc = (HttpException) e; 35 | ex = new ApiException(e, httpExc.code()); 36 | ex.setMsg("网络错误"); //均视为网络错误 37 | return ex; 38 | } else if (e instanceof ServerException) { //服务器返回的错误(交由开发者自己处理) 39 | ServerException serverExc = (ServerException) e; 40 | ex = new ApiException(serverExc, serverExc.getCode()); 41 | ex.setMsg(serverExc.getMsg()); 42 | return ex; 43 | } else if (e instanceof JsonParseException 44 | || e instanceof JSONException 45 | || e instanceof ParseException || e instanceof MalformedJsonException) { //解析数据错误 46 | ex = new ApiException(e, ANALYTIC_SERVER_DATA_ERROR); 47 | ex.setMsg("解析错误"); 48 | return ex; 49 | } else if (e instanceof ConnectException || e instanceof SSLHandshakeException || e instanceof UnknownHostException) {//连接网络错误 50 | ex = new ApiException(e, CONNECT_ERROR); 51 | ex.setMsg("连接失败"); 52 | return ex; 53 | } else if (e instanceof SocketTimeoutException) {//网络超时 54 | ex = new ApiException(e, TIME_OUT_ERROR); 55 | ex.setMsg("网络超时"); 56 | return ex; 57 | } else { //未知错误 58 | ex = new ApiException(e, UN_KNOWN_ERROR); 59 | ex.setMsg("未知错误"); 60 | return ex; 61 | } 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/exception/ServerException.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.exception; 2 | 3 | /** 4 | * 自定义服务器错误 5 | * 6 | * @author ZhongDaFeng 7 | */ 8 | public class ServerException extends RuntimeException { 9 | private int code; 10 | private String msg; 11 | 12 | public ServerException(int code, String msg) { 13 | this.code = code; 14 | this.msg = msg; 15 | } 16 | 17 | public int getCode() { 18 | return code; 19 | } 20 | 21 | public String getMsg() { 22 | return msg; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/function/HttpResultFunction.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.function; 2 | 3 | 4 | import com.r.http.cn.exception.ExceptionEngine; 5 | import com.r.http.cn.utils.LogUtils; 6 | 7 | import io.reactivex.Observable; 8 | import io.reactivex.annotations.NonNull; 9 | import io.reactivex.functions.Function; 10 | 11 | /** 12 | * http结果处理函数 13 | * 14 | * @author ZhongDaFeng 15 | */ 16 | public class HttpResultFunction implements Function> { 17 | @Override 18 | public Observable apply(@NonNull Throwable throwable) throws Exception { 19 | //打印具体错误 20 | LogUtils.e("HttpResultFunction:" + throwable); 21 | return Observable.error(ExceptionEngine.handleException(throwable)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/function/ServerResultFunction.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.function; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.JsonElement; 5 | import com.r.http.cn.utils.LogUtils; 6 | 7 | import io.reactivex.annotations.NonNull; 8 | import io.reactivex.functions.Function; 9 | 10 | /** 11 | * 服务器结果处理函数 12 | * 13 | * @author ZhongDaFeng 14 | */ 15 | public class ServerResultFunction implements Function { 16 | @Override 17 | public Object apply(@NonNull JsonElement response) throws Exception { 18 | //打印服务器回传结果 19 | LogUtils.e("HttpResponse:" + response.toString()); 20 | /*此处不再处理业务相关逻辑交由开发者重写httpCallback*/ 21 | return new Gson().toJson(response); 22 | } 23 | } -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/helper/ParseHelper.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.helper; 2 | 3 | /** 4 | * 数据解析helper 5 | * 6 | * @author ZhongDaFeng 7 | */ 8 | public interface ParseHelper { 9 | /*解析数据*/ 10 | T parse(String data); 11 | } 12 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/load/download/DownloadCallback.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.load.download; 2 | 3 | import com.r.http.cn.model.Download; 4 | 5 | /** 6 | * 下载回调 7 | * 8 | * @author ZhongDaFeng 9 | */ 10 | public abstract class DownloadCallback { 11 | 12 | /** 13 | * 进度回调 14 | * 15 | * @param state 下载状态 16 | * @param currentSize 当前已下载 17 | * @param totalSize 文件总大小 18 | * @param progress 进度 19 | */ 20 | public abstract void onProgress(Download.State state, long currentSize, long totalSize, float progress); 21 | 22 | /** 23 | * 下载出错 24 | * 25 | * @param e 26 | */ 27 | public abstract void onError(Throwable e); 28 | 29 | /** 30 | * 下载成功 31 | * 32 | * @param object 33 | */ 34 | public abstract void onSuccess(T object); 35 | } 36 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/load/download/DownloadInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.load.download; 2 | 3 | import java.io.IOException; 4 | 5 | import okhttp3.Interceptor; 6 | import okhttp3.Response; 7 | 8 | 9 | /** 10 | * 通过Interceptor回调监听Response进度 11 | * 12 | * @author ZhongDaFeng 13 | */ 14 | public class DownloadInterceptor implements Interceptor { 15 | 16 | private DownloadProgressCallback callback; 17 | 18 | public DownloadInterceptor(DownloadProgressCallback callback) { 19 | this.callback = callback; 20 | } 21 | 22 | @Override 23 | public Response intercept(Chain chain) throws IOException { 24 | Response response = chain.proceed(chain.request()); 25 | return response.newBuilder() 26 | .body(new DownloadResponseBody(response.body(), callback)) 27 | .build(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/load/download/DownloadObserver.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.load.download; 2 | 3 | 4 | import android.os.Handler; 5 | 6 | import com.r.http.cn.RDownLoad; 7 | import com.r.http.cn.model.Download; 8 | import com.r.http.cn.utils.ComputeUtils; 9 | import com.r.http.cn.utils.DBHelper; 10 | import com.r.http.cn.utils.LogUtils; 11 | 12 | import java.lang.ref.SoftReference; 13 | 14 | import io.reactivex.Observer; 15 | import io.reactivex.annotations.NonNull; 16 | import io.reactivex.disposables.Disposable; 17 | 18 | 19 | /** 20 | * 下载观察者(监听) 21 | * 备注:在此处监听: 开始下载 、下载错误 、下载完成 等状态 22 | * 23 | * @author ZhongDaFeng 24 | */ 25 | public class DownloadObserver implements DownloadProgressCallback, Observer { 26 | 27 | private Download download; 28 | private Handler handler; 29 | private Disposable disposable; 30 | private SoftReference downloadCallback; 31 | 32 | public void setDownload(Download download) { 33 | this.download = download; 34 | this.downloadCallback = new SoftReference<>(download.getCallback()); 35 | } 36 | 37 | public DownloadObserver(Download download, Handler handler) { 38 | this.download = download; 39 | this.handler = handler; 40 | this.downloadCallback = new SoftReference<>(download.getCallback()); 41 | } 42 | 43 | /** 44 | * 开始下载/继续下载 45 | * 备注:继续下载需要获取之前下载的数据 46 | */ 47 | @Override 48 | public void onSubscribe(@NonNull Disposable d) { 49 | disposable = d; 50 | download.setState(Download.State.WAITING);//等待状态 51 | DBHelper.get().insertOrUpdate(download);//更新数据库 52 | if (downloadCallback.get() != null) {//回调 53 | float progress = ComputeUtils.getProgress(download.getCurrentSize(), download.getTotalSize()); 54 | downloadCallback.get().onProgress(download.getState(), download.getCurrentSize(), download.getTotalSize(), progress); 55 | } 56 | } 57 | 58 | /** 59 | * 下载出错 60 | * 备注:回调进度,回调onError 61 | */ 62 | @Override 63 | public void onError(Throwable e) { 64 | download.setState(Download.State.ERROR);//错误状态 65 | RDownLoad.get().removeDownload(download, false);//移除下载 66 | DBHelper.get().insertOrUpdate(download);//更新数据 67 | if (downloadCallback.get() != null) { 68 | float progress = ComputeUtils.getProgress(download.getCurrentSize(), download.getTotalSize()); 69 | downloadCallback.get().onProgress(download.getState(), download.getCurrentSize(), download.getTotalSize(), progress); 70 | downloadCallback.get().onError(e); 71 | } 72 | } 73 | 74 | /** 75 | * 下载完成 76 | * 备注:将开发者传入的Download子类回传 77 | */ 78 | @Override 79 | public void onNext(T t) { 80 | download.setState(Download.State.FINISH);//下载完成 81 | RDownLoad.get().removeDownload(download, false);//移除下载 82 | DBHelper.get().insertOrUpdate(download);//更新数据 83 | if (downloadCallback.get() != null) {//回调 84 | downloadCallback.get().onSuccess(t); 85 | } 86 | } 87 | 88 | @Override 89 | public void onComplete() { 90 | } 91 | 92 | 93 | /** 94 | * 进度回调 95 | * 96 | * @param currentSize 当前值 97 | * @param totalSize 总大小 98 | */ 99 | @Override 100 | public void progress(long currentSize, long totalSize) { 101 | if (download.getTotalSize() > totalSize) { 102 | currentSize = download.getTotalSize() - totalSize + currentSize; 103 | } else { 104 | download.setTotalSize(totalSize); 105 | } 106 | download.setCurrentSize(currentSize); 107 | handler.post(new Runnable() { 108 | @Override 109 | public void run() { 110 | /*下载进度==总进度修改为完成状态*/ 111 | if ((download.getCurrentSize() == download.getTotalSize()) && (download.getTotalSize() != 0)) { 112 | download.setState(Download.State.FINISH); 113 | } 114 | /*如果暂停或者停止状态延迟,不需要继续发送回调,影响显示*/ 115 | if (download.getState() != Download.State.PAUSE) { 116 | float progress = (float) download.getCurrentSize() / (float) download.getTotalSize(); 117 | if (downloadCallback.get() != null) { 118 | downloadCallback.get().onProgress(download.getState(), download.getCurrentSize(), download.getTotalSize(), progress); 119 | } 120 | } 121 | } 122 | }); 123 | } 124 | 125 | /** 126 | * 取消请求 127 | * 备注:暂停下载时调用 128 | */ 129 | public void dispose() { 130 | if (disposable != null && !disposable.isDisposed()) { 131 | disposable.dispose(); 132 | } 133 | } 134 | 135 | } -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/load/download/DownloadProgressCallback.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.load.download; 2 | 3 | 4 | /** 5 | * 下载回调接口 6 | * 7 | * @author ZhongDaFeng 8 | */ 9 | public interface DownloadProgressCallback { 10 | 11 | /** 12 | * 下载进度回调 13 | * 14 | * @param currentSize 当前值 15 | * @param totalSize 总大小 16 | */ 17 | void progress(long currentSize, long totalSize); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/load/download/DownloadResponseBody.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.load.download; 2 | 3 | import com.r.http.cn.utils.LogUtils; 4 | 5 | import java.io.IOException; 6 | 7 | import okhttp3.MediaType; 8 | import okhttp3.ResponseBody; 9 | import okio.Buffer; 10 | import okio.BufferedSource; 11 | import okio.ForwardingSource; 12 | import okio.Okio; 13 | import okio.Source; 14 | 15 | 16 | /** 17 | * 下载ResponseBody 18 | * 19 | * @author ZhongDaFeng 20 | */ 21 | public class DownloadResponseBody extends ResponseBody { 22 | 23 | private ResponseBody responseBody; 24 | private DownloadProgressCallback callback; 25 | private BufferedSource bufferedSource; 26 | 27 | public DownloadResponseBody(ResponseBody responseBody, DownloadProgressCallback callback) { 28 | this.responseBody = responseBody; 29 | this.callback = callback; 30 | } 31 | 32 | @Override 33 | public MediaType contentType() { 34 | return responseBody.contentType(); 35 | } 36 | 37 | @Override 38 | public long contentLength() { 39 | return responseBody.contentLength(); 40 | } 41 | 42 | @Override 43 | public BufferedSource source() { 44 | if (bufferedSource == null) { 45 | bufferedSource = Okio.buffer(source(responseBody.source())); 46 | } 47 | return bufferedSource; 48 | } 49 | 50 | private Source source(Source source) { 51 | return new ForwardingSource(source) { 52 | long readBytesCount = 0L; 53 | long totalBytesCount = 0L; 54 | 55 | @Override 56 | public long read(Buffer sink, long byteCount) throws IOException { 57 | long bytesRead = super.read(sink, byteCount); 58 | // read() returns the number of bytes read, or -1 if this source is exhausted. 59 | readBytesCount += bytesRead != -1 ? bytesRead : 0; 60 | if (totalBytesCount == 0) { 61 | totalBytesCount = contentLength(); 62 | } 63 | LogUtils.d("download progress readBytesCount:" + readBytesCount + " totalBytesCount:" + totalBytesCount + " callback:" + callback); 64 | if (callback != null) { 65 | callback.progress(readBytesCount, totalBytesCount); 66 | } 67 | return bytesRead; 68 | } 69 | }; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/load/upload/UploadProgressCallback.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.load.upload; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * 进度回调接口 7 | * 8 | * @author ZhongDaFeng 9 | */ 10 | public interface UploadProgressCallback { 11 | 12 | /** 13 | * 上传进度回调 14 | * 15 | * @param currentSize 当前值 16 | * @param totalSize 总大小 17 | * @param progress 进度 18 | * @param currentIndex 当前下标 19 | * @param totalFile 总文件数 20 | */ 21 | void progress(File file, long currentSize, long totalSize, float progress, int currentIndex, int totalFile); 22 | } 23 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/load/upload/UploadRequestBody.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.load.upload; 2 | 3 | 4 | import com.r.http.cn.RHttp; 5 | 6 | import java.io.File; 7 | import java.io.IOException; 8 | 9 | import okhttp3.MediaType; 10 | import okhttp3.RequestBody; 11 | import okio.Buffer; 12 | import okio.BufferedSink; 13 | import okio.ForwardingSink; 14 | import okio.Okio; 15 | import okio.Sink; 16 | 17 | /** 18 | * 上传RequestBody 19 | * 20 | * @author ZhongDaFeng 21 | */ 22 | public class UploadRequestBody extends RequestBody { 23 | 24 | //实际的待包装请求体 25 | private final RequestBody requestBody; 26 | //进度回调接口 27 | private final UploadProgressCallback progressCallback; 28 | //包装完成的BufferedSink 29 | private BufferedSink bufferedSink; 30 | //源文件 31 | private File file; 32 | //当前下标 33 | private int current; 34 | //上传总文件 35 | private int totalFile; 36 | 37 | 38 | public UploadRequestBody(RequestBody requestBody, File file, int current, int totalFile, UploadProgressCallback progressCallback) { 39 | this.file = file; 40 | this.current = current; 41 | this.totalFile = totalFile; 42 | this.requestBody = requestBody; 43 | this.progressCallback = progressCallback; 44 | } 45 | 46 | /** 47 | * 重写调用实际的响应体的contentType 48 | * 49 | * @return MediaType 50 | */ 51 | @Override 52 | public MediaType contentType() { 53 | return requestBody.contentType(); 54 | } 55 | 56 | /** 57 | * 重写调用实际的响应体的contentLength 58 | * 59 | * @return contentLength 60 | * @throws IOException 异常 61 | */ 62 | @Override 63 | public long contentLength() throws IOException { 64 | return requestBody.contentLength(); 65 | } 66 | 67 | /** 68 | * 重写writeTo 69 | * 70 | * @param sink BufferedSink 71 | * @throws IOException 异常 72 | */ 73 | @Override 74 | public void writeTo(BufferedSink sink) throws IOException { 75 | if (null == bufferedSink) { 76 | bufferedSink = Okio.buffer(sink(sink)); 77 | } 78 | requestBody.writeTo(bufferedSink); 79 | //必须调用flush,否则最后一部分数据可能不会被写入 80 | bufferedSink.flush(); 81 | } 82 | 83 | /** 84 | * 写入,回调进度接口 85 | * 86 | * @param sink Sink 87 | * @return Sink 88 | */ 89 | private Sink sink(Sink sink) { 90 | return new ForwardingSink(sink) { 91 | //当前写入字节数 92 | long writtenBytesCount = 0L; 93 | //总字节长度,避免多次调用contentLength()方法 94 | long totalBytesCount = 0L; 95 | 96 | @Override 97 | public void write(Buffer source, long byteCount) throws IOException { 98 | super.write(source, byteCount); 99 | //增加当前写入的字节数 100 | writtenBytesCount += byteCount; 101 | //获得contentLength的值,后续不再调用 102 | if (totalBytesCount == 0) { 103 | totalBytesCount = contentLength(); 104 | } 105 | //回调接口 106 | if (progressCallback != null) { 107 | RHttp.Configure.get().getHandler().post(new Runnable() { 108 | @Override 109 | public void run() { 110 | float progress = (float) writtenBytesCount / (float) totalBytesCount; 111 | progressCallback.progress(file, writtenBytesCount, totalBytesCount, progress, current, totalFile); 112 | } 113 | }); 114 | } 115 | } 116 | }; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/model/Download.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.model; 2 | 3 | import com.litesuits.orm.db.annotation.Column; 4 | import com.litesuits.orm.db.annotation.Ignore; 5 | import com.litesuits.orm.db.annotation.PrimaryKey; 6 | import com.litesuits.orm.db.annotation.Table; 7 | import com.litesuits.orm.db.enums.AssignType; 8 | import com.r.http.cn.api.Api; 9 | import com.r.http.cn.load.download.DownloadCallback; 10 | 11 | import java.io.Serializable; 12 | 13 | 14 | /** 15 | * 下载实体类 16 | * 备注:用户使用下载类需要继承此类 17 | * 18 | * @author ZhongDaFeng 19 | */ 20 | @Table("download") 21 | public class Download implements Serializable { 22 | 23 | @PrimaryKey(AssignType.AUTO_INCREMENT) 24 | @Column("_id") 25 | private long id; 26 | 27 | @Column("localUrl") 28 | private String localUrl;//本地存储地址 29 | 30 | @Column("serverUrl") 31 | private String serverUrl;//下载地址 32 | 33 | @Column("totalSize") 34 | private long totalSize;//文件大小 35 | 36 | @Column("currentSize") 37 | private long currentSize;//当前大小 38 | 39 | @Column("state") 40 | private State state = State.NONE;//下载状态 41 | 42 | @Ignore 43 | private Api api;//接口service 44 | 45 | @Ignore 46 | private DownloadCallback callback;//回调接口 47 | 48 | public Download() { 49 | } 50 | 51 | public Download(String url) { 52 | setServerUrl(url); 53 | } 54 | 55 | public Download(String url, DownloadCallback callback) { 56 | setServerUrl(url); 57 | setCallback(callback); 58 | } 59 | 60 | /** 61 | * 枚举下载状态 62 | */ 63 | public enum State { 64 | NONE, //无状态 65 | WAITING, //等待 66 | LOADING, //下载中 67 | PAUSE, //暂停 68 | ERROR, //错误 69 | FINISH, //完成 70 | } 71 | 72 | 73 | public long getId() { 74 | return id; 75 | } 76 | 77 | public void setId(long id) { 78 | this.id = id; 79 | } 80 | 81 | public String getLocalUrl() { 82 | return localUrl == null ? "" : localUrl; 83 | } 84 | 85 | public void setLocalUrl(String localUrl) { 86 | this.localUrl = localUrl; 87 | } 88 | 89 | public String getServerUrl() { 90 | return serverUrl == null ? "" : serverUrl; 91 | } 92 | 93 | public void setServerUrl(String serverUrl) { 94 | this.serverUrl = serverUrl; 95 | } 96 | 97 | public long getTotalSize() { 98 | return totalSize; 99 | } 100 | 101 | public void setTotalSize(long totalSize) { 102 | this.totalSize = totalSize; 103 | } 104 | 105 | public long getCurrentSize() { 106 | return currentSize; 107 | } 108 | 109 | public void setCurrentSize(long currentSize) { 110 | this.currentSize = currentSize; 111 | } 112 | 113 | public State getState() { 114 | return state; 115 | } 116 | 117 | public void setState(State state) { 118 | this.state = state; 119 | } 120 | 121 | public Api getApi() { 122 | return api; 123 | } 124 | 125 | public void setApi(Api api) { 126 | this.api = api; 127 | } 128 | 129 | public DownloadCallback getCallback() { 130 | return callback; 131 | } 132 | 133 | public void setCallback(DownloadCallback callback) { 134 | this.callback = callback; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/observer/HttpObserver.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.observer; 2 | 3 | 4 | import android.text.TextUtils; 5 | 6 | import com.r.http.cn.cancel.RequestCancel; 7 | import com.r.http.cn.cancel.RequestManagerImpl; 8 | 9 | import io.reactivex.Observer; 10 | import io.reactivex.annotations.NonNull; 11 | import io.reactivex.disposables.Disposable; 12 | 13 | 14 | /** 15 | * 适用Retrofit网络请求Observer(监听者) 16 | * 备注: 17 | * 1.重写onSubscribe,添加请求标识 18 | * 2.重写onError,移除请求 19 | * 4.重写cancel,取消请求 20 | * 3.重写onNext,移除请求 21 | * 22 | * @author ZhongDaFeng 23 | */ 24 | public abstract class HttpObserver implements Observer, RequestCancel { 25 | /*请求标识*/ 26 | private String mTag; 27 | 28 | @Override 29 | public void onError(Throwable e) { 30 | e.printStackTrace(); 31 | if (!TextUtils.isEmpty(mTag)) { 32 | RequestManagerImpl.getInstance().remove(mTag); 33 | } 34 | } 35 | 36 | @Override 37 | public void onComplete() { 38 | /** 39 | * 由于LifecycleProvider取消监听直接截断事件发送,但是必定回调onComplete() 40 | * 因此在这里判断请求是否被取消,如果到这里还未被取消,说明是LifecycleProvider导致的取消请求,回调onCancel逻辑 41 | * 备注: 42 | * 1.子类重写此方法时需要调用super 43 | * 2.多个请求复用一个监听者HttpObserver时,tag会被覆盖,取消回调会有误 44 | */ 45 | if (!RequestManagerImpl.getInstance().isDisposed(mTag)) { 46 | cancel(); 47 | } 48 | } 49 | 50 | @Override 51 | public void onNext(@NonNull T value) { 52 | if (!TextUtils.isEmpty(mTag)) { 53 | RequestManagerImpl.getInstance().remove(mTag); 54 | } 55 | } 56 | 57 | @Override 58 | public void onSubscribe(@NonNull Disposable d) { 59 | if (!TextUtils.isEmpty(mTag)) { 60 | RequestManagerImpl.getInstance().add(mTag, d); 61 | } 62 | } 63 | 64 | /** 65 | * 手动取消请求 66 | */ 67 | @Override 68 | public void cancel() { 69 | if (!TextUtils.isEmpty(mTag)) { 70 | RequestManagerImpl.getInstance().cancel(mTag); 71 | } 72 | } 73 | 74 | /** 75 | * 是否已经处理 76 | * 77 | * @author ZhongDaFeng 78 | */ 79 | public boolean isDisposed() { 80 | if (TextUtils.isEmpty(mTag)) { 81 | return true; 82 | } 83 | return RequestManagerImpl.getInstance().isDisposed(mTag); 84 | } 85 | 86 | /** 87 | * 设置标识请求的TAG 88 | * 89 | * @param tag 90 | */ 91 | public void setTag(String tag) { 92 | this.mTag = tag; 93 | } 94 | 95 | 96 | } 97 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/retrofit/Method.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.retrofit; 2 | 3 | /** 4 | * Http请求方式 5 | * 6 | * @author ZhongDaFeng 7 | */ 8 | public enum Method { 9 | GET, 10 | POST, 11 | DELETE, 12 | PUT 13 | } 14 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/utils/ComputeUtils.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.utils; 2 | 3 | import android.text.TextUtils; 4 | 5 | import java.io.File; 6 | 7 | /** 8 | * 计算工具类 9 | * 10 | * @author ZhongDaFeng 11 | */ 12 | public class ComputeUtils { 13 | 14 | /** 15 | * 计算进度值 16 | * 17 | * @param current 18 | * @param total 19 | * @return 20 | */ 21 | public static float getProgress(long current, long total) { 22 | float progress = (float) current / (float) total; 23 | return progress; 24 | } 25 | 26 | /** 27 | * 文件是否存在 28 | * 29 | * @param fileUrl 文件路径 30 | * @return 31 | */ 32 | public static boolean isFileExists(String fileUrl) { 33 | boolean flag = false; 34 | File file = new File(fileUrl); 35 | if (file.exists() && file.isFile()) { 36 | flag = true; 37 | } 38 | return flag; 39 | } 40 | 41 | /** 42 | * 删除文件 43 | * 44 | * @param filePath 45 | * @return 46 | */ 47 | public static boolean deleteFile(String filePath) { 48 | if (TextUtils.isEmpty(filePath)) return false; 49 | 50 | File file = new File(filePath); 51 | if (file.exists() && file.isFile()) { 52 | if (file.delete()) { 53 | System.out.println("删除单个文件" + filePath + "成功!"); 54 | return true; 55 | } else { 56 | System.out.println("删除单个文件" + filePath + "失败!"); 57 | return false; 58 | } 59 | } else { 60 | System.out.println("删除单个文件失败:" + filePath + "不存在!"); 61 | return false; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/utils/DBHelper.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.utils; 2 | 3 | import android.content.Context; 4 | 5 | import com.litesuits.orm.LiteOrm; 6 | import com.litesuits.orm.db.DataBaseConfig; 7 | import com.r.http.cn.RHttp; 8 | 9 | import java.util.ArrayList; 10 | 11 | /** 12 | * 数据库辅助类 13 | * 14 | * @author ZhongDaFeng 15 | * @https://github.com/litesuits/android-lite-orm 16 | */ 17 | public class DBHelper { 18 | 19 | /*数据库名称*/ 20 | private final String DB_NAME = "com-r-mvp-cn.db"; 21 | private final int DB_VERSION = 1; 22 | private static DBHelper instance; 23 | private static LiteOrm db; 24 | private Context context; 25 | 26 | private DBHelper() { 27 | if (RHttp.Configure.get().getContext() == null) { 28 | throw new NullPointerException("RHttp not init!"); 29 | } 30 | context = RHttp.Configure.get().getContext(); 31 | initDB(context); 32 | } 33 | 34 | public static DBHelper get() { 35 | if (instance == null) { 36 | synchronized (DBHelper.class) { 37 | if (instance == null) { 38 | instance = new DBHelper(); 39 | } 40 | } 41 | } 42 | return instance; 43 | } 44 | 45 | /** 46 | * 初始化数据库 47 | * 48 | * @param context 49 | */ 50 | private void initDB(Context context) { 51 | if (db == null) { 52 | DataBaseConfig config = new DataBaseConfig(context, DB_NAME); 53 | config.debugged = RHttp.Configure.get().isShowLog(); // open the log 54 | config.dbVersion = DB_VERSION; // set database version 55 | config.onUpdateListener = null; // set database update listener 56 | db = LiteOrm.newSingleInstance(config); 57 | } 58 | } 59 | 60 | /** 61 | * 插入或者更新对象 62 | * 备注:有则更新,无则插入 63 | * 64 | * @param object 65 | * @return 66 | */ 67 | public long insertOrUpdate(Object object) { 68 | long count = 0; 69 | if (db != null) { 70 | count = db.save(object); 71 | } 72 | return count; 73 | } 74 | 75 | /** 76 | * 删除对象 77 | * 78 | * @param var1 79 | * @return 80 | */ 81 | public int delete(Object var1) { 82 | int count = 0; 83 | if (db != null) { 84 | count = db.delete(var1); 85 | LogUtils.e("count======" + count); 86 | } 87 | return count; 88 | } 89 | 90 | /** 91 | * 查询数据总数 92 | * 93 | * @param var1 94 | * @param 95 | * @return 96 | */ 97 | public long queryCount(Class var1) { 98 | long count = 0; 99 | if (db != null) { 100 | count = db.queryCount(var1); 101 | } 102 | return count; 103 | } 104 | 105 | /** 106 | * 查询列表 107 | * 108 | * @param var1 109 | * @param 110 | * @return 111 | */ 112 | public ArrayList query(Class var1) { 113 | ArrayList list = new ArrayList<>(); 114 | if (db != null) { 115 | list = db.query(var1); 116 | } 117 | return list; 118 | } 119 | 120 | /** 121 | * 根据ID查询数据 122 | * 123 | * @param var1 124 | * @param var2 125 | * @param 126 | * @return 127 | */ 128 | public T queryById(long var1, Class var2) { 129 | T t = null; 130 | if (db != null) { 131 | t = db.queryById(var1, var2); 132 | } 133 | return t; 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/utils/LogUtils.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.utils; 2 | 3 | import android.util.Log; 4 | 5 | import com.r.http.cn.RHttp; 6 | 7 | /** 8 | * LOG工具类 9 | * 10 | * @author ZhongDaFeng 11 | */ 12 | public class LogUtils { 13 | 14 | private static final String TAG = "RHttp"; 15 | private static boolean allowD = true; 16 | private static boolean allowE = true; 17 | private static boolean allowI = true; 18 | private static boolean allowV = true; 19 | private static boolean allowW = true; 20 | 21 | static { 22 | allowD = allowE = allowI = allowV = allowW = RHttp.Configure.get().isShowLog(); 23 | } 24 | 25 | private LogUtils() { 26 | } 27 | 28 | /** 29 | * 开启Log 30 | * 31 | * @author ZhongDaFeng 32 | */ 33 | public static void openLog(boolean flag) { 34 | allowD = flag; 35 | allowE = flag; 36 | allowI = flag; 37 | allowV = flag; 38 | allowW = flag; 39 | } 40 | 41 | public static void d(String content) { 42 | if (!allowD) 43 | return; 44 | Log.d(TAG, content); 45 | } 46 | 47 | public static void e(String content) { 48 | if (!allowE) 49 | return; 50 | Log.e(TAG, content); 51 | } 52 | 53 | public static void i(String content) { 54 | if (!allowI) 55 | return; 56 | Log.i(TAG, content); 57 | } 58 | 59 | public static void v(String content) { 60 | if (!allowV) 61 | return; 62 | Log.v(TAG, content); 63 | } 64 | 65 | public static void w(String content) { 66 | if (!allowW) 67 | return; 68 | Log.w(TAG, content); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/utils/RequestUtils.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.utils; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.net.URLEncoder; 5 | import java.util.TreeMap; 6 | 7 | /** 8 | * 请求工具类 9 | * 10 | * @author ZhongDaFeng 11 | */ 12 | public class RequestUtils { 13 | 14 | private static RequestUtils instance = null; 15 | 16 | private RequestUtils() { 17 | } 18 | 19 | public static RequestUtils get() { 20 | if (instance == null) { 21 | synchronized (RequestUtils.class) { 22 | if (instance == null) { 23 | instance = new RequestUtils(); 24 | } 25 | } 26 | } 27 | return instance; 28 | } 29 | 30 | 31 | /** 32 | * 获取BaseUrl 33 | * 备注:根据完整URL获取BasUrl 34 | * 35 | * @param url 36 | * @return 37 | */ 38 | public static String getBasUrl(String url) { 39 | String head = ""; 40 | int index = url.indexOf("://"); 41 | if (index != -1) { 42 | head = url.substring(0, index + 3); 43 | url = url.substring(index + 3); 44 | } 45 | index = url.indexOf("/"); 46 | if (index != -1) { 47 | url = url.substring(0, index + 1); 48 | } 49 | return head + url; 50 | } 51 | 52 | 53 | /** 54 | * 获取 encode 后 Header 值 55 | * 备注: OkHttp Header 中的 value 不支持 null, \n 和 中文 等特殊字符 56 | * 后台解析中文 Header 值需要decode(这个后台处理,前端不用理会) 57 | * 58 | * @param value 59 | * @return 60 | */ 61 | public static Object getHeaderValueEncoded(Object value) { 62 | if (value == null) return "null"; 63 | if (value instanceof String) { 64 | String strValue = ((String) value).replace("\n", "");//换行符 65 | for (int i = 0, length = strValue.length(); i < length; i++) { 66 | char c = strValue.charAt(i); 67 | if (c <= '\u001f' || c >= '\u007f') { 68 | try { 69 | return URLEncoder.encode(strValue, "UTF-8");//中文处理 70 | } catch (UnsupportedEncodingException e) { 71 | e.printStackTrace(); 72 | return ""; 73 | } 74 | } 75 | } 76 | return strValue; 77 | } else { 78 | return value; 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/utils/ResponseUtils.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.utils; 2 | 3 | import com.r.http.cn.model.Download; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.io.RandomAccessFile; 9 | import java.nio.MappedByteBuffer; 10 | import java.nio.channels.FileChannel; 11 | 12 | import okhttp3.ResponseBody; 13 | 14 | /** 15 | * 响应工具类 16 | * 17 | * @author ZhongDaFeng 18 | */ 19 | public class ResponseUtils { 20 | 21 | 22 | private static ResponseUtils instance = null; 23 | 24 | private ResponseUtils() { 25 | } 26 | 27 | public static ResponseUtils get() { 28 | if (instance == null) { 29 | synchronized (ResponseUtils.class) { 30 | if (instance == null) { 31 | instance = new ResponseUtils(); 32 | } 33 | } 34 | } 35 | return instance; 36 | } 37 | 38 | 39 | /** 40 | * 下载文件到本地 41 | * 42 | * @param responseBody 响应体 43 | * @param file 目标文件 44 | * @param download 下载实体类 45 | */ 46 | public void download2LocalFile(ResponseBody responseBody, File file, Download download) throws IOException { 47 | try { 48 | RandomAccessFile randomAccessFile = null; 49 | FileChannel channelOut = null; 50 | InputStream inputStream = null; 51 | try { 52 | //创建文件夹 53 | if (!file.getParentFile().exists()) { 54 | file.getParentFile().mkdirs(); 55 | } 56 | //初始化 57 | inputStream = responseBody.byteStream(); 58 | randomAccessFile = new RandomAccessFile(file, "rwd"); 59 | channelOut = randomAccessFile.getChannel(); 60 | //总长度 61 | long allLength = download.getTotalSize() == 0 ? responseBody.contentLength() : download.getCurrentSize() + responseBody.contentLength(); 62 | 63 | MappedByteBuffer mappedBuffer = channelOut.map(FileChannel.MapMode.READ_WRITE, download.getCurrentSize(), allLength - download.getCurrentSize()); 64 | 65 | byte[] buffer = new byte[1024 * 4]; 66 | int length; 67 | while ((length = inputStream.read(buffer)) != -1) { 68 | mappedBuffer.put(buffer, 0, length); 69 | } 70 | } catch (IOException e) { 71 | throw e; 72 | } finally { 73 | if (inputStream != null) { 74 | inputStream.close(); 75 | } 76 | if (channelOut != null) { 77 | channelOut.close(); 78 | } 79 | if (randomAccessFile != null) { 80 | randomAccessFile.close(); 81 | } 82 | } 83 | } catch (IOException e) { 84 | throw e; 85 | } 86 | } 87 | 88 | 89 | } 90 | -------------------------------------------------------------------------------- /RHttp/src/main/java/com/r/http/cn/utils/ThreadUtils.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn.utils; 2 | 3 | import android.os.Looper; 4 | 5 | /** 6 | * 线程工具类 7 | * 8 | * @author ZhongDaFeng 9 | */ 10 | public class ThreadUtils { 11 | /** 12 | * 是否主线程 13 | * 14 | * @return 15 | */ 16 | public static boolean isMainThread() { 17 | return Looper.getMainLooper().getThread().getId() == Thread.currentThread().getId(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /RHttp/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /RHttp/src/test/java/com/r/http/cn/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.r.http.cn; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/rx/mvp/cn/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.rx.mvp.cn", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 34 | 37 | 40 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.base; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.os.Bundle; 6 | import android.support.annotation.NonNull; 7 | 8 | import com.r.mvp.cn.MvpAppCompatActivity; 9 | import com.r.mvp.cn.root.IMvpPresenter; 10 | import com.rx.mvp.cn.manager.ActivityStackManager; 11 | import com.rx.mvp.cn.utils.ToastUtils; 12 | import com.rx.mvp.cn.widget.RLoadingDialog; 13 | 14 | import java.util.List; 15 | 16 | import butterknife.ButterKnife; 17 | import butterknife.Unbinder; 18 | import pub.devrel.easypermissions.EasyPermissions; 19 | 20 | 21 | /** 22 | * 基类Activity 23 | * 备注:所有的Activity都继承自此Activity 24 | * 1.规范团队开发 25 | * 2.统一处理Activity所需配置,初始化 26 | * 27 | * @author ZhongDaFeng 28 | */ 29 | public abstract class BaseActivity extends MvpAppCompatActivity implements EasyPermissions.PermissionCallbacks { 30 | 31 | protected Context mContext; 32 | protected Unbinder unBinder; 33 | protected RLoadingDialog mLoadingDialog; 34 | 35 | @Override 36 | protected void onCreate(Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | ActivityStackManager.getManager().push(this); 39 | setContentView(getContentViewId()); 40 | mContext = this; 41 | unBinder = ButterKnife.bind(this); 42 | mLoadingDialog = new RLoadingDialog(this, true); 43 | initBundleData(); 44 | initView(); 45 | initData(); 46 | } 47 | 48 | @Override 49 | protected void onDestroy() { 50 | super.onDestroy(); 51 | //移除view绑定 52 | if (unBinder != null) { 53 | unBinder.unbind(); 54 | } 55 | ActivityStackManager.getManager().remove(this); 56 | } 57 | 58 | @Override 59 | public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { 60 | EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); 61 | } 62 | 63 | @Override 64 | public void onPermissionsGranted(int requestCode, List list) { 65 | } 66 | 67 | @Override 68 | public void onPermissionsDenied(int requestCode, List list) { 69 | } 70 | 71 | /** 72 | * 获取显示view的xml文件ID 73 | */ 74 | protected abstract int getContentViewId(); 75 | 76 | 77 | /** 78 | * 获取上一个界面传送过来的数据 79 | */ 80 | protected abstract void initBundleData(); 81 | 82 | /** 83 | * 初始化view 84 | */ 85 | protected abstract void initView(); 86 | 87 | /** 88 | * 初始化Data 89 | */ 90 | protected abstract void initData(); 91 | 92 | 93 | /**------------MVP通用方法避免每个组件都要实现--------------**/ 94 | 95 | /** 96 | * Presenter绑定入口,组件使用Presenter时存入具体值 97 | */ 98 | @Override 99 | protected IMvpPresenter[] getPresenterArray() { 100 | return new IMvpPresenter[0]; 101 | } 102 | 103 | /**------------MVP->View层方法预实现{@link com.r.mvp.cn.MvpView}--------------**/ 104 | 105 | /** 106 | * 展示吐司 107 | */ 108 | public void showToast(@NonNull String msg) { 109 | ToastUtils.showToast(this, msg); 110 | } 111 | 112 | /** 113 | * 显示进度View 114 | */ 115 | public void showProgressView() { 116 | mLoadingDialog.show(); 117 | } 118 | 119 | /** 120 | * 隐藏进度View 121 | */ 122 | public void dismissProgressView() { 123 | mLoadingDialog.dismiss(); 124 | } 125 | 126 | /** 127 | * 获取Activity实例 128 | */ 129 | public Activity getActivity() { 130 | return this; 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/base/BaseBiz.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.base; 2 | 3 | import java.util.TreeMap; 4 | 5 | /** 6 | * 基础业务类 7 | * 8 | * @author ZhongDaFeng 9 | */ 10 | public class BaseBiz { 11 | 12 | 13 | public final String appKey = "1889b37351288"; 14 | public final String k_key = "key"; 15 | 16 | /** 17 | * 获取基础request参数 18 | */ 19 | public TreeMap getBaseRequest() { 20 | TreeMap map = new TreeMap<>(); 21 | map.put(k_key, appKey); 22 | return map; 23 | } 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/base/BaseFragment.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.base; 2 | 3 | 4 | import android.content.Context; 5 | import android.os.Bundle; 6 | import android.support.annotation.NonNull; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | 11 | import com.r.mvp.cn.MvpFragment; 12 | import com.r.mvp.cn.root.IMvpPresenter; 13 | import com.rx.mvp.cn.utils.ToastUtils; 14 | import com.rx.mvp.cn.widget.RLoadingDialog; 15 | 16 | import java.util.List; 17 | 18 | import butterknife.ButterKnife; 19 | import butterknife.Unbinder; 20 | import pub.devrel.easypermissions.EasyPermissions; 21 | 22 | 23 | /** 24 | * 基类Fragment 25 | * 备注:所有的Fragment都继承自此Fragment 26 | * 1.规范团队开发 27 | * 2.统一处理Fragment所需配置,初始化 28 | * 29 | * @author ZhongDaFeng 30 | */ 31 | public abstract class BaseFragment extends MvpFragment implements EasyPermissions.PermissionCallbacks { 32 | 33 | protected Context mContext; 34 | protected Unbinder unBinder; 35 | protected View mView; 36 | protected RLoadingDialog mLoadingDialog; 37 | 38 | @Override 39 | public void onCreate(Bundle savedInstanceState) { 40 | super.onCreate(savedInstanceState); 41 | mContext = getActivity(); 42 | if (mContext == null) return; 43 | mView = getContentView(); 44 | unBinder = ButterKnife.bind(this, mView); 45 | mLoadingDialog = new RLoadingDialog(getActivity(), true); 46 | initBundleData(); 47 | initView(); 48 | initData(); 49 | } 50 | 51 | @Override 52 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 53 | if (mView.getParent() != null) { 54 | ((ViewGroup) mView.getParent()).removeView(mView); 55 | } 56 | return mView; 57 | } 58 | 59 | @Override 60 | public void onDestroy() { 61 | super.onDestroy(); 62 | //移除view绑定 63 | if (unBinder != null) { 64 | unBinder.unbind(); 65 | } 66 | } 67 | 68 | /** 69 | * 是否已经创建 70 | * 71 | * @return 72 | */ 73 | public boolean isCreated() { 74 | return mView != null; 75 | } 76 | 77 | /** 78 | * 获取显示view 79 | */ 80 | protected abstract View getContentView(); 81 | 82 | /** 83 | * 获取上一个界面传送过来的数据 84 | */ 85 | protected abstract void initBundleData(); 86 | 87 | /** 88 | * 初始化view 89 | */ 90 | protected abstract void initView(); 91 | 92 | /** 93 | * 初始化Data 94 | */ 95 | protected abstract void initData(); 96 | 97 | @Override 98 | public void onPermissionsGranted(int requestCode, List list) { 99 | } 100 | 101 | @Override 102 | public void onPermissionsDenied(int requestCode, List list) { 103 | } 104 | 105 | 106 | /**------------MVP通用方法避免每个组件都要实现--------------**/ 107 | 108 | /** 109 | * Presenter绑定入口,组件使用Presenter时存入具体值 110 | */ 111 | @Override 112 | protected IMvpPresenter[] getPresenterArray() { 113 | return new IMvpPresenter[0]; 114 | } 115 | 116 | /**------------MVP->View层方法预实现{@link com.r.mvp.cn.MvpView}--------------**/ 117 | 118 | /** 119 | * 展示吐司 120 | */ 121 | public void showToast(@NonNull String msg) { 122 | ToastUtils.showToast(getActivity(), msg); 123 | } 124 | 125 | /** 126 | * 显示进度View 127 | */ 128 | public void showProgressView() { 129 | mLoadingDialog.show(); 130 | } 131 | 132 | /** 133 | * 隐藏进度View 134 | */ 135 | public void dismissProgressView() { 136 | mLoadingDialog.dismiss(); 137 | } 138 | 139 | /** 140 | * 获取Activity实例(Fragment本身存在getActivity取巧不用实现) 141 | */ 142 | /*public Activity getActivity() { 143 | return getActivity(); 144 | }*/ 145 | 146 | } 147 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/base/BaseFragmentActivity.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.base; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.os.Bundle; 6 | import android.support.annotation.NonNull; 7 | 8 | import com.r.mvp.cn.MvpFragmentActivity; 9 | import com.r.mvp.cn.root.IMvpPresenter; 10 | import com.rx.mvp.cn.manager.ActivityStackManager; 11 | import com.rx.mvp.cn.utils.ToastUtils; 12 | import com.rx.mvp.cn.widget.RLoadingDialog; 13 | 14 | import java.util.List; 15 | 16 | import butterknife.ButterKnife; 17 | import butterknife.Unbinder; 18 | import pub.devrel.easypermissions.EasyPermissions; 19 | 20 | /** 21 | * 基类Activity 22 | * 备注:所有的Activity都继承自此Activity 23 | * 1.规范团队开发 24 | * 2.统一处理Activity所需配置,初始化 25 | * 26 | * @author ZhongDaFeng 27 | */ 28 | public abstract class BaseFragmentActivity extends MvpFragmentActivity implements EasyPermissions.PermissionCallbacks { 29 | 30 | protected Context mContext; 31 | protected Unbinder unBinder; 32 | protected RLoadingDialog mLoadingDialog; 33 | 34 | @Override 35 | protected void onCreate(Bundle savedInstanceState) { 36 | super.onCreate(savedInstanceState); 37 | ActivityStackManager.getManager().push(this); 38 | setContentView(getContentViewId()); 39 | mContext = this; 40 | unBinder = ButterKnife.bind(this); 41 | mLoadingDialog = new RLoadingDialog(this, true); 42 | initBundleData(); 43 | initView(); 44 | initData(); 45 | } 46 | 47 | @Override 48 | protected void onDestroy() { 49 | super.onDestroy(); 50 | //移除view绑定 51 | if (unBinder != null) { 52 | unBinder.unbind(); 53 | } 54 | ActivityStackManager.getManager().remove(this); 55 | } 56 | 57 | @Override 58 | public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { 59 | EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); 60 | } 61 | 62 | @Override 63 | public void onPermissionsGranted(int requestCode, List list) { 64 | } 65 | 66 | @Override 67 | public void onPermissionsDenied(int requestCode, List list) { 68 | } 69 | 70 | /** 71 | * 获取显示view的xml文件ID 72 | */ 73 | protected abstract int getContentViewId(); 74 | 75 | 76 | /** 77 | * 获取上一个界面传送过来的数据 78 | */ 79 | protected abstract void initBundleData(); 80 | 81 | /** 82 | * 初始化view 83 | */ 84 | protected abstract void initView(); 85 | 86 | /** 87 | * 初始化Data 88 | */ 89 | protected abstract void initData(); 90 | 91 | 92 | /**------------MVP通用方法避免每个组件都要实现--------------**/ 93 | 94 | /** 95 | * Presenter绑定入口,组件使用Presenter时存入具体值 96 | */ 97 | @Override 98 | protected IMvpPresenter[] getPresenterArray() { 99 | return new IMvpPresenter[0]; 100 | } 101 | 102 | /**------------MVP->View层方法预实现{@link com.r.mvp.cn.MvpView}--------------**/ 103 | 104 | /** 105 | * 展示吐司 106 | */ 107 | public void showToast(@NonNull String msg) { 108 | ToastUtils.showToast(this, msg); 109 | } 110 | 111 | /** 112 | * 显示进度View 113 | */ 114 | public void showProgressView() { 115 | mLoadingDialog.show(); 116 | } 117 | 118 | /** 119 | * 隐藏进度View 120 | */ 121 | public void dismissProgressView() { 122 | mLoadingDialog.dismiss(); 123 | } 124 | 125 | /** 126 | * 获取Activity实例 127 | */ 128 | public Activity getActivity() { 129 | return this; 130 | } 131 | 132 | } -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/base/BasePagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.base; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentManager; 5 | import android.support.v4.app.FragmentPagerAdapter; 6 | 7 | import java.util.ArrayList; 8 | 9 | 10 | /** 11 | * FragmentPager适配器 12 | * 13 | * @author ZhongDaFeng 14 | */ 15 | public class BasePagerAdapter extends FragmentPagerAdapter { 16 | private ArrayList fragments; 17 | 18 | public BasePagerAdapter(FragmentManager fm, ArrayList fragments) { 19 | super(fm); 20 | this.fragments = fragments; 21 | } 22 | 23 | @Override 24 | public Fragment getItem(int position) { 25 | return fragments.get(position); 26 | } 27 | 28 | @Override 29 | public int getCount() { 30 | return fragments.size(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/base/BizFactory.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.base; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import com.r.mvp.cn.root.IMvpModel; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | /** 11 | * Biz工厂类 12 | * 13 | * @author ZhongDaFeng 14 | */ 15 | public class BizFactory { 16 | 17 | /** 18 | * 全局存储Biz 19 | */ 20 | private static Map modelMap = new HashMap<>(); 21 | 22 | /** 23 | * 获取Biz 24 | * 查询Map中是否存在Biz实例,不存在时动态创建 25 | * 26 | * @param cls 类 27 | * @param model 28 | * @return 29 | */ 30 | public static T getBiz(@NonNull Class cls) { 31 | String className = cls.getName();//类名 32 | T model = (T) modelMap.get(className); 33 | if (model == null) {//不存在 34 | model = getModelReflex(className); 35 | modelMap.put(className, model); 36 | } 37 | return model; 38 | } 39 | 40 | /** 41 | * 反射获取Biz 42 | * 43 | * @param className 包含完整路径的类名称 com.ruffian.cn.UserBiz 44 | * @param 45 | * @return 46 | */ 47 | private static T getModelReflex(@NonNull String className) { 48 | T result = null; 49 | try { 50 | result = (T) Class.forName(className).newInstance(); 51 | } catch (Exception e) { 52 | e.printStackTrace(); 53 | } 54 | return result; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/core/bitmap/ImageLoaderUtils.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.core.bitmap; 2 | 3 | import android.content.Context; 4 | import android.widget.ImageView; 5 | 6 | import com.bumptech.glide.Glide; 7 | import com.rx.mvp.cn.R; 8 | 9 | 10 | /** 11 | * ImageLoaderUtils 12 | * 13 | * @author ZhongDaFeng 14 | */ 15 | public class ImageLoaderUtils { 16 | 17 | public static void load(Context context, String url, ImageView imageView) { 18 | if (context != null) { 19 | Glide.with(context).load(url).placeholder(R.mipmap.ic_launcher).dontAnimate().error(R.mipmap.ic_launcher).into(imageView); 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/core/net/http/RHttpCallback.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.core.net.http; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.JsonElement; 5 | import com.r.http.cn.callback.HttpCallback; 6 | import com.rx.mvp.cn.model.Response; 7 | 8 | /** 9 | * 根据业务进一步封装 10 | * 11 | * @author ZhongDaFeng 12 | */ 13 | public abstract class RHttpCallback extends HttpCallback { 14 | 15 | private Response response; 16 | 17 | @Override 18 | public T onConvert(String data) { 19 | /** 20 | * 接口响应数据格式如@Response 21 | * 根据业务封装: 22 | * 1. response.isSuccess() (code==0) 业务逻辑成功回调convert()=>onSuccess(),否则失败回调onError() 23 | * 2.统一处理接口逻辑 例如:code==101 token过期等等 24 | */ 25 | T t = null; 26 | response = new Gson().fromJson(data, Response.class); 27 | int code = response.getCode(); 28 | String msg = response.getMsg(); 29 | JsonElement result = response.getResult(); 30 | switch (code) { 31 | case 101://token过期,跳转登录页面重新登录(示例) 32 | break; 33 | case 102://系统公告(示例) 34 | break; 35 | default: 36 | if (response.isSuccess()) {//与服务器约定成功逻辑 37 | t = convert(result); 38 | } else {//统一为错误处理 39 | onError(code, msg); 40 | } 41 | break; 42 | } 43 | return t; 44 | } 45 | 46 | /** 47 | * 数据转换/解析 48 | * 49 | * @param data 50 | * @return 51 | */ 52 | public abstract T convert(JsonElement data); 53 | 54 | /** 55 | * 成功回调 56 | * 57 | * @param value 58 | */ 59 | public abstract void onSuccess(T value); 60 | 61 | /** 62 | * 失败回调 63 | * 64 | * @param code 65 | * @param desc 66 | */ 67 | public abstract void onError(int code, String desc); 68 | 69 | /** 70 | * 取消回调 71 | */ 72 | public abstract void onCancel(); 73 | 74 | /** 75 | * 业务逻辑是否成功 76 | * 77 | * @return 78 | */ 79 | @Override 80 | public boolean isBusinessOk() { 81 | return response.isSuccess(); 82 | } 83 | 84 | 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/core/net/http/RUploadCallback.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.core.net.http; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.JsonElement; 5 | import com.r.http.cn.callback.UploadCallback; 6 | import com.rx.mvp.cn.model.Response; 7 | 8 | import java.io.File; 9 | 10 | /** 11 | * 根据业务进一步封装 12 | * 13 | * @author ZhongDaFeng 14 | */ 15 | public abstract class RUploadCallback extends UploadCallback { 16 | 17 | private Response response; 18 | 19 | @Override 20 | public T onConvert(String data) { 21 | /** 22 | * 接口响应数据格式如@Response 23 | * 将result转化给success 24 | * 这里处理通过错误 25 | */ 26 | T t = null; 27 | response = new Gson().fromJson(data, Response.class); 28 | int code = response.getCode(); 29 | String msg = response.getMsg(); 30 | switch (code) { 31 | case 101://token过期,跳转登录页面重新登录(示例) 32 | break; 33 | case 102://系统公告(示例) 34 | break; 35 | default: 36 | if (response.isSuccess()) {//与服务器约定成功逻辑 37 | t = convert(response.getResult()); 38 | } else {//统一为错误处理 39 | onError(code, msg); 40 | } 41 | break; 42 | } 43 | return t; 44 | } 45 | 46 | /** 47 | * 数据转换/解析 48 | * 49 | * @param data 50 | * @return 51 | */ 52 | public abstract T convert(JsonElement data); 53 | 54 | /** 55 | * 上传回调 56 | * 57 | * @param file 58 | * @param currentSize 59 | * @param totalSize 60 | * @param progress 61 | * @param currentIndex 62 | * @param totalFile 63 | */ 64 | public abstract void onProgress(File file, long currentSize, long totalSize, float progress, int currentIndex, int totalFile); 65 | 66 | 67 | /** 68 | * 成功回调 69 | * 70 | * @param value 71 | */ 72 | public abstract void onSuccess(T value); 73 | 74 | /** 75 | * 失败回调 76 | * 77 | * @param code 78 | * @param desc 79 | */ 80 | public abstract void onError(int code, String desc); 81 | 82 | /** 83 | * 取消回调 84 | */ 85 | public abstract void onCancel(); 86 | 87 | /** 88 | * 业务逻辑是否成功 89 | * 90 | * @return 91 | */ 92 | @Override 93 | public boolean isBusinessOk() { 94 | return response.isSuccess(); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/manager/ActivityStackManager.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.manager; 2 | 3 | import android.app.Activity; 4 | import android.app.ActivityManager; 5 | import android.app.NotificationManager; 6 | import android.content.Context; 7 | 8 | import java.util.Stack; 9 | 10 | 11 | /** 12 | * Activity栈管理 13 | * 14 | * @author ZhongDaFeng 15 | */ 16 | public class ActivityStackManager { 17 | 18 | private static ActivityStackManager instance = null; 19 | private static Stack activityStack;// 栈 20 | 21 | /** 22 | * 私有构造 23 | */ 24 | private ActivityStackManager() { 25 | activityStack = new Stack(); 26 | } 27 | 28 | /** 29 | * 单例实例 30 | * 31 | * @return 32 | */ 33 | public static ActivityStackManager getManager() { 34 | if (instance == null) { 35 | synchronized (ActivityStackManager.class) { 36 | if (instance == null) { 37 | instance = new ActivityStackManager(); 38 | } 39 | } 40 | } 41 | return instance; 42 | } 43 | 44 | /** 45 | * 压栈 46 | * 47 | * @param activity 48 | */ 49 | public void push(Activity activity) { 50 | activityStack.push(activity); 51 | } 52 | 53 | /** 54 | * 出栈 55 | * 56 | * @return 57 | */ 58 | public Activity pop() { 59 | if (activityStack.isEmpty()) 60 | return null; 61 | return activityStack.pop(); 62 | } 63 | 64 | /** 65 | * 栈顶 66 | * 67 | * @return 68 | */ 69 | public Activity peek() { 70 | if (activityStack.isEmpty()) 71 | return null; 72 | return activityStack.peek(); 73 | } 74 | 75 | /** 76 | * 移除 77 | * 78 | * @param activity 79 | */ 80 | public void remove(Activity activity) { 81 | if (activityStack.size() > 0 && activity == activityStack.peek()) 82 | activityStack.pop(); 83 | else 84 | activityStack.remove(activity); 85 | } 86 | 87 | /** 88 | * 是否存在栈 89 | * 90 | * @param activity 91 | * @return 92 | */ 93 | public boolean contains(Activity activity) { 94 | return activityStack.contains(activity); 95 | } 96 | 97 | /** 98 | * 结束所有Activity 99 | */ 100 | public void finishAllActivity() { 101 | while (!activityStack.isEmpty()) { 102 | activityStack.pop().finish(); 103 | } 104 | } 105 | 106 | /** 107 | * 退出应用程序 108 | * 109 | * @param context 110 | */ 111 | public void exitApp(Context context) { 112 | try { 113 | finishAllActivity(); 114 | ActivityManager activityManager = (ActivityManager) context 115 | .getSystemService(Context.ACTIVITY_SERVICE); 116 | activityManager.restartPackage(context.getPackageName()); 117 | //清除通知栏 118 | NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 119 | notificationManager.cancelAll(); 120 | android.os.Process.killProcess(android.os.Process.myPid()); 121 | } catch (Exception e) { 122 | } 123 | } 124 | } -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/GlobalConstants.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.model; 2 | 3 | /** 4 | * 全局常量 5 | * 6 | * @author ZhongDaFeng 7 | */ 8 | public class GlobalConstants { 9 | 10 | //登录Action 11 | public static final String ACTION_LOGIN = "action_login"; 12 | //号码查询Action 13 | public static final String ACTION_QUERY_PHONE = "action_query_phone"; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.model; 2 | 3 | import android.Manifest; 4 | import android.content.Intent; 5 | import android.view.View; 6 | 7 | import com.r.mvp.cn.root.IMvpPresenter; 8 | import com.rx.mvp.cn.R; 9 | import com.rx.mvp.cn.base.BaseActivity; 10 | import com.rx.mvp.cn.model.account.activity.LoginActivity; 11 | import com.rx.mvp.cn.model.load.download.DownloadActivity; 12 | import com.rx.mvp.cn.model.load.upload.UploadActivity; 13 | import com.rx.mvp.cn.model.multiple.MultipleActivity; 14 | import com.rx.mvp.cn.model.phone.activity.PhoneAddressActivity; 15 | import com.rx.mvp.cn.utils.LogUtils; 16 | 17 | import java.util.List; 18 | 19 | import butterknife.OnClick; 20 | import pub.devrel.easypermissions.EasyPermissions; 21 | 22 | public class MainActivity extends BaseActivity { 23 | 24 | @Override 25 | protected int getContentViewId() { 26 | return R.layout.activity_main; 27 | } 28 | 29 | @Override 30 | protected void initBundleData() { 31 | 32 | } 33 | 34 | @Override 35 | protected void initView() { 36 | 37 | } 38 | 39 | @Override 40 | protected void initData() { 41 | String[] per = {Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}; 42 | if (!EasyPermissions.hasPermissions(this, per)) { 43 | EasyPermissions.requestPermissions(this, "申请读写权限", 101, per); 44 | } 45 | } 46 | 47 | @OnClick({R.id.login, R.id.phone_address, R.id.multiple, R.id.upload, R.id.download}) 48 | public void onClick(View v) { 49 | Intent intent; 50 | switch (v.getId()) { 51 | case R.id.login: 52 | intent = new Intent(this, LoginActivity.class); 53 | startActivity(intent); 54 | break; 55 | case R.id.phone_address: 56 | intent = new Intent(this, PhoneAddressActivity.class); 57 | startActivity(intent); 58 | break; 59 | case R.id.multiple: 60 | intent = new Intent(this, MultipleActivity.class); 61 | startActivity(intent); 62 | break; 63 | case R.id.upload: 64 | intent = new Intent(this, UploadActivity.class); 65 | startActivity(intent); 66 | break; 67 | case R.id.download: 68 | intent = new Intent(this, DownloadActivity.class); 69 | startActivity(intent); 70 | break; 71 | } 72 | 73 | } 74 | 75 | @Override 76 | public void onPermissionsDenied(int requestCode, List list) { 77 | LogUtils.e("申请权限成功"); 78 | } 79 | 80 | @Override 81 | public void onPermissionsGranted(int requestCode, List list) { 82 | LogUtils.e("申请权限失败"); 83 | } 84 | 85 | @Override 86 | protected IMvpPresenter[] getPresenterArray() { 87 | return new IMvpPresenter[0]; 88 | } 89 | } 90 | 91 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/RApp.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.model; 2 | 3 | import android.app.Application; 4 | 5 | import com.r.http.cn.RHttp; 6 | 7 | /** 8 | * @author ZhongDaFeng 9 | * @date 2018/8/20 10 | */ 11 | 12 | public class RApp extends Application { 13 | 14 | /*http请求基础路径*/ 15 | public static final String BASE_API = "http://apicloud.mob.com/"; 16 | 17 | @Override 18 | public void onCreate() { 19 | super.onCreate(); 20 | RHttp.Configure.get() 21 | .baseUrl(BASE_API) //基础URL 22 | .init(this); //初始化 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/Response.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.model; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.JsonElement; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * http响应参数实体类 11 | * 通过Gson解析属性名称需要与服务器返回字段对应,或者使用注解@SerializedName 12 | * 备注:这里与服务器约定返回格式 13 | * 14 | * @author ZhongDaFeng 15 | */ 16 | public class Response implements Serializable { 17 | 18 | /** 19 | * 描述信息 20 | */ 21 | @SerializedName("msg") 22 | private String msg; 23 | 24 | /** 25 | * 状态码 26 | */ 27 | @SerializedName("retCode") 28 | private int code; 29 | 30 | /** 31 | * 数据对象/成功返回对象 32 | */ 33 | @SerializedName("result") 34 | private JsonElement result; 35 | 36 | /** 37 | * 是否成功 38 | * 39 | * @return 40 | */ 41 | public boolean isSuccess() { 42 | return code == 200; 43 | } 44 | 45 | public String toString() { 46 | String response = "[http response]" + "{\"code\": " + code + ",\"msg\":" + msg + ",\"result\":" + new Gson().toJson(result) + "}"; 47 | return response; 48 | } 49 | 50 | 51 | public String getMsg() { 52 | return msg; 53 | } 54 | 55 | public void setMsg(String msg) { 56 | this.msg = msg; 57 | } 58 | 59 | public int getCode() { 60 | return code; 61 | } 62 | 63 | public void setCode(int code) { 64 | this.code = code; 65 | } 66 | 67 | public JsonElement getResult() { 68 | return result; 69 | } 70 | 71 | public void setResult(JsonElement result) { 72 | this.result = result; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/account/activity/LoginActivity.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.model.account.activity; 2 | 3 | import android.app.Activity; 4 | import android.text.TextUtils; 5 | import android.view.View; 6 | import android.widget.EditText; 7 | import android.widget.TextView; 8 | 9 | import com.r.mvp.cn.root.IMvpPresenter; 10 | import com.rx.mvp.cn.R; 11 | import com.rx.mvp.cn.base.BaseActivity; 12 | import com.rx.mvp.cn.model.account.contract.AccountContract; 13 | import com.rx.mvp.cn.model.account.presenter.LoginPresenter; 14 | import com.rx.mvp.cn.utils.ToastUtils; 15 | import com.rx.mvp.cn.widget.RLoadingDialog; 16 | import com.trello.rxlifecycle2.LifecycleProvider; 17 | 18 | import butterknife.BindView; 19 | import butterknife.OnClick; 20 | 21 | /** 22 | * 登录页面MVP示例 23 | * 24 | * @author ZhongDaFeng 25 | */ 26 | public class LoginActivity extends BaseActivity implements AccountContract.ILoginView { 27 | 28 | @BindView(R.id.et_user_name) 29 | EditText etUserName; 30 | @BindView(R.id.et_password) 31 | EditText etPassword; 32 | @BindView(R.id.tv_result) 33 | TextView tvResult; 34 | 35 | private LoginPresenter mLoginPresenter = new LoginPresenter(); 36 | 37 | @Override 38 | protected int getContentViewId() { 39 | return R.layout.activity_login; 40 | } 41 | 42 | @Override 43 | protected void initBundleData() { 44 | } 45 | 46 | @Override 47 | protected void initView() { 48 | mLoadingDialog = new RLoadingDialog(this, true); 49 | } 50 | 51 | @Override 52 | protected void initData() { 53 | //获取缓存数据 54 | mLoginPresenter.getLocalCache(); 55 | } 56 | 57 | @OnClick({R.id.login}) 58 | public void onClick(View v) { 59 | switch (v.getId()) { 60 | case R.id.login: 61 | String userName = etUserName.getText().toString(); 62 | String password = etPassword.getText().toString(); 63 | if (TextUtils.isEmpty(userName) || TextUtils.isEmpty(password)) { 64 | return; 65 | } 66 | //登录 67 | mLoginPresenter.login(userName, password); 68 | break; 69 | } 70 | } 71 | 72 | @Override 73 | protected IMvpPresenter[] getPresenterArray() { 74 | return new IMvpPresenter[]{mLoginPresenter}; 75 | } 76 | 77 | @Override 78 | public LifecycleProvider getRxLifecycle() { 79 | return this; 80 | } 81 | 82 | @Override 83 | public void showResult(String data) { 84 | tvResult.setText(data); 85 | } 86 | 87 | @Override 88 | public void showError(int code, String msg) { 89 | showToast(msg); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/account/biz/UserBiz.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.model.account.biz; 2 | 3 | import com.r.http.cn.RHttp; 4 | import com.r.http.cn.callback.HttpCallback; 5 | import com.rx.mvp.cn.base.BaseBiz; 6 | import com.trello.rxlifecycle2.LifecycleProvider; 7 | 8 | import java.util.TreeMap; 9 | 10 | /** 11 | * 用户相关业务 12 | * 13 | * @author ZhongDaFeng 14 | */ 15 | public class UserBiz extends BaseBiz { 16 | 17 | /** 18 | * 登录API 19 | */ 20 | private final String API_LOGIN = "user/login"; 21 | 22 | /** 23 | * 用户登录 24 | * 25 | * @param userName 26 | * @param password 27 | * @param lifecycle 28 | * @param callback 29 | */ 30 | public void login(String userName, String password, LifecycleProvider lifecycle, HttpCallback callback) { 31 | /** 32 | * 构建请求参数 33 | */ 34 | TreeMap request = new TreeMap<>(); 35 | request.put("username", userName); 36 | request.put("password", password); 37 | request.putAll(getBaseRequest()); 38 | 39 | /** 40 | * 发送请求 41 | */ 42 | RHttp http = new RHttp.Builder() 43 | .post() 44 | .baseUrl("http://apicloud.mob.com/") 45 | .apiUrl(API_LOGIN) 46 | .addParameter(request) 47 | .lifecycle(lifecycle) 48 | .build(); 49 | 50 | http.request(callback); 51 | 52 | } 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/account/contract/AccountContract.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.model.account.contract; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.UiThread; 5 | 6 | import com.r.mvp.cn.MvpView; 7 | import com.r.mvp.cn.model.ModelCallback; 8 | import com.r.mvp.cn.root.IMvpModel; 9 | import com.rx.mvp.cn.model.account.entity.UserBean; 10 | import com.trello.rxlifecycle2.LifecycleProvider; 11 | 12 | /** 13 | * Account业务的Contract(协议) 14 | * 目的:避免mvp架构 view/model 文件过多 15 | * 综合管理某业务的 view/model 接口 16 | * 17 | * @author ZhongDaFeng 18 | */ 19 | public interface AccountContract { 20 | 21 | /*登录模块View接口*/ 22 | interface ILoginView extends MvpView { 23 | 24 | /*登录成功展示结果*/ 25 | @UiThread 26 | void showResult(String data); 27 | 28 | /*登录错误处理逻辑*/ 29 | @UiThread 30 | void showError(int code, String msg); 31 | } 32 | 33 | /*登录模块model接口.此处根据具体项目决定是否需要此接口层*/ 34 | interface LoginModel extends IMvpModel { 35 | /** 36 | * 用户密码登录 37 | * 38 | * @param lifecycle 组件生命周期 39 | * @param modelCallback model回调接口(网络) 40 | */ 41 | void login(final Context context, String userName, String password, LifecycleProvider lifecycle, ModelCallback.Http modelCallback); 42 | 43 | /** 44 | * 获取本地缓存数据 45 | * 46 | * @param modelCallback model回调接口(普通数据) 47 | */ 48 | void getLocalCache(Context context, LifecycleProvider lifecycle, ModelCallback.Data modelCallback); 49 | 50 | /** 51 | * 缓存数据 52 | */ 53 | void saveLocalCache(Context context, UserBean data); 54 | } 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/account/entity/UserBean.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.model.account.entity; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * 用户实体类 9 | * 10 | * @author ZhongDaFeng 11 | */ 12 | 13 | public class UserBean implements Serializable { 14 | //token string 用户登录生成的token 15 | //uid string 用户Id 16 | @SerializedName("token") 17 | private String token; 18 | @SerializedName("uid") 19 | private String uid; 20 | private String time; 21 | 22 | public String getToken() { 23 | return token; 24 | } 25 | 26 | public void setToken(String token) { 27 | this.token = token; 28 | } 29 | 30 | public String getUid() { 31 | return uid; 32 | } 33 | 34 | public void setUid(String uid) { 35 | this.uid = uid; 36 | } 37 | 38 | public String getTime() { 39 | return time == null ? "" : time; 40 | } 41 | 42 | public void setTime(String time) { 43 | this.time = time; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/account/fragment/LoginFragment.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.model.account.fragment; 2 | 3 | import android.text.TextUtils; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.widget.EditText; 7 | import android.widget.TextView; 8 | 9 | import com.r.mvp.cn.root.IMvpPresenter; 10 | import com.rx.mvp.cn.R; 11 | import com.rx.mvp.cn.base.BaseFragment; 12 | import com.rx.mvp.cn.model.account.contract.AccountContract; 13 | import com.rx.mvp.cn.model.account.presenter.LoginPresenter; 14 | import com.rx.mvp.cn.utils.ToastUtils; 15 | import com.rx.mvp.cn.widget.RLoadingDialog; 16 | import com.trello.rxlifecycle2.LifecycleProvider; 17 | 18 | import butterknife.BindView; 19 | import butterknife.OnClick; 20 | 21 | /** 22 | * 登录Fragment 23 | * 24 | * @author ZhongDaFeng 25 | */ 26 | public class LoginFragment extends BaseFragment implements AccountContract.ILoginView { 27 | 28 | @BindView(R.id.et_user_name) 29 | EditText etUserName; 30 | @BindView(R.id.et_password) 31 | EditText etPassword; 32 | @BindView(R.id.tv_result) 33 | TextView tvResult; 34 | 35 | private LoginPresenter mLoginPresenter = new LoginPresenter(); 36 | 37 | @Override 38 | protected View getContentView() { 39 | return LayoutInflater.from(mContext).inflate(R.layout.activity_login, null); 40 | } 41 | 42 | @Override 43 | protected void initBundleData() { 44 | 45 | } 46 | 47 | @Override 48 | protected void initView() { 49 | mLoadingDialog = new RLoadingDialog(mContext, true); 50 | } 51 | 52 | @Override 53 | protected void initData() { 54 | //获取缓存数据 55 | mLoginPresenter.getLocalCache(); 56 | } 57 | 58 | @OnClick({R.id.login}) 59 | public void onClick(View v) { 60 | switch (v.getId()) { 61 | case R.id.login: 62 | String userName = etUserName.getText().toString(); 63 | String password = etPassword.getText().toString(); 64 | if (TextUtils.isEmpty(userName) || TextUtils.isEmpty(password)) { 65 | return; 66 | } 67 | mLoginPresenter.login( userName, password); 68 | break; 69 | } 70 | } 71 | 72 | @Override 73 | protected IMvpPresenter[] getPresenterArray() { 74 | return new IMvpPresenter[]{mLoginPresenter}; 75 | } 76 | 77 | @Override 78 | public LifecycleProvider getRxLifecycle() { 79 | return this; 80 | } 81 | 82 | @Override 83 | public void showResult(String data) { 84 | tvResult.setText(data); 85 | } 86 | 87 | @Override 88 | public void showError(int code, String msg) { 89 | showToast(msg); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/account/model/AccountModel.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.model.account.model; 2 | 3 | import android.content.Context; 4 | 5 | import com.google.gson.Gson; 6 | import com.google.gson.JsonElement; 7 | import com.r.mvp.cn.model.ModelCallback; 8 | import com.rx.mvp.cn.base.BizFactory; 9 | import com.rx.mvp.cn.core.net.http.RHttpCallback; 10 | import com.rx.mvp.cn.model.account.biz.UserBiz; 11 | import com.rx.mvp.cn.model.account.contract.AccountContract; 12 | import com.rx.mvp.cn.model.account.entity.UserBean; 13 | import com.rx.mvp.cn.utils.SpUtils; 14 | import com.trello.rxlifecycle2.LifecycleProvider; 15 | import com.trello.rxlifecycle2.android.ActivityEvent; 16 | 17 | import java.text.SimpleDateFormat; 18 | 19 | import io.reactivex.Observable; 20 | import io.reactivex.ObservableEmitter; 21 | import io.reactivex.ObservableOnSubscribe; 22 | import io.reactivex.Observer; 23 | import io.reactivex.android.schedulers.AndroidSchedulers; 24 | import io.reactivex.annotations.NonNull; 25 | import io.reactivex.disposables.Disposable; 26 | import io.reactivex.schedulers.Schedulers; 27 | 28 | /** 29 | * AccountModel 30 | * 31 | * @author ZhongDaFeng 32 | */ 33 | public class AccountModel implements AccountContract.LoginModel { 34 | 35 | private final String key_user_cache = "key_user_info"; 36 | 37 | @Override 38 | public void login(final Context context, String userName, String password, LifecycleProvider lifecycle, final ModelCallback.Http modelCallback) { 39 | 40 | //Biz发起网络请求 41 | BizFactory.getBiz(UserBiz.class).login(userName, password, lifecycle, new RHttpCallback() { 42 | 43 | @Override 44 | public UserBean convert(JsonElement data) { 45 | return new Gson().fromJson(data, UserBean.class); 46 | } 47 | 48 | @Override 49 | public void onSuccess(UserBean value) { 50 | 51 | String time = new SimpleDateFormat("yyyy/mm/dd HH:mm:ss").format(System.currentTimeMillis()); 52 | value.setTime(time); 53 | //回调给Presenter 54 | modelCallback.onSuccess(value); 55 | //保存到本地数据 56 | saveLocalCache(context, value); 57 | } 58 | 59 | @Override 60 | public void onError(int code, String desc) { 61 | //回调给Presenter 62 | modelCallback.onError(code, desc); 63 | } 64 | 65 | @Override 66 | public void onCancel() { 67 | //回调给Presenter 68 | modelCallback.onCancel(); 69 | } 70 | }); 71 | 72 | } 73 | 74 | @Override 75 | public void getLocalCache(final Context context, LifecycleProvider lifecycle, final ModelCallback.Data modelCallback) { 76 | //RxJava异步解析本地数据 77 | Observable.create(new ObservableOnSubscribe() { 78 | @Override 79 | public void subscribe(@NonNull ObservableEmitter e) throws Exception { 80 | 81 | //模拟工作线程获取并解析数据 82 | String userInfo = SpUtils.getSpUtils(context).getSPValue(key_user_cache, ""); 83 | 84 | e.onNext(userInfo); 85 | e.onComplete(); 86 | 87 | } 88 | }).subscribeOn(Schedulers.io())//工作线程 89 | .observeOn(AndroidSchedulers.mainThread()) 90 | .compose(lifecycle.bindToLifecycle())//绑定生命周期 91 | .subscribe(new Observer() { 92 | @Override 93 | public void onSubscribe(@NonNull Disposable d) { 94 | 95 | } 96 | 97 | @Override 98 | public void onNext(@NonNull String userBean) { 99 | modelCallback.onSuccess(userBean); //回调给Presenter 100 | } 101 | 102 | @Override 103 | public void onError(@NonNull Throwable e) { 104 | modelCallback.onSuccess(""); 105 | } 106 | 107 | @Override 108 | public void onComplete() { 109 | 110 | } 111 | }); 112 | } 113 | 114 | @Override 115 | public void saveLocalCache(Context context, UserBean data) { 116 | StringBuffer sb = new StringBuffer(); 117 | sb.append("用户ID:") 118 | .append(data.getUid()) 119 | .append("\n") 120 | .append("Token:") 121 | .append("\n") 122 | .append(data.getToken()) 123 | .append("\n") 124 | .append("最后登录:") 125 | .append("\n") 126 | .append(data.getTime()); 127 | 128 | SpUtils.getSpUtils(context).putSPValue(key_user_cache, sb.toString()); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/account/presenter/LoginPresenter.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.model.account.presenter; 2 | 3 | import com.r.mvp.cn.MvpPresenter; 4 | import com.r.mvp.cn.model.ModelCallback; 5 | import com.r.mvp.cn.model.ModelFactory; 6 | import com.rx.mvp.cn.model.account.contract.AccountContract; 7 | import com.rx.mvp.cn.model.account.entity.UserBean; 8 | import com.rx.mvp.cn.model.account.model.AccountModel; 9 | 10 | /** 11 | * 登录Presenter 12 | * 备注:继承 MvpPresenter 指定 View 类型 13 | * 14 | * @author ZhongDaFeng 15 | */ 16 | public class LoginPresenter extends MvpPresenter { 17 | 18 | /** 19 | * 登录 20 | */ 21 | public void login(String userName, String password) { 22 | 23 | //显示loading框 24 | getView().showProgressView(); 25 | 26 | //调用model获取网络数据 27 | ModelFactory.getModel(AccountModel.class).login(getView().getActivity(), userName, password, getView().getRxLifecycle(), new ModelCallback.Http() { 28 | @Override 29 | public void onSuccess(UserBean data) { 30 | //model数据回传 31 | 32 | //关闭弹窗 33 | getView().dismissProgressView(); 34 | 35 | StringBuffer sb = new StringBuffer(); 36 | sb.append("登录成功") 37 | .append("\n") 38 | .append("用户ID:") 39 | .append(data.getUid()) 40 | .append("\n") 41 | .append("Token:") 42 | .append("\n") 43 | .append(data.getToken()) 44 | .append("\n") 45 | .append("最后登录:") 46 | .append("\n") 47 | .append(data.getTime()); 48 | 49 | //用户信息展示 50 | getView().showResult(sb.toString()); 51 | 52 | } 53 | 54 | @Override 55 | public void onError(int code, String desc) { 56 | //model数据回传 57 | 58 | //关闭弹窗 59 | getView().dismissProgressView(); 60 | 61 | //错误信息提示 62 | getView().showError(code, desc); 63 | } 64 | 65 | @Override 66 | public void onCancel() { 67 | //关闭弹窗 68 | getView().dismissProgressView(); 69 | } 70 | }); 71 | 72 | } 73 | 74 | /** 75 | * 获取本地缓存数据 76 | */ 77 | public void getLocalCache() { 78 | 79 | //调用model获取本地数据 80 | ModelFactory.getModel(AccountModel.class).getLocalCache(getView().getActivity(), getView().getRxLifecycle(), new ModelCallback.Data() { 81 | @Override 82 | public void onSuccess(String object) { 83 | //model数据回传 84 | 85 | //关闭弹窗 86 | getView().dismissProgressView(); 87 | 88 | //用户信息展示 89 | getView().showResult(object); 90 | 91 | } 92 | }); 93 | } 94 | 95 | @Override 96 | public void destroy() { 97 | 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/load/download/DownloadBean.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.model.load.download; 2 | 3 | 4 | import com.r.http.cn.model.Download; 5 | 6 | /** 7 | * 下载实体类,继承Download 8 | */ 9 | public class DownloadBean extends Download { 10 | 11 | /** 12 | * 额外字段,apk图标 13 | */ 14 | private String icon; 15 | 16 | public DownloadBean(String url,String icon,String localUrl) { 17 | setServerUrl(url); 18 | setLocalUrl(localUrl); 19 | setIcon(icon); 20 | } 21 | 22 | 23 | public String getIcon() { 24 | return icon == null ? "" : icon; 25 | } 26 | 27 | public void setIcon(String icon) { 28 | this.icon = icon; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/load/特殊包说明.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 这个包目录下的功能为了快速演示上传下载功能,就不遵循MVP模式了 4 | 如果想要MVP使用查看 account 模块 -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/multiple/MultipleActivity.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.model.multiple; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.view.ViewPager; 5 | 6 | import com.ruffian.library.RVPIndicator; 7 | import com.rx.mvp.cn.R; 8 | import com.rx.mvp.cn.base.BaseActivity; 9 | import com.rx.mvp.cn.base.BasePagerAdapter; 10 | import com.rx.mvp.cn.model.account.fragment.LoginFragment; 11 | import com.rx.mvp.cn.model.phone.fragment.PhoneAddressFragment; 12 | 13 | import java.util.ArrayList; 14 | import java.util.Arrays; 15 | import java.util.List; 16 | 17 | import butterknife.BindView; 18 | 19 | /** 20 | * Fragment使用示例 21 | * 22 | * @author ZhongDaFeng 23 | */ 24 | public class MultipleActivity extends BaseActivity { 25 | 26 | @BindView(R.id.vp_indicator) 27 | RVPIndicator vpIndicator; 28 | @BindView(R.id.view_pager) 29 | ViewPager viewPager; 30 | 31 | private BasePagerAdapter mPagerAdapter; 32 | private ArrayList mFragmentList = new ArrayList<>(); 33 | private List mList = Arrays.asList("综合使用", "用户登录", "号码查询"); 34 | 35 | @Override 36 | protected int getContentViewId() { 37 | return R.layout.multiple_activity; 38 | } 39 | 40 | @Override 41 | protected void initBundleData() { 42 | 43 | } 44 | 45 | @Override 46 | protected void initView() { 47 | 48 | } 49 | 50 | @Override 51 | protected void initData() { 52 | 53 | mFragmentList.add(new MultipleFragment()); 54 | mFragmentList.add(new LoginFragment()); 55 | mFragmentList.add(new PhoneAddressFragment()); 56 | mPagerAdapter = new BasePagerAdapter(getSupportFragmentManager(), mFragmentList); 57 | 58 | //设置指示器title 59 | vpIndicator.setTitleList(mList); 60 | 61 | // 设置关联的ViewPager 62 | vpIndicator.setViewPager(viewPager, 0); 63 | 64 | //设置Adapter 65 | viewPager.setAdapter(mPagerAdapter); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/multiple/MultipleFragment.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.model.multiple; 2 | 3 | import android.view.LayoutInflater; 4 | import android.view.View; 5 | import android.widget.TextView; 6 | 7 | import com.r.mvp.cn.root.IMvpPresenter; 8 | import com.ruffian.library.widget.RTextView; 9 | import com.rx.mvp.cn.R; 10 | import com.rx.mvp.cn.base.BaseFragment; 11 | import com.rx.mvp.cn.model.account.contract.AccountContract; 12 | import com.rx.mvp.cn.model.account.presenter.LoginPresenter; 13 | import com.rx.mvp.cn.model.phone.contract.PhoneContract; 14 | import com.rx.mvp.cn.model.phone.entity.PhoneAddressBean; 15 | import com.rx.mvp.cn.model.phone.presenter.PhoneAddressPresenter; 16 | import com.rx.mvp.cn.widget.RLoadingDialog; 17 | import com.trello.rxlifecycle2.LifecycleProvider; 18 | 19 | import butterknife.BindView; 20 | 21 | /** 22 | * 演示一个页面调用多个接口 23 | * 备注:使用多个 Presenter / 实现多个 View 接口 24 | * 25 | * @author ZhongDaFeng 26 | */ 27 | public class MultipleFragment extends BaseFragment implements AccountContract.ILoginView, PhoneContract.IPhoneView { 28 | 29 | @BindView(R.id.tv_uid) 30 | RTextView tvUid; 31 | @BindView(R.id.tv_phone) 32 | TextView tvPhone; 33 | @BindView(R.id.tv_province) 34 | TextView tvProvince; 35 | @BindView(R.id.tv_city) 36 | TextView tvCity; 37 | @BindView(R.id.tv_operator) 38 | TextView tvOperator; 39 | 40 | private LoginPresenter mLoginPresenter = new LoginPresenter(); 41 | private PhoneAddressPresenter mPhonePst = new PhoneAddressPresenter(); 42 | 43 | //手机号码 44 | private String mPhoneNumber = "1351073"; 45 | //账号密码 46 | private String mUserName = "ruffian"; 47 | private String mPsw = "EA8A706C4C34A168"; 48 | 49 | @Override 50 | protected View getContentView() { 51 | return LayoutInflater.from(mContext).inflate(R.layout.multiple_fragment, null); 52 | } 53 | 54 | @Override 55 | protected void initBundleData() { 56 | 57 | } 58 | 59 | @Override 60 | protected void initView() { 61 | mLoadingDialog = new RLoadingDialog(mContext, true); 62 | } 63 | 64 | @Override 65 | protected void initData() { 66 | //登录 67 | mLoginPresenter.login(mUserName, mPsw); 68 | //查询 69 | mPhonePst.phoneQuery(mPhoneNumber); 70 | } 71 | 72 | @Override 73 | protected IMvpPresenter[] getPresenterArray() { 74 | return new IMvpPresenter[]{mLoginPresenter, mPhonePst}; 75 | } 76 | 77 | /** 78 | * 用户信息展示 79 | */ 80 | @Override 81 | public void showResult(String data) { 82 | tvUid.setText(data); 83 | } 84 | 85 | @Override 86 | public void showError(int code, String msg) { 87 | showToast(msg); 88 | } 89 | 90 | /** 91 | * 号码查询结果展示 92 | */ 93 | @Override 94 | public void showPhoneResult(PhoneAddressBean bean) { 95 | if (bean == null) return; 96 | tvPhone.setText(bean.getMobileNumber()); 97 | tvCity.setText(bean.getCity()); 98 | tvProvince.setText(bean.getProvince()); 99 | tvOperator.setText(bean.getOperator()); 100 | } 101 | 102 | @Override 103 | public LifecycleProvider getRxLifecycle() { 104 | return this; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/phone/activity/PhoneAddressActivity.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.model.phone.activity; 2 | 3 | import android.text.TextUtils; 4 | import android.view.View; 5 | import android.widget.EditText; 6 | import android.widget.TextView; 7 | import android.widget.Toast; 8 | 9 | import com.r.mvp.cn.root.IMvpPresenter; 10 | import com.rx.mvp.cn.R; 11 | import com.rx.mvp.cn.base.BaseActivity; 12 | import com.rx.mvp.cn.model.phone.contract.PhoneContract; 13 | import com.rx.mvp.cn.model.phone.entity.PhoneAddressBean; 14 | import com.rx.mvp.cn.model.phone.presenter.PhoneAddressPresenter; 15 | import com.rx.mvp.cn.widget.RLoadingDialog; 16 | import com.trello.rxlifecycle2.LifecycleProvider; 17 | 18 | import butterknife.BindView; 19 | import butterknife.OnClick; 20 | 21 | /** 22 | * 手机号码归属地查询页面 23 | * 24 | * @author ZhongDaFeng 25 | */ 26 | public class PhoneAddressActivity extends BaseActivity implements PhoneContract.IPhoneView { 27 | 28 | @BindView(R.id.et_phone) 29 | EditText etPhone; 30 | @BindView(R.id.tv_phone) 31 | TextView tvPhone; 32 | @BindView(R.id.tv_province) 33 | TextView tvProvince; 34 | @BindView(R.id.tv_city) 35 | TextView tvCity; 36 | @BindView(R.id.tv_operator) 37 | TextView tvOperator; 38 | 39 | private PhoneAddressPresenter mPhonePst = new PhoneAddressPresenter(); 40 | 41 | @Override 42 | protected int getContentViewId() { 43 | return R.layout.activity_phone_address; 44 | } 45 | 46 | @Override 47 | protected void initBundleData() { 48 | 49 | } 50 | 51 | @Override 52 | protected void initView() { 53 | mLoadingDialog = new RLoadingDialog(this, true); 54 | } 55 | 56 | @Override 57 | protected void initData() { 58 | 59 | } 60 | 61 | @OnClick({R.id.submit}) 62 | public void onClick(View v) { 63 | switch (v.getId()) { 64 | case R.id.submit: 65 | attemptSubmit(); 66 | break; 67 | } 68 | } 69 | 70 | /** 71 | * 尝试提交 72 | */ 73 | private void attemptSubmit() { 74 | String phone = etPhone.getText().toString(); 75 | if (TextUtils.isEmpty(phone)) { 76 | Toast.makeText(mContext, getString(R.string.hint_phone), Toast.LENGTH_SHORT).show(); 77 | return; 78 | } 79 | mPhonePst.phoneQuery(phone); 80 | } 81 | 82 | @Override 83 | protected IMvpPresenter[] getPresenterArray() { 84 | return new IMvpPresenter[]{mPhonePst}; 85 | } 86 | 87 | @Override 88 | public void showPhoneResult(PhoneAddressBean bean) { 89 | if (bean == null) return; 90 | tvPhone.setText(bean.getMobileNumber()); 91 | tvCity.setText(bean.getCity()); 92 | tvProvince.setText(bean.getProvince()); 93 | tvOperator.setText(bean.getOperator()); 94 | } 95 | 96 | @Override 97 | public LifecycleProvider getRxLifecycle() { 98 | return this; 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/phone/biz/PhoneBiz.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.model.phone.biz; 2 | 3 | import com.r.http.cn.RHttp; 4 | import com.r.http.cn.callback.HttpCallback; 5 | import com.rx.mvp.cn.base.BaseBiz; 6 | import com.trello.rxlifecycle2.LifecycleProvider; 7 | 8 | import java.util.TreeMap; 9 | 10 | /** 11 | * 其他业务类 12 | * 13 | * @author ZhongDaFeng 14 | */ 15 | public class PhoneBiz extends BaseBiz { 16 | 17 | /** 18 | * 号码归属地查询API 19 | */ 20 | private final String API_PHONE_QUERY = "v1/mobile/address/query"; 21 | 22 | public void phoneQuery(String phone, LifecycleProvider lifecycle, HttpCallback callback) { 23 | /** 24 | * 构建参数 25 | */ 26 | TreeMap request = new TreeMap<>(); 27 | request.put("phone", phone); 28 | request.putAll(getBaseRequest()); 29 | 30 | /** 31 | * 发送请求 32 | */ 33 | RHttp http = new RHttp.Builder() 34 | .post() 35 | .baseUrl("http://apicloud.mob.com/") 36 | .apiUrl(API_PHONE_QUERY) 37 | .addParameter(request) 38 | .lifecycle(lifecycle) 39 | .build(); 40 | 41 | http.request(callback); 42 | 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/phone/contract/PhoneContract.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.model.phone.contract; 2 | 3 | import android.support.annotation.UiThread; 4 | 5 | import com.r.mvp.cn.MvpView; 6 | import com.r.mvp.cn.model.ModelCallback; 7 | import com.r.mvp.cn.root.IMvpModel; 8 | import com.rx.mvp.cn.model.phone.entity.PhoneAddressBean; 9 | import com.trello.rxlifecycle2.LifecycleProvider; 10 | 11 | /** 12 | * Phone业务的Contract(协议) 13 | * 目的:避免mvp架构 view/model 文件过多 14 | * 综合管理某业务的 view/model 接口 15 | * 16 | * @author ZhongDaFeng 17 | */ 18 | public interface PhoneContract { 19 | 20 | /*号码查询模块View接口*/ 21 | interface IPhoneView extends MvpView { 22 | 23 | /** 24 | * 展示号码结果 25 | */ 26 | @UiThread 27 | void showPhoneResult(PhoneAddressBean bean); 28 | } 29 | 30 | /*Phone模块model接口.此处根据具体项目决定是否需要此接口层*/ 31 | interface PhoneModel extends IMvpModel { 32 | /** 33 | * 查询号码 34 | */ 35 | void phoneQuery(String phone, LifecycleProvider lifecycle, ModelCallback.Http modelCallback); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/phone/entity/PhoneAddressBean.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.model.phone.entity; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * 手机归属地实体类 9 | * 10 | * @author ZhongDaFeng 11 | */ 12 | 13 | public class PhoneAddressBean implements Serializable { 14 | 15 | 16 | // "city":"南宁市", 17 | // "cityCode":"0771", 18 | // "mobileNumber":"1330000", 19 | // "operator":"电信CDMA卡", 20 | // "province":"广西", 21 | // "zipCode":"530000" 22 | 23 | @SerializedName("city") 24 | private String city; 25 | @SerializedName("cityCode") 26 | private String cityCode; 27 | @SerializedName("mobileNumber") 28 | private String mobileNumber; 29 | @SerializedName("operator") 30 | private String operator; 31 | @SerializedName("province") 32 | private String province; 33 | @SerializedName("zipCode") 34 | private String zipCode; 35 | 36 | public String getCity() { 37 | return city; 38 | } 39 | 40 | public void setCity(String city) { 41 | this.city = city; 42 | } 43 | 44 | public String getCityCode() { 45 | return cityCode; 46 | } 47 | 48 | public void setCityCode(String cityCode) { 49 | this.cityCode = cityCode; 50 | } 51 | 52 | public String getMobileNumber() { 53 | return mobileNumber; 54 | } 55 | 56 | public void setMobileNumber(String mobileNumber) { 57 | this.mobileNumber = mobileNumber; 58 | } 59 | 60 | public String getOperator() { 61 | return operator; 62 | } 63 | 64 | public void setOperator(String operator) { 65 | this.operator = operator; 66 | } 67 | 68 | public String getProvince() { 69 | return province; 70 | } 71 | 72 | public void setProvince(String province) { 73 | this.province = province; 74 | } 75 | 76 | public String getZipCode() { 77 | return zipCode; 78 | } 79 | 80 | public void setZipCode(String zipCode) { 81 | this.zipCode = zipCode; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/phone/fragment/PhoneAddressFragment.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.model.phone.fragment; 2 | 3 | import android.text.TextUtils; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.widget.EditText; 7 | import android.widget.TextView; 8 | import android.widget.Toast; 9 | 10 | import com.r.mvp.cn.root.IMvpPresenter; 11 | import com.rx.mvp.cn.R; 12 | import com.rx.mvp.cn.base.BaseFragment; 13 | import com.rx.mvp.cn.model.phone.contract.PhoneContract; 14 | import com.rx.mvp.cn.model.phone.entity.PhoneAddressBean; 15 | import com.rx.mvp.cn.model.phone.presenter.PhoneAddressPresenter; 16 | import com.rx.mvp.cn.widget.RLoadingDialog; 17 | import com.trello.rxlifecycle2.LifecycleProvider; 18 | 19 | import butterknife.BindView; 20 | import butterknife.OnClick; 21 | 22 | /** 23 | * 手机号码归属地查询Fragment 24 | * 25 | * @author ZhongDaFeng 26 | */ 27 | public class PhoneAddressFragment extends BaseFragment implements PhoneContract.IPhoneView { 28 | 29 | @BindView(R.id.et_phone) 30 | EditText etPhone; 31 | @BindView(R.id.tv_phone) 32 | TextView tvPhone; 33 | @BindView(R.id.tv_province) 34 | TextView tvProvince; 35 | @BindView(R.id.tv_city) 36 | TextView tvCity; 37 | @BindView(R.id.tv_operator) 38 | TextView tvOperator; 39 | 40 | private PhoneAddressPresenter mPhonePst = new PhoneAddressPresenter(); 41 | 42 | @Override 43 | protected View getContentView() { 44 | return LayoutInflater.from(mContext).inflate(R.layout.activity_phone_address, null); 45 | } 46 | 47 | @Override 48 | protected void initBundleData() { 49 | 50 | } 51 | 52 | @Override 53 | protected void initView() { 54 | mLoadingDialog = new RLoadingDialog(mContext, true); 55 | } 56 | 57 | @Override 58 | protected void initData() { 59 | 60 | } 61 | 62 | @OnClick({R.id.submit}) 63 | public void onClick(View v) { 64 | switch (v.getId()) { 65 | case R.id.submit: 66 | attemptSubmit(); 67 | break; 68 | } 69 | } 70 | 71 | /** 72 | * 尝试提交 73 | */ 74 | private void attemptSubmit() { 75 | String phone = etPhone.getText().toString(); 76 | if (TextUtils.isEmpty(phone)) { 77 | Toast.makeText(mContext, getString(R.string.hint_phone), Toast.LENGTH_SHORT).show(); 78 | return; 79 | } 80 | mPhonePst.phoneQuery(phone); 81 | } 82 | 83 | @Override 84 | protected IMvpPresenter[] getPresenterArray() { 85 | return new IMvpPresenter[]{mPhonePst}; 86 | } 87 | 88 | @Override 89 | public LifecycleProvider getRxLifecycle() { 90 | return this; 91 | } 92 | 93 | @Override 94 | public void showPhoneResult(PhoneAddressBean bean) { 95 | if (bean == null) return; 96 | tvPhone.setText(bean.getMobileNumber()); 97 | tvCity.setText(bean.getCity()); 98 | tvProvince.setText(bean.getProvince()); 99 | tvOperator.setText(bean.getOperator()); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/phone/model/PhoneModel.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.model.phone.model; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.JsonElement; 5 | import com.r.mvp.cn.model.ModelCallback; 6 | import com.rx.mvp.cn.base.BizFactory; 7 | import com.rx.mvp.cn.core.net.http.RHttpCallback; 8 | import com.rx.mvp.cn.model.phone.biz.PhoneBiz; 9 | import com.rx.mvp.cn.model.phone.contract.PhoneContract; 10 | import com.rx.mvp.cn.model.phone.entity.PhoneAddressBean; 11 | import com.trello.rxlifecycle2.LifecycleProvider; 12 | 13 | /** 14 | * PhoneModel 15 | * 16 | * @author ZhongDaFeng 17 | */ 18 | public class PhoneModel implements PhoneContract.PhoneModel { 19 | 20 | @Override 21 | public void phoneQuery(String phone, LifecycleProvider lifecycle, final ModelCallback.Http modelCallback) { 22 | //Biz发起网络请求 23 | BizFactory.getBiz(PhoneBiz.class).phoneQuery(phone, lifecycle, new RHttpCallback() { 24 | @Override 25 | public PhoneAddressBean convert(JsonElement data) { 26 | return new Gson().fromJson(data, PhoneAddressBean.class); 27 | } 28 | 29 | @Override 30 | public void onSuccess(PhoneAddressBean object) { 31 | modelCallback.onSuccess(object); 32 | } 33 | 34 | @Override 35 | public void onError(int code, String desc) { 36 | modelCallback.onError(code, desc); 37 | } 38 | 39 | @Override 40 | public void onCancel() { 41 | modelCallback.onCancel(); 42 | } 43 | }); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/model/phone/presenter/PhoneAddressPresenter.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.model.phone.presenter; 2 | 3 | import com.r.mvp.cn.MvpPresenter; 4 | import com.r.mvp.cn.model.ModelCallback; 5 | import com.r.mvp.cn.model.ModelFactory; 6 | import com.rx.mvp.cn.model.phone.contract.PhoneContract; 7 | import com.rx.mvp.cn.model.phone.entity.PhoneAddressBean; 8 | import com.rx.mvp.cn.model.phone.model.PhoneModel; 9 | 10 | /** 11 | * 手机号归属地Presenter 12 | * 13 | * @author ZhongDaFeng 14 | */ 15 | public class PhoneAddressPresenter extends MvpPresenter { 16 | 17 | 18 | /** 19 | * 获取信息 20 | * 21 | * @author ZhongDaFeng 22 | */ 23 | public void phoneQuery(String phone) { 24 | 25 | getView().showProgressView(); 26 | ModelFactory.getModel(PhoneModel.class).phoneQuery(phone, getView().getRxLifecycle(), new ModelCallback.Http() { 27 | @Override 28 | public void onSuccess(PhoneAddressBean object) { 29 | getView().dismissProgressView(); 30 | getView().showPhoneResult(object); 31 | } 32 | 33 | @Override 34 | public void onError(int code, String desc) { 35 | getView().dismissProgressView(); 36 | getView().showToast(desc); 37 | } 38 | 39 | @Override 40 | public void onCancel() { 41 | getView().dismissProgressView(); 42 | } 43 | }); 44 | 45 | } 46 | 47 | 48 | @Override 49 | public void destroy() { 50 | 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/sample/HttpSample.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.sample; 2 | 3 | /** 4 | * Http(Retrofit)使用demo/测试类 5 | * 6 | * @author ZhongDaFeng 7 | */ 8 | public class HttpSample { 9 | 10 | /** 11 | * 此处不再重复示例,直接查看UserBiz 12 | */ 13 | 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/sample/mvp/AccountActivity.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.sample.mvp; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.view.View; 5 | 6 | import com.r.mvp.cn.root.IMvpPresenter; 7 | import com.rx.mvp.cn.base.BaseActivity; 8 | import com.rx.mvp.cn.model.account.entity.UserBean; 9 | import com.rx.mvp.cn.utils.ToastUtils; 10 | import com.trello.rxlifecycle2.LifecycleProvider; 11 | 12 | /** 13 | * XX业务 Activity 14 | * 15 | * @author ZhongDaFeng 16 | */ 17 | public class AccountActivity extends BaseActivity implements AccountContract.ILoginView { 18 | 19 | private AccountPresenter accountPresenter = new AccountPresenter(); 20 | 21 | @Override 22 | protected int getContentViewId() { 23 | return 0; 24 | } 25 | 26 | @Override 27 | protected void initBundleData() { 28 | 29 | } 30 | 31 | @Override 32 | protected void initView() { 33 | 34 | } 35 | 36 | @Override 37 | protected void initData() { 38 | //默认加载本地缓存数据 39 | accountPresenter.getLocalCache("123456"); 40 | 41 | new View(this).setOnClickListener(new View.OnClickListener() { 42 | @Override 43 | public void onClick(View v) { 44 | //账号密码登录 45 | accountPresenter.login("acb", "123456"); 46 | } 47 | }); 48 | } 49 | 50 | 51 | /*---------mvp--------*/ 52 | 53 | /** 54 | * 需要使用Presenter时 覆盖重写 55 | */ 56 | @Override 57 | protected IMvpPresenter[] getPresenterArray() { 58 | return new IMvpPresenter[]{accountPresenter}; 59 | } 60 | 61 | @Override 62 | public void showResult(UserBean data) { 63 | //展示用户数据 64 | } 65 | 66 | @Override 67 | public void showError(int code, String msg) { 68 | //错误处理UI 69 | switch (code) { 70 | case 0: 71 | showToast(msg); 72 | break; 73 | case 1: 74 | // new AlertDialog(this).show(); 75 | break; 76 | } 77 | } 78 | 79 | @Override 80 | public LifecycleProvider getRxLifecycle() { 81 | return this; 82 | } 83 | 84 | @Override 85 | public void showToast(@NonNull String msg) { 86 | //吐司提示信息 87 | ToastUtils.showToast(this, msg); 88 | } 89 | 90 | @Override 91 | public void showProgressView() { 92 | //展示加载中相关的控件 93 | //showProgressDialog(); 94 | } 95 | 96 | @Override 97 | public void dismissProgressView() { 98 | //关闭加载中相关的控件 99 | //dismissProgressDialog(); 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/sample/mvp/AccountContract.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.sample.mvp; 2 | 3 | import android.support.annotation.UiThread; 4 | 5 | import com.r.mvp.cn.MvpView; 6 | import com.r.mvp.cn.model.ModelCallback; 7 | import com.r.mvp.cn.root.IMvpModel; 8 | import com.rx.mvp.cn.model.account.entity.UserBean; 9 | import com.trello.rxlifecycle2.LifecycleProvider; 10 | 11 | /** 12 | * XX业务的Contract(协议) 13 | * 目的:避免mvp架构 view/model 文件过多 14 | * 综合管理某业务的 view/model 接口 15 | * 16 | * @author ZhongDaFeng 17 | */ 18 | public interface AccountContract { 19 | 20 | /*登录模块View接口*/ 21 | interface ILoginView extends MvpView { 22 | 23 | /*登录成功展示结果*/ 24 | @UiThread 25 | void showResult(UserBean data); 26 | 27 | /*登录错误处理逻辑*/ 28 | @UiThread 29 | void showError(int code, String msg); 30 | } 31 | 32 | /*登录模块model接口.此处根据具体项目决定是否需要此接口层*/ 33 | interface LoginModel extends IMvpModel { 34 | /** 35 | * 用户密码登录 36 | * 37 | * @param lifecycle 组件生命周期 38 | * @param modelCallback model回调接口(网络) 39 | */ 40 | void login(String userName, String password, LifecycleProvider lifecycle, ModelCallback.Http modelCallback); 41 | 42 | /** 43 | * 获取本地缓存数据 44 | * 45 | * @param modelCallback model回调接口(普通数据) 46 | */ 47 | void getLocalCache(String account, LifecycleProvider lifecycle, ModelCallback.Data modelCallback); 48 | } 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/sample/mvp/AccountFragment.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.sample.mvp; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.view.View; 5 | 6 | import com.r.mvp.cn.root.IMvpPresenter; 7 | import com.rx.mvp.cn.base.BaseFragment; 8 | import com.rx.mvp.cn.model.account.entity.UserBean; 9 | import com.rx.mvp.cn.utils.ToastUtils; 10 | import com.trello.rxlifecycle2.LifecycleProvider; 11 | 12 | /** 13 | * XX业务 Fragment 14 | * 15 | * @author ZhongDaFeng 16 | */ 17 | public class AccountFragment extends BaseFragment implements AccountContract.ILoginView { 18 | 19 | private AccountPresenter accountPresenter = new AccountPresenter(); 20 | 21 | @Override 22 | protected View getContentView() { 23 | return null; 24 | } 25 | 26 | @Override 27 | protected void initBundleData() { 28 | 29 | } 30 | 31 | @Override 32 | protected void initView() { 33 | 34 | } 35 | 36 | @Override 37 | protected void initData() { 38 | //默认加载本地缓存数据 39 | accountPresenter.getLocalCache("123456"); 40 | 41 | new View(getActivity()).setOnClickListener(new View.OnClickListener() { 42 | @Override 43 | public void onClick(View v) { 44 | //账号密码登录 45 | accountPresenter.login("acb", "123456"); 46 | } 47 | }); 48 | } 49 | 50 | /*---------mvp--------*/ 51 | 52 | /** 53 | * 需要使用Presenter时 覆盖重写 54 | */ 55 | @Override 56 | protected IMvpPresenter[] getPresenterArray() { 57 | return new IMvpPresenter[]{accountPresenter}; 58 | } 59 | 60 | @Override 61 | public void showResult(UserBean data) { 62 | //展示用户数据 63 | } 64 | 65 | @Override 66 | public void showError(int code, String msg) { 67 | //错误处理UI 68 | switch (code) { 69 | case 0: 70 | showToast(msg); 71 | break; 72 | case 1: 73 | // new AlertDialog(getActivity()).show(); 74 | break; 75 | } 76 | } 77 | 78 | @Override 79 | public LifecycleProvider getRxLifecycle() { 80 | return this; 81 | } 82 | 83 | @Override 84 | public void showToast(@NonNull String msg) { 85 | //吐司提示信息 86 | ToastUtils.showToast(getActivity(), msg); 87 | } 88 | 89 | @Override 90 | public void showProgressView() { 91 | //展示加载中相关的控件 92 | //showProgressDialog(); 93 | } 94 | 95 | @Override 96 | public void dismissProgressView() { 97 | //关闭加载中相关的控件 98 | // dismissProgressDialog(); 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/sample/mvp/AccountModel.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.sample.mvp; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.JsonElement; 5 | import com.r.mvp.cn.model.ModelCallback; 6 | import com.rx.mvp.cn.base.BizFactory; 7 | import com.rx.mvp.cn.core.net.http.RHttpCallback; 8 | import com.rx.mvp.cn.model.account.biz.UserBiz; 9 | import com.rx.mvp.cn.model.account.entity.UserBean; 10 | import com.trello.rxlifecycle2.LifecycleProvider; 11 | 12 | import org.json.JSONObject; 13 | 14 | import io.reactivex.Observable; 15 | import io.reactivex.ObservableEmitter; 16 | import io.reactivex.ObservableOnSubscribe; 17 | import io.reactivex.Observer; 18 | import io.reactivex.android.schedulers.AndroidSchedulers; 19 | import io.reactivex.annotations.NonNull; 20 | import io.reactivex.disposables.Disposable; 21 | import io.reactivex.schedulers.Schedulers; 22 | 23 | /** 24 | * XX业务的Model 25 | * 26 | * @author ZhongDaFeng 27 | */ 28 | public class AccountModel implements AccountContract.LoginModel { 29 | 30 | @Override 31 | public void login(String userName, String password, LifecycleProvider lifecycle, final ModelCallback.Http modelCallback) { 32 | //Biz发起网络请求 33 | BizFactory.getBiz(UserBiz.class).login(userName, password, lifecycle, new RHttpCallback() { 34 | 35 | @Override 36 | public UserBean convert(JsonElement data) { 37 | return new Gson().fromJson(data, UserBean.class); 38 | } 39 | 40 | @Override 41 | public void onSuccess(UserBean value) { 42 | //回调给Presenter 43 | modelCallback.onSuccess(value); 44 | } 45 | 46 | @Override 47 | public void onError(int code, String desc) { 48 | //回调给Presenter 49 | modelCallback.onError(code, desc); 50 | } 51 | 52 | @Override 53 | public void onCancel() { 54 | 55 | } 56 | }); 57 | } 58 | 59 | @Override 60 | public void getLocalCache(String account, LifecycleProvider lifecycle, final ModelCallback.Data modelCallback) { 61 | 62 | //RxJava异步解析本地数据 63 | Observable.create(new ObservableOnSubscribe() { 64 | @Override 65 | public void subscribe(@NonNull ObservableEmitter e) throws Exception { 66 | 67 | //模拟工作线程获取并解析数据 68 | 69 | e.onNext(new UserBean()); 70 | 71 | } 72 | }).subscribeOn(Schedulers.io())//工作线程 73 | .observeOn(AndroidSchedulers.mainThread()) 74 | .compose(lifecycle.bindToLifecycle())//绑定生命周期 75 | .subscribe(new Observer() { 76 | @Override 77 | public void onSubscribe(@NonNull Disposable d) { 78 | 79 | } 80 | 81 | @Override 82 | public void onNext(@NonNull UserBean userBean) { 83 | modelCallback.onSuccess(userBean); //回调给Presenter 84 | } 85 | 86 | @Override 87 | public void onError(@NonNull Throwable e) { 88 | modelCallback.onSuccess(new UserBean()); 89 | } 90 | 91 | @Override 92 | public void onComplete() { 93 | 94 | } 95 | }); 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/sample/mvp/AccountPresenter.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.sample.mvp; 2 | 3 | import com.r.mvp.cn.MvpPresenter; 4 | import com.r.mvp.cn.model.ModelCallback; 5 | import com.r.mvp.cn.model.ModelFactory; 6 | import com.rx.mvp.cn.model.account.entity.UserBean; 7 | 8 | /** 9 | * XX业务的Presenter 10 | * 11 | * @author ZhongDaFeng 12 | */ 13 | public class AccountPresenter extends MvpPresenter { 14 | 15 | /** 16 | * 登录 17 | */ 18 | void login(String userName, String password) { 19 | 20 | //1.展示loading框 21 | getView().showProgressView(); 22 | 23 | //调用model中login方法 24 | ModelFactory.getModel(AccountModel.class).login(userName, password, getView().getRxLifecycle(), new ModelCallback.Http() { 25 | @Override 26 | public void onSuccess(UserBean object) { 27 | //model给回的数据 28 | 29 | //2.关闭loading框 30 | getView().dismissProgressView(); 31 | 32 | //展示用户数据 33 | getView().showResult(object); 34 | 35 | } 36 | 37 | @Override 38 | public void onError(int code, String desc) { 39 | //model给回的数据 40 | 41 | //2.关闭loading框 42 | getView().dismissProgressView(); 43 | 44 | //展示错误信息 45 | getView().showError(code, desc); 46 | 47 | } 48 | 49 | @Override 50 | public void onCancel() { 51 | //2.关闭loading框 52 | getView().dismissProgressView(); 53 | } 54 | }); 55 | } 56 | 57 | /** 58 | * 获取本地缓存数据 59 | */ 60 | public void getLocalCache(String account) { 61 | 62 | //调用model中getLocalCache方法 63 | ModelFactory.getModel(AccountModel.class).getLocalCache(account, getView().getRxLifecycle(), new ModelCallback.Data() { 64 | @Override 65 | public void onSuccess(UserBean object) { 66 | //model给回的数据 67 | 68 | //展示用户数据 69 | getView().showResult(object); 70 | } 71 | }); 72 | 73 | } 74 | 75 | @Override 76 | public void destroy() { 77 | 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/utils/LogUtils.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.utils; 2 | 3 | import android.util.Log; 4 | 5 | import com.rx.mvp.cn.BuildConfig; 6 | 7 | /** 8 | * LOG工具类 9 | * 10 | * @author ZhongDaFeng 11 | */ 12 | public class LogUtils { 13 | 14 | private static final String TAG = "Rx-Mvp"; 15 | private static boolean allowD = true; 16 | private static boolean allowE = true; 17 | private static boolean allowI = true; 18 | private static boolean allowV = true; 19 | private static boolean allowW = true; 20 | 21 | static { 22 | allowD = allowE = allowI = allowV = allowW = BuildConfig.LOG_DEBUG; 23 | } 24 | 25 | private LogUtils() { 26 | } 27 | 28 | /** 29 | * 开启Log 30 | * 31 | * @author ZhongDaFeng 32 | */ 33 | public static void openLog(boolean flag) { 34 | allowD = flag; 35 | allowE = flag; 36 | allowI = flag; 37 | allowV = flag; 38 | allowW = flag; 39 | } 40 | 41 | public static void d(String content) { 42 | if (!allowD) 43 | return; 44 | Log.d(TAG, content); 45 | } 46 | 47 | public static void e(String content) { 48 | if (!allowE) 49 | return; 50 | Log.e(TAG, content); 51 | } 52 | 53 | public static void i(String content) { 54 | if (!allowI) 55 | return; 56 | Log.i(TAG, content); 57 | } 58 | 59 | public static void v(String content) { 60 | if (!allowV) 61 | return; 62 | Log.v(TAG, content); 63 | } 64 | 65 | public static void w(String content) { 66 | if (!allowW) 67 | return; 68 | Log.w(TAG, content); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/utils/SpUtils.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.utils; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.text.TextUtils; 6 | 7 | import com.google.gson.Gson; 8 | import com.google.gson.JsonArray; 9 | import com.google.gson.JsonElement; 10 | import com.google.gson.JsonParser; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | /** 16 | * SP数据操作工具类 17 | * 18 | * @author ZhongDaFeng 19 | */ 20 | public class SpUtils { 21 | 22 | 23 | private static final String SP_FILE_KEY = "RxMvp"; 24 | private static SpUtils spUtil; 25 | private static SharedPreferences sp; 26 | 27 | private SpUtils(Context context, String fileKey, int mode) { 28 | sp = context.getSharedPreferences(fileKey, mode); 29 | } 30 | 31 | public static SpUtils getSpUtil(Context context, String fileKey, int mode) { 32 | if (spUtil == null) { 33 | spUtil = new SpUtils(context, fileKey, mode); 34 | } else { 35 | sp = context.getSharedPreferences(fileKey, mode); 36 | } 37 | return spUtil; 38 | } 39 | 40 | public static SpUtils getSpUtils(Context context) { 41 | return getSpUtil(context, SP_FILE_KEY, Context.MODE_PRIVATE); 42 | } 43 | 44 | public void putSPValue(String valueKey, String value) { 45 | sp.edit().putString(valueKey, value).commit(); 46 | } 47 | 48 | public void putSPValue(String valueKey, int value) { 49 | sp.edit().putInt(valueKey, value).apply(); 50 | } 51 | 52 | public void putSPValue(String valueKey, float value) { 53 | sp.edit().putFloat(valueKey, value).apply(); 54 | } 55 | 56 | public void putSPValue(String valueKey, boolean value) { 57 | sp.edit().putBoolean(valueKey, value).apply(); 58 | } 59 | 60 | public void putSPValue(String valueKey, long value) { 61 | sp.edit().putLong(valueKey, value).apply(); 62 | } 63 | 64 | public int getSPValue(String valueKey, int value) { 65 | return sp.getInt(valueKey, value); 66 | } 67 | 68 | public float getSPValue(String valueKey, float value) { 69 | return sp.getFloat(valueKey, value); 70 | } 71 | 72 | public String getSPValue(String valueKey, String value) { 73 | return sp.getString(valueKey, value); 74 | } 75 | 76 | public boolean getSPValue(String valueKey, boolean value) { 77 | return sp.getBoolean(valueKey, value); 78 | } 79 | 80 | public long getSPValue(String valueKey, long value) { 81 | return sp.getLong(valueKey, value); 82 | } 83 | 84 | public void remove(String key) { 85 | sp.edit().remove(key).apply(); 86 | } 87 | 88 | public void clear() { 89 | sp.edit().clear().apply(); 90 | } 91 | 92 | 93 | /** 94 | * 保存List 95 | */ 96 | public void putSPList(String key, List list) { 97 | if (null == list || list.size() <= 0) { 98 | sp.edit().putString(key, "").apply(); 99 | return; 100 | } 101 | Gson gson = new Gson(); 102 | //转换成json数据,再保存 103 | String strJson = gson.toJson(list); 104 | sp.edit().putString(key, strJson).apply(); 105 | } 106 | 107 | /** 108 | * 获取List 109 | */ 110 | public List getSPList(String tag, Class cls) { 111 | List list = new ArrayList(); 112 | String strJson = sp.getString(tag, null); 113 | if (TextUtils.isEmpty(strJson)) { 114 | return list; 115 | } 116 | Gson gson = new Gson(); 117 | JsonArray array = new JsonParser().parse(strJson).getAsJsonArray(); 118 | for (JsonElement jsonElement : array) { 119 | list.add(gson.fromJson(jsonElement, cls)); 120 | } 121 | return list; 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/utils/ToastUtils.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.utils; 2 | 3 | import android.content.Context; 4 | import android.text.TextUtils; 5 | import android.widget.Toast; 6 | 7 | /** 8 | * toast工具类 9 | * 10 | * @author ZhongDaFeng 11 | */ 12 | public class ToastUtils { 13 | 14 | private static Toast toast; 15 | 16 | /** 17 | * 显示提示信息 18 | */ 19 | public static void showToast(Context context, String text) { 20 | if (TextUtils.isEmpty(text)) return; 21 | if (toast == null) { 22 | toast = Toast.makeText(context, text, Toast.LENGTH_SHORT); 23 | } else { 24 | toast.setText(text); 25 | } 26 | toast.show(); 27 | 28 | } 29 | 30 | /** 31 | * 显示提示信息 32 | */ 33 | public static void showToast(Context context, int rId) { 34 | if (toast == null) { 35 | toast = Toast.makeText(context, rId, Toast.LENGTH_SHORT); 36 | } else { 37 | toast.setText(rId); 38 | } 39 | toast.show(); 40 | 41 | } 42 | 43 | /** 44 | * 显示提示信息(时间较长) 45 | */ 46 | public static void showLongToast(Context context, String text) { 47 | if (toast == null) { 48 | toast = Toast.makeText(context, text, Toast.LENGTH_LONG); 49 | } else { 50 | toast.setText(text); 51 | } 52 | toast.show(); 53 | 54 | } 55 | 56 | /** 57 | * 显示提示信息(时间较长) 58 | */ 59 | public static void showLongToast(Context context, int rId) { 60 | if (toast == null) { 61 | toast = Toast.makeText(context, rId, Toast.LENGTH_LONG); 62 | } else { 63 | toast.setText(rId); 64 | } 65 | toast.show(); 66 | 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/rx/mvp/cn/widget/RLoadingDialog.java: -------------------------------------------------------------------------------- 1 | package com.rx.mvp.cn.widget; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.os.Bundle; 6 | import android.view.Window; 7 | import android.widget.LinearLayout; 8 | import android.widget.ProgressBar; 9 | 10 | /** 11 | * 自定义Loading弹窗 12 | * 13 | * @author ZhongDafeng 14 | */ 15 | public class RLoadingDialog extends Dialog { 16 | 17 | public RLoadingDialog(Context context, boolean cancelable) { 18 | super(context); 19 | setCancelable(cancelable); 20 | } 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | requestWindowFeature(Window.FEATURE_NO_TITLE); 26 | LinearLayout linearLayout = new LinearLayout(getContext()); 27 | ProgressBar progressBar = new ProgressBar(getContext()); 28 | 29 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(125, 30 | 125); 31 | params.setMargins(100, 20, 100, 20); 32 | progressBar.setLayoutParams(params); 33 | linearLayout.addView(progressBar); 34 | 35 | setContentView(linearLayout); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_download.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_login.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 17 | 18 | 23 | 24 |