Commit bc416ae58356fb0dcfb8adef5b9ff87a3213f837

Authored by YangShuai
1 parent 31cde7c5

搭建网络请求框架

Showing 103 changed files with 5469 additions and 99 deletions
app/strike/build.gradle
@@ -11,7 +11,7 @@ android { @@ -11,7 +11,7 @@ android {
11 11
12 defaultConfig { 12 defaultConfig {
13 applicationId "com.cnlive.strike" 13 applicationId "com.cnlive.strike"
14 - minSdkVersion 16 14 + minSdkVersion 21
15 targetSdkVersion 29 15 targetSdkVersion 29
16 versionCode 1 16 versionCode 1
17 versionName "1.0" 17 versionName "1.0"
app/strike/src/main/AndroidManifest.xml
@@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
10 android:allowBackup="true" 10 android:allowBackup="true"
11 android:icon="@mipmap/ic_launcher" 11 android:icon="@mipmap/ic_launcher"
12 android:label="@string/app_name" 12 android:label="@string/app_name"
  13 + android:networkSecurityConfig="@xml/network_security_config"
13 android:roundIcon="@mipmap/ic_launcher_round" 14 android:roundIcon="@mipmap/ic_launcher_round"
14 android:supportsRtl="true" 15 android:supportsRtl="true"
15 android:theme="@style/AppTheme"> 16 android:theme="@style/AppTheme">
app/strike/src/main/java/com/cnlive/strike/MainActivity.java
1 package com.cnlive.strike; 1 package com.cnlive.strike;
2 2
3 3
4 -import android.content.Context;  
5 import android.content.Intent; 4 import android.content.Intent;
6 -import android.os.Bundle;  
7 -import android.util.AttributeSet; 5 +import android.os.Handler;
  6 +import android.util.Log;
8 import android.view.View; 7 import android.view.View;
9 8
10 -import androidx.annotation.NonNull;  
11 -import androidx.annotation.Nullable;  
12 -import androidx.appcompat.app.AppCompatActivity; 9 +import com.cnlive.core.libs.base.network.manager.SubscriptionManager;
  10 +import com.cnlive.core.network.request.BaseRequest;
  11 +import com.cnlive.core.libs.base.network.BaseResult;
  12 +import com.cnlive.core.libs.base.network.HttpConn;
  13 +import com.cnlive.core.libs.base.network.NetCallBack;
  14 +import com.cnlive.strike.network.api.ApiService;
  15 +import com.cnlive.strike.network.bean.LetHimNoSeeBean;
  16 +import com.cnlive.strike.network.bean.TestBean;
  17 +import com.cnlive.core.libs.base.frame.activity.BaseActivity;
13 18
14 -public class MainActivity extends AppCompatActivity { 19 +import java.util.HashMap;
  20 +import java.util.List;
  21 +import java.util.Map;
15 22
  23 +import io.reactivex.ObservableSource;
  24 +import io.reactivex.functions.Function;
  25 +
  26 +public class MainActivity extends BaseActivity {
  27 +
  28 +
  29 + @Override
  30 + protected int initLayout() {
  31 + return R.layout.activity_main;
  32 + }
16 33
17 @Override 34 @Override
18 - protected void onCreate(@Nullable Bundle savedInstanceState) {  
19 - super.onCreate(savedInstanceState);  
20 - setContentView(R.layout.activity_main);  
21 - findViewById(R.id.go_to).setOnClickListener(view -> startActivity(new Intent(this,MyActivity.class)) ); 35 + protected void initView() {
  36 +// findViewById(R.id.go_to).setOnClickListener(view -> startActivity(new Intent(this, MyActivity.class)));
  37 + findViewById(R.id.go_to).setOnClickListener(new View.OnClickListener() {
  38 + @Override
  39 + public void onClick(View v) {
  40 + startActivity(new Intent(MainActivity.this,MyActivity.class));
  41 +
  42 + }
  43 + });
  44 + }
22 45
  46 + @Override
  47 + protected void onPause() {
  48 + super.onPause();
  49 + SubscriptionManager.getInstance().cancelAll();
23 } 50 }
24 51
25 - @Nullable  
26 @Override 52 @Override
27 - public View onCreateView(@NonNull String name, @NonNull Context context, @NonNull AttributeSet attrs) {  
28 - return super.onCreateView(name, context, attrs); 53 + protected void initData() {
  54 +
29 } 55 }
30 } 56 }
app/strike/src/main/java/com/cnlive/strike/MyActivity.java
1 package com.cnlive.strike; 1 package com.cnlive.strike;
2 2
3 3
4 -import com.cnlive.libs.base.frame.activity.BaseActivity; 4 +import com.cnlive.core.libs.base.frame.activity.BaseActivity;
5 5
6 6
7 public class MyActivity extends BaseActivity { 7 public class MyActivity extends BaseActivity {
app/strike/src/main/java/com/cnlive/strike/MyActivityTest1.java
1 package com.cnlive.strike; 1 package com.cnlive.strike;
2 2
3 -import com.cnlive.libs.base.frame.activity.BaseActivity; 3 +import com.cnlive.core.libs.base.frame.activity.BaseActivity;
4 4
5 5
6 public class MyActivityTest1 extends BaseActivity { 6 public class MyActivityTest1 extends BaseActivity {
app/strike/src/main/java/com/cnlive/strike/MyApp.java
@@ -2,9 +2,18 @@ package com.cnlive.strike; @@ -2,9 +2,18 @@ package com.cnlive.strike;
2 2
3 import android.app.Application; 3 import android.app.Application;
4 4
  5 +import com.cnlive.core.libs.base.application.AppConfig;
  6 +
5 public class MyApp extends Application { 7 public class MyApp extends Application {
6 @Override 8 @Override
7 public void onCreate() { 9 public void onCreate() {
8 super.onCreate(); 10 super.onCreate();
  11 + AppConfig.init(this, BuildConfig.APP_ID, BuildConfig.APP_KEY,
  12 + BuildConfig.APP_SCERET, BuildConfig.SPECIAL_GROUP_MEMBER_LIMIT,
  13 + BuildConfig.VERSION_AS_DEBUG, "", "",
  14 + "10514333", "",
  15 + "", "", "",
  16 + "", "", "",
  17 + BuildConfig.BAIDU_MAP_APP_KEY, "");
9 } 18 }
10 } 19 }
app/strike/src/main/java/com/cnlive/strike/MyFragment.java
@@ -3,24 +3,44 @@ package com.cnlive.strike; @@ -3,24 +3,44 @@ package com.cnlive.strike;
3 3
4 import android.content.Intent; 4 import android.content.Intent;
5 import android.os.Bundle; 5 import android.os.Bundle;
  6 +import android.os.Handler;
  7 +import android.util.Log;
6 import android.view.LayoutInflater; 8 import android.view.LayoutInflater;
7 import android.view.View; 9 import android.view.View;
8 import android.view.ViewGroup; 10 import android.view.ViewGroup;
  11 +import android.widget.TextView;
9 12
10 -import com.cnlive.libs.base.frame.fragment.BaseFragment;  
11 -import com.cnlive.libs.base.util.StatusBarConfig; 13 +import com.cnlive.core.libs.base.frame.fragment.BaseFragment;
  14 +import com.cnlive.core.libs.base.network.BaseResult;
  15 +import com.cnlive.core.libs.base.network.HttpConn;
  16 +import com.cnlive.core.libs.base.network.NetCallBack;
  17 +import com.cnlive.core.libs.base.util.StatusBarConfig;
  18 +import com.cnlive.core.network.request.BaseRequest;
  19 +import com.cnlive.strike.network.api.ApiService;
  20 +import com.cnlive.strike.network.bean.LetHimNoSeeBean;
  21 +import com.cnlive.strike.network.bean.TestBean;
12 22
13 import androidx.annotation.NonNull; 23 import androidx.annotation.NonNull;
14 import androidx.annotation.Nullable; 24 import androidx.annotation.Nullable;
15 25
  26 +import java.util.HashMap;
  27 +import java.util.List;
  28 +import java.util.Map;
  29 +import java.util.concurrent.TimeUnit;
  30 +
  31 +import io.reactivex.ObservableSource;
  32 +import io.reactivex.functions.Function;
  33 +
16 34
17 public class MyFragment extends BaseFragment<MyFragmentView, MyPresenter> { 35 public class MyFragment extends BaseFragment<MyFragmentView, MyPresenter> {
18 private View view; 36 private View view;
  37 + public TextView textView;
19 38
20 @Nullable 39 @Nullable
21 @Override 40 @Override
22 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 41 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
23 view = inflater.inflate(R.layout.activity_main1, container, false); 42 view = inflater.inflate(R.layout.activity_main1, container, false);
  43 + textView = view.findViewById(R.id.tv1);
24 return view; 44 return view;
25 } 45 }
26 46
@@ -31,7 +51,58 @@ public class MyFragment extends BaseFragment&lt;MyFragmentView, MyPresenter&gt; { @@ -31,7 +51,58 @@ public class MyFragment extends BaseFragment&lt;MyFragmentView, MyPresenter&gt; {
31 view.findViewById(R.id.btn_test).setOnClickListener(new View.OnClickListener() { 51 view.findViewById(R.id.btn_test).setOnClickListener(new View.OnClickListener() {
32 @Override 52 @Override
33 public void onClick(View v) { 53 public void onClick(View v) {
34 - getActivity().startActivity(new Intent(getActivity(), MyActivityTest1.class)); 54 + //多个请求
  55 + HttpConn.action(
  56 + BaseRequest
  57 + .service(ApiService.class)
  58 + .getTest(), new NetCallBack<List<TestBean>>() {
  59 + @Override
  60 + public void onRequestState(int state) {
  61 +
  62 + }
  63 +
  64 + @Override
  65 + public void onSuccess(List<TestBean> data) {
  66 +
  67 + }
  68 +
  69 + @Override
  70 + public void onFailure(String errCode, String errMsg) {
  71 +
  72 + }
  73 + });
  74 + Map<String, String> param = new HashMap<>();
  75 + param.put("sid", "358916");
  76 + //多个请求
  77 + HttpConn.action(
  78 + BaseRequest.service(ApiService.class)
  79 + .getLetHimNoSee(param)
  80 + .flatMap(new Function<BaseResult<LetHimNoSeeBean>, ObservableSource<BaseResult<List<TestBean>>>>() {
  81 + @Override
  82 + public ObservableSource<BaseResult<List<TestBean>>> apply(BaseResult<LetHimNoSeeBean> letHimNoSeeBeanBaseResult) throws Exception {
  83 + Log.e(TAG, "apply: " + letHimNoSeeBeanBaseResult.getData().getDoNotletFsids().size());
  84 + return BaseRequest.service(ApiService.class).getTest();
  85 + }
  86 + })
  87 + , new NetCallBack<List<TestBean>>() {
  88 + @Override
  89 + public void onRequestState(int state) {
  90 + Log.e(TAG, "onRequestState: ");
  91 + }
  92 +
  93 + @Override
  94 + public void onSuccess(List<TestBean> data) {
  95 + Log.e(TAG, "onSuccess: " + data.size());
  96 + }
  97 +
  98 + @Override
  99 + public void onFailure(String errCode, String errMsg) {
  100 + Log.e(TAG, "onFailure: " + errMsg);
  101 +// textView.setText(errMsg);
  102 + getMvpView().setData(errMsg);
  103 +
  104 + }
  105 + });
35 } 106 }
36 }); 107 });
37 } 108 }
app/strike/src/main/java/com/cnlive/strike/MyFragment1.java
1 package com.cnlive.strike; 1 package com.cnlive.strike;
2 2
3 3
4 -import android.content.Intent;  
5 import android.os.Bundle; 4 import android.os.Bundle;
6 import android.view.LayoutInflater; 5 import android.view.LayoutInflater;
7 import android.view.View; 6 import android.view.View;
@@ -10,8 +9,8 @@ import android.view.ViewGroup; @@ -10,8 +9,8 @@ import android.view.ViewGroup;
10 import androidx.annotation.NonNull; 9 import androidx.annotation.NonNull;
11 import androidx.annotation.Nullable; 10 import androidx.annotation.Nullable;
12 11
13 -import com.cnlive.libs.base.frame.fragment.BaseFragment;  
14 -import com.cnlive.libs.base.util.StatusBarConfig; 12 +import com.cnlive.core.libs.base.frame.fragment.BaseFragment;
  13 +import com.cnlive.core.libs.base.util.StatusBarConfig;
15 14
16 15
17 public class MyFragment1 extends BaseFragment { 16 public class MyFragment1 extends BaseFragment {
app/strike/src/main/java/com/cnlive/strike/MyFragment1View.java
@@ -2,7 +2,7 @@ package com.cnlive.strike; @@ -2,7 +2,7 @@ package com.cnlive.strike;
2 2
3 import android.util.Log; 3 import android.util.Log;
4 4
5 -import com.cnlive.libs.base.frame.view.BaseView; 5 +import com.cnlive.core.libs.base.frame.view.BaseView;
6 6
7 public class MyFragment1View extends BaseView { 7 public class MyFragment1View extends BaseView {
8 // private MyFragment fragment; 8 // private MyFragment fragment;
app/strike/src/main/java/com/cnlive/strike/MyFragmentView.java
1 package com.cnlive.strike; 1 package com.cnlive.strike;
2 2
3 -import com.cnlive.libs.base.frame.view.BaseView; 3 +import com.cnlive.core.libs.base.frame.view.BaseView;
4 4
5 public class MyFragmentView extends BaseView { 5 public class MyFragmentView extends BaseView {
6 MyFragment fragment; 6 MyFragment fragment;
@@ -9,7 +9,7 @@ public class MyFragmentView extends BaseView { @@ -9,7 +9,7 @@ public class MyFragmentView extends BaseView {
9 this.fragment = fragment; 9 this.fragment = fragment;
10 } 10 }
11 11
12 - public void setData(String msg){  
13 -// fragment.tx.setText(msg); 12 + public void setData(String msg) {
  13 + fragment.textView.setText(msg);
14 } 14 }
15 } 15 }
app/strike/src/main/java/com/cnlive/strike/MyPresenter.java
1 package com.cnlive.strike; 1 package com.cnlive.strike;
2 2
3 -import com.cnlive.libs.base.frame.presenter.BasePresenter;  
4 -import com.hannesdorfmann.mosby3.mvp.MvpBasePresenter; 3 +import com.cnlive.core.libs.base.frame.presenter.BasePresenter;
5 4
6 public class MyPresenter extends BasePresenter<MyFragmentView> { 5 public class MyPresenter extends BasePresenter<MyFragmentView> {
7 public void setData(String msg) { 6 public void setData(String msg) {
app/strike/src/main/java/com/cnlive/strike/MyPresenter1.java
1 package com.cnlive.strike; 1 package com.cnlive.strike;
2 2
3 -import com.cnlive.libs.base.frame.presenter.BasePresenter; 3 +import com.cnlive.core.libs.base.frame.presenter.BasePresenter;
4 4
5 public class MyPresenter1 extends BasePresenter<MyFragment1View> { 5 public class MyPresenter1 extends BasePresenter<MyFragment1View> {
6 public void setData1(String msg) { 6 public void setData1(String msg) {
app/strike/src/main/java/com/cnlive/strike/network/api/ApiService.java 0 → 100644
  1 +package com.cnlive.strike.network.api;
  2 +
  3 +import com.cnlive.core.libs.base.network.BaseResult;
  4 +import com.cnlive.strike.network.bean.LetHimNoSeeBean;
  5 +import com.cnlive.strike.network.bean.TestBean;
  6 +
  7 +import java.util.List;
  8 +import java.util.Map;
  9 +
  10 +import io.reactivex.Observable;
  11 +import retrofit2.http.GET;
  12 +import retrofit2.http.POST;
  13 +import retrofit2.http.QueryMap;
  14 +
  15 +public interface ApiService {
  16 + @GET("福利/10/1")
  17 + Observable<BaseResult<List<TestBean>>> getTest();
  18 +
  19 + @POST("Daren/moment/getDoNotletFsids.action")
  20 + Observable<BaseResult<LetHimNoSeeBean>> getLetHimNoSee(@QueryMap() Map<String, String> maps);
  21 +}
app/strike/src/main/java/com/cnlive/strike/network/bean/LetHimNoSeeBean.java 0 → 100644
  1 +package com.cnlive.strike.network.bean;
  2 +
  3 +import java.util.List;
  4 +
  5 +public class LetHimNoSeeBean {
  6 +
  7 + private List<DoNotletFsidsBean> doNotletFsids;
  8 +
  9 + public List<DoNotletFsidsBean> getDoNotletFsids() {
  10 + return doNotletFsids;
  11 + }
  12 +
  13 + public void setDoNotletFsids(List<DoNotletFsidsBean> doNotletFsids) {
  14 + this.doNotletFsids = doNotletFsids;
  15 + }
  16 +
  17 + public static class DoNotletFsidsBean {
  18 + /**
  19 + * image : http://yweb0.cnliveimg.com/images/headImg/2018/1114/1542164956106_small.jpg
  20 + * nickName : 峨眉派掌门候选人
  21 + * userId : 10513196
  22 + */
  23 +
  24 + private String image;
  25 + private String nickName;
  26 + private String userId;
  27 +
  28 + public String getImage() {
  29 + return image;
  30 + }
  31 +
  32 + public void setImage(String image) {
  33 + this.image = image;
  34 + }
  35 +
  36 + public String getNickName() {
  37 + return nickName;
  38 + }
  39 +
  40 + public void setNickName(String nickName) {
  41 + this.nickName = nickName;
  42 + }
  43 +
  44 + public String getUserId() {
  45 + return userId;
  46 + }
  47 +
  48 + public void setUserId(String userId) {
  49 + this.userId = userId;
  50 + }
  51 + }
  52 +}
app/strike/src/main/java/com/cnlive/strike/network/bean/TestBean.java 0 → 100644
  1 +package com.cnlive.strike.network.bean;
  2 +
  3 +public class TestBean {
  4 +
  5 + /**
  6 + * _id : 5ccdbc219d212239df927a93
  7 + * createdAt : 2019-05-04T16:21:53.523Z
  8 + * desc : 2019-05-05
  9 + * publishedAt : 2019-05-04T16:21:59.733Z
  10 + * source : web
  11 + * type : 福利
  12 + * url : http://ww1.sinaimg.cn/large/0065oQSqly1g2pquqlp0nj30n00yiq8u.jpg
  13 + * used : true
  14 + * who : lijinshanmx
  15 + */
  16 +
  17 + private String _id;
  18 + private String createdAt;
  19 + private String desc;
  20 + private String publishedAt;
  21 + private String source;
  22 + private String type;
  23 + private String url;
  24 + private boolean used;
  25 + private String who;
  26 +
  27 + public String get_id() {
  28 + return _id;
  29 + }
  30 +
  31 + public void set_id(String _id) {
  32 + this._id = _id;
  33 + }
  34 +
  35 + public String getCreatedAt() {
  36 + return createdAt;
  37 + }
  38 +
  39 + public void setCreatedAt(String createdAt) {
  40 + this.createdAt = createdAt;
  41 + }
  42 +
  43 + public String getDesc() {
  44 + return desc;
  45 + }
  46 +
  47 + public void setDesc(String desc) {
  48 + this.desc = desc;
  49 + }
  50 +
  51 + public String getPublishedAt() {
  52 + return publishedAt;
  53 + }
  54 +
  55 + public void setPublishedAt(String publishedAt) {
  56 + this.publishedAt = publishedAt;
  57 + }
  58 +
  59 + public String getSource() {
  60 + return source;
  61 + }
  62 +
  63 + public void setSource(String source) {
  64 + this.source = source;
  65 + }
  66 +
  67 + public String getType() {
  68 + return type;
  69 + }
  70 +
  71 + public void setType(String type) {
  72 + this.type = type;
  73 + }
  74 +
  75 + public String getUrl() {
  76 + return url;
  77 + }
  78 +
  79 + public void setUrl(String url) {
  80 + this.url = url;
  81 + }
  82 +
  83 + public boolean isUsed() {
  84 + return used;
  85 + }
  86 +
  87 + public void setUsed(boolean used) {
  88 + this.used = used;
  89 + }
  90 +
  91 + public String getWho() {
  92 + return who;
  93 + }
  94 +
  95 + public void setWho(String who) {
  96 + this.who = who;
  97 + }
  98 +}
app/strike/src/main/res/layout/activity_main1.xml
1 <?xml version="1.0" encoding="utf-8"?> 1 <?xml version="1.0" encoding="utf-8"?>
2 <layout> 2 <layout>
3 3
4 - <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 4 + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
5 xmlns:app="http://schemas.android.com/apk/res-auto" 5 xmlns:app="http://schemas.android.com/apk/res-auto"
6 xmlns:tools="http://schemas.android.com/tools" 6 xmlns:tools="http://schemas.android.com/tools"
7 android:layout_width="match_parent" 7 android:layout_width="match_parent"
@@ -20,5 +20,5 @@ @@ -20,5 +20,5 @@
20 android:layout_width="wrap_content" 20 android:layout_width="wrap_content"
21 android:layout_height="wrap_content" 21 android:layout_height="wrap_content"
22 android:text="测试view" /> 22 android:text="测试view" />
23 - </RelativeLayout> 23 + </LinearLayout>
24 </layout> 24 </layout>
25 \ No newline at end of file 25 \ No newline at end of file
app/strike/src/main/res/xml/network_security_config.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<network-security-config>
  3 + <base-config cleartextTrafficPermitted="true">
  4 + <trust-anchors>
  5 + <certificates src="system" />
  6 + </trust-anchors>
  7 + </base-config>
  8 +</network-security-config>
config.gradle
@@ -71,6 +71,10 @@ ext { @@ -71,6 +71,10 @@ ext {
71 rxjava : 'io.reactivex.rxjava2:rxjava:2.2.9', 71 rxjava : 'io.reactivex.rxjava2:rxjava:2.2.9',
72 rxandroid : 'io.reactivex.rxjava2:rxandroid:2.1.1', 72 rxandroid : 'io.reactivex.rxjava2:rxandroid:2.1.1',
73 rxbinding : 'com.jakewharton.rxbinding:rxbinding:1.0.1', 73 rxbinding : 'com.jakewharton.rxbinding:rxbinding:1.0.1',
  74 + //rxlifecycle(管理Rxjava)
  75 + rxlifecycle : 'com.trello.rxlifecycle3:rxlifecycle:3.1.0',
  76 + rxlifecycle_android : 'com.trello.rxlifecycle3:rxlifecycle-android:3.1.0',
  77 + rxlifecycle_components : 'com.trello.rxlifecycle3:rxlifecycle-components:3.1.0',
74 //Retrofit 78 //Retrofit
75 retrofit : 'com.squareup.retrofit2:retrofit:2.6.0', 79 retrofit : 'com.squareup.retrofit2:retrofit:2.6.0',
76 retrofitConverterGson : 'com.squareup.retrofit2:converter-gson:2.6.0', 80 retrofitConverterGson : 'com.squareup.retrofit2:converter-gson:2.6.0',
@@ -108,10 +112,10 @@ ext { @@ -108,10 +112,10 @@ ext {
108 library.qmui, 112 library.qmui,
109 library.qmui_arch, 113 library.qmui_arch,
110 //mvp 114 //mvp
111 - library.mvp,  
112 - library.mvp_lce,  
113 - library.mvp_nullobject_presenter,  
114 - library.mvp_viewstate, 115 +// library.mvp,
  116 +// library.mvp_lce,
  117 +// library.mvp_nullobject_presenter,
  118 +// library.mvp_viewstate,
115 //图片加载Glide 119 //图片加载Glide
116 glide.api, 120 glide.api,
117 glide.transformations, 121 glide.transformations,
@@ -136,7 +140,8 @@ ext { @@ -136,7 +140,8 @@ ext {
136 library.okhttp, 140 library.okhttp,
137 library.okhttpLoggingInterceptor, 141 library.okhttpLoggingInterceptor,
138 library.greendao, 142 library.greendao,
139 - 143 + //管理rxjava生命周期
  144 +// library.rx
140 router.api, 145 router.api,
141 146
142 test.junit, 147 test.junit,
core/base/src/main/java/com/cnlive/libs/base/application/AppConfig.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/application/AppConfig.java
1 -package com.cnlive.libs.base.application; 1 +package com.cnlive.core.libs.base.application;
2 2
3 import android.content.Context; 3 import android.content.Context;
4 4
5 -import com.cnlive.libs.base.util.AppUtil;  
6 -import com.cnlive.libs.base.util.ChannelUtil;  
7 -import com.cnlive.libs.base.util.UUIDUtils; 5 +import com.cnlive.core.libs.base.util.AppUtil;
  6 +import com.cnlive.core.libs.base.util.ChannelUtil;
  7 +import com.cnlive.core.libs.base.util.UUIDUtils;
8 8
9 9
10 /** 10 /**
core/base/src/main/java/com/cnlive/libs/base/application/MyAppGlideModule.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/application/MyAppGlideModule.java
1 -package com.cnlive.libs.base.application; 1 +package com.cnlive.core.libs.base.application;
2 2
3 import com.bumptech.glide.annotation.GlideModule; 3 import com.bumptech.glide.annotation.GlideModule;
4 import com.bumptech.glide.module.AppGlideModule; 4 import com.bumptech.glide.module.AppGlideModule;
core/base/src/main/java/com/cnlive/libs/base/frame/activity/BaseActivity.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/frame/activity/BaseActivity.java
1 -package com.cnlive.libs.base.frame.activity; 1 +package com.cnlive.core.libs.base.frame.activity;
2 2
3 3
4 import android.annotation.SuppressLint; 4 import android.annotation.SuppressLint;
@@ -6,6 +6,7 @@ import android.content.Context; @@ -6,6 +6,7 @@ import android.content.Context;
6 import android.content.pm.ActivityInfo; 6 import android.content.pm.ActivityInfo;
7 import android.os.Bundle; 7 import android.os.Bundle;
8 import android.os.Looper; 8 import android.os.Looper;
  9 +import android.util.Log;
9 import android.view.View; 10 import android.view.View;
10 import android.view.Window; 11 import android.view.Window;
11 import android.view.WindowManager; 12 import android.view.WindowManager;
@@ -20,9 +21,10 @@ import androidx.core.content.ContextCompat; @@ -20,9 +21,10 @@ import androidx.core.content.ContextCompat;
20 import androidx.databinding.DataBindingUtil; 21 import androidx.databinding.DataBindingUtil;
21 import androidx.databinding.ViewDataBinding; 22 import androidx.databinding.ViewDataBinding;
22 23
23 -import com.cnlive.libs.base.util.StatusBarConfig;  
24 -import com.cnlive.libs.base.util.StatusBarUtil;  
25 -import com.cnlive.libs.base.util.ActivityCollector; 24 +import com.cnlive.core.libs.base.network.manager.SubscriptionManager;
  25 +import com.cnlive.core.libs.base.util.StatusBarConfig;
  26 +import com.cnlive.core.libs.base.util.StatusBarUtil;
  27 +import com.cnlive.core.libs.base.util.ActivityCollector;
26 28
27 /** 29 /**
28 * @author ys 30 * @author ys
@@ -49,6 +51,8 @@ public abstract class BaseActivity extends AppCompatActivity { @@ -49,6 +51,8 @@ public abstract class BaseActivity extends AppCompatActivity {
49 context = this; 51 context = this;
50 //activity管理 52 //activity管理
51 ActivityCollector.addActivity(this); 53 ActivityCollector.addActivity(this);
  54 + //创建订阅映射
  55 + SubscriptionManager.getInstance().setCurrentDisposables(TAG);
52 if (!isShowTitle) { 56 if (!isShowTitle) {
53 requestWindowFeature(Window.FEATURE_NO_TITLE); 57 requestWindowFeature(Window.FEATURE_NO_TITLE);
54 } 58 }
@@ -210,6 +214,8 @@ public abstract class BaseActivity extends AppCompatActivity { @@ -210,6 +214,8 @@ public abstract class BaseActivity extends AppCompatActivity {
210 super.onDestroy(); 214 super.onDestroy();
211 //activity管理 215 //activity管理
212 ActivityCollector.removeActivity(this); 216 ActivityCollector.removeActivity(this);
  217 + //清除所有订阅
  218 + SubscriptionManager.getInstance().cancel(TAG);
213 } 219 }
214 220
215 /** 221 /**
core/base/src/main/java/com/cnlive/libs/base/frame/activity/MvpActivity.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/frame/activity/MvpActivity.java
1 -package com.cnlive.libs.base.frame.activity; 1 +package com.cnlive.core.libs.base.frame.activity;
2 2
3 import android.os.Bundle; 3 import android.os.Bundle;
4 4
5 import androidx.annotation.NonNull; 5 import androidx.annotation.NonNull;
6 6
7 -import com.cnlive.libs.base.util.ReflectUtil; 7 +import com.cnlive.core.libs.base.util.ReflectUtil;
8 import com.hannesdorfmann.mosby3.mvp.MvpPresenter; 8 import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
9 import com.hannesdorfmann.mosby3.mvp.MvpView; 9 import com.hannesdorfmann.mosby3.mvp.MvpView;
10 10
core/base/src/main/java/com/cnlive/libs/base/frame/activity/MvpBindingActivity.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/frame/activity/MvpBindingActivity.java
1 -package com.cnlive.libs.base.frame.activity; 1 +package com.cnlive.core.libs.base.frame.activity;
2 2
3 import android.os.Bundle; 3 import android.os.Bundle;
4 4
@@ -6,7 +6,7 @@ import androidx.annotation.NonNull; @@ -6,7 +6,7 @@ import androidx.annotation.NonNull;
6 import androidx.databinding.DataBindingUtil; 6 import androidx.databinding.DataBindingUtil;
7 import androidx.databinding.ViewDataBinding; 7 import androidx.databinding.ViewDataBinding;
8 8
9 -import com.cnlive.libs.base.util.ReflectUtil; 9 +import com.cnlive.core.libs.base.util.ReflectUtil;
10 import com.hannesdorfmann.mosby3.mvp.MvpPresenter; 10 import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
11 import com.hannesdorfmann.mosby3.mvp.MvpView; 11 import com.hannesdorfmann.mosby3.mvp.MvpView;
12 12
@@ -17,7 +17,7 @@ import com.hannesdorfmann.mosby3.mvp.MvpView; @@ -17,7 +17,7 @@ import com.hannesdorfmann.mosby3.mvp.MvpView;
17 * @param <D> Databind Page Data 17 * @param <D> Databind Page Data
18 * @param <T> Databind Activity ViewDataBinding {@link ViewDataBinding} 18 * @param <T> Databind Activity ViewDataBinding {@link ViewDataBinding}
19 */ 19 */
20 -public abstract class MvpBindingActivity<V extends MvpView, P extends MvpPresenter<V>, D, T extends ViewDataBinding> extends com.cnlive.libs.base.frame.activity.MvpActivity<V, P> { 20 +public abstract class MvpBindingActivity<V extends MvpView, P extends MvpPresenter<V>, D, T extends ViewDataBinding> extends MvpActivity<V, P> {
21 21
22 public T binding; 22 public T binding;
23 public D data; 23 public D data;
core/base/src/main/java/com/cnlive/libs/base/frame/fragment/BaseFragment.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/frame/fragment/BaseFragment.java
1 -package com.cnlive.libs.base.frame.fragment; 1 +package com.cnlive.core.libs.base.frame.fragment;
2 2
3 import android.os.Bundle; 3 import android.os.Bundle;
4 import android.view.View; 4 import android.view.View;
@@ -9,11 +9,11 @@ import androidx.annotation.NonNull; @@ -9,11 +9,11 @@ import androidx.annotation.NonNull;
9 import androidx.annotation.Nullable; 9 import androidx.annotation.Nullable;
10 import androidx.core.content.ContextCompat; 10 import androidx.core.content.ContextCompat;
11 11
12 -import com.cnlive.libs.base.frame.presenter.BasePresenter;  
13 -import com.cnlive.libs.base.frame.view.BaseView;  
14 -import com.cnlive.libs.base.util.ReflectUtil;  
15 -import com.cnlive.libs.base.util.StatusBarConfig;  
16 -import com.cnlive.libs.base.util.StatusBarUtil; 12 +import com.cnlive.core.libs.base.frame.presenter.BasePresenter;
  13 +import com.cnlive.core.libs.base.util.ReflectUtil;
  14 +import com.cnlive.core.libs.base.frame.view.BaseView;
  15 +import com.cnlive.core.libs.base.util.StatusBarConfig;
  16 +import com.cnlive.core.libs.base.util.StatusBarUtil;
17 17
18 /** 18 /**
19 * 基类fragment 19 * 基类fragment
@@ -25,6 +25,7 @@ import com.cnlive.libs.base.util.StatusBarUtil; @@ -25,6 +25,7 @@ import com.cnlive.libs.base.util.StatusBarUtil;
25 public abstract class BaseFragment<V extends BaseView, P extends BasePresenter<V>> extends com.hannesdorfmann.mosby3.mvp.MvpFragment<V, P> { 25 public abstract class BaseFragment<V extends BaseView, P extends BasePresenter<V>> extends com.hannesdorfmann.mosby3.mvp.MvpFragment<V, P> {
26 public V view; 26 public V view;
27 public P presenter; 27 public P presenter;
  28 + protected final String TAG = this.getClass().getSimpleName();
28 29
29 @Override 30 @Override
30 public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 31 public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
core/base/src/main/java/com/cnlive/libs/base/frame/presenter/BasePresenter.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/frame/presenter/BasePresenter.java
1 -package com.cnlive.libs.base.frame.presenter; 1 +package com.cnlive.core.libs.base.frame.presenter;
2 2
3 -import com.cnlive.libs.base.frame.view.BaseView; 3 +import com.cnlive.core.libs.base.frame.view.BaseView;
4 import com.hannesdorfmann.mosby3.mvp.MvpBasePresenter; 4 import com.hannesdorfmann.mosby3.mvp.MvpBasePresenter;
5 5
6 public class BasePresenter<V extends BaseView> extends MvpBasePresenter<V> { 6 public class BasePresenter<V extends BaseView> extends MvpBasePresenter<V> {
core/base/src/main/java/com/cnlive/libs/base/frame/view/BaseView.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/frame/view/BaseView.java
1 -package com.cnlive.libs.base.frame.view; 1 +package com.cnlive.core.libs.base.frame.view;
2 2
3 import com.hannesdorfmann.mosby3.mvp.MvpView; 3 import com.hannesdorfmann.mosby3.mvp.MvpView;
4 4
core/base/src/main/java/com/cnlive/core/libs/base/network/BaseResult.java 0 → 100644
  1 +package com.cnlive.core.libs.base.network;
  2 +
  3 +/**
  4 + * 返回参数基类
  5 + *
  6 + * @param <T>
  7 + */
  8 +public class BaseResult<T> {
  9 + private static final String CODE_SUCCESS = "0";//响应成功的code
  10 + private String errorCode;
  11 + private String errorMessage;
  12 + private T data;
  13 +
  14 + public boolean isSuccess() {
  15 + return CODE_SUCCESS.equals(errorCode);
  16 + }
  17 +
  18 + public String getErrorCode() {
  19 + return errorCode;
  20 + }
  21 +
  22 + public void setErrorCode(String errorCode) {
  23 + this.errorCode = errorCode;
  24 + }
  25 +
  26 + public String getErrorMessage() {
  27 + return errorMessage;
  28 + }
  29 +
  30 + public void setErrorMessage(String errorMessage) {
  31 + this.errorMessage = errorMessage;
  32 + }
  33 +
  34 + public T getData() {
  35 + return data;
  36 + }
  37 +
  38 + public void setData(T data) {
  39 + this.data = data;
  40 + }
  41 +
  42 +//private static int SUCCESS_CODE=000000;//成功的code
  43 +// private int code;
  44 +// private String message;
  45 +// private T results;
  46 +// private boolean error;
  47 +//
  48 +// public boolean isSuccess(){
  49 +// return getCode()==SUCCESS_CODE;
  50 +// }
  51 +// public int getCode() {
  52 +// return code;
  53 +// }
  54 +//
  55 +// public void setCode(int code) {
  56 +// this.code = code;
  57 +// }
  58 +//
  59 +// public String getMessage() {
  60 +// return message;
  61 +// }
  62 +//
  63 +// public void setMessage(String message) {
  64 +// this.message = message;
  65 +// }
  66 +//
  67 +// public T getResults() {
  68 +// return results;
  69 +// }
  70 +//
  71 +// public void setResults(T results) {
  72 +// this.results = results;
  73 +// }
  74 +//
  75 +// public boolean isError() {
  76 +// return error;
  77 +// }
  78 +//
  79 +// public void setError(boolean error) {
  80 +// this.error = error;
  81 +// }
  82 +//
  83 +// @Override
  84 +// public String toString() {
  85 +// return super.toString();
  86 +// }
  87 +}
core/base/src/main/java/com/cnlive/core/libs/base/network/HttpConn.java 0 → 100644
  1 +package com.cnlive.core.libs.base.network;
  2 +
  3 +import android.util.Log;
  4 +
  5 +import com.cnlive.core.libs.base.network.manager.SubscriptionManager;
  6 +
  7 +import io.reactivex.Observable;
  8 +import io.reactivex.android.schedulers.AndroidSchedulers;
  9 +import io.reactivex.disposables.Disposable;
  10 +import io.reactivex.functions.Consumer;
  11 +import io.reactivex.functions.Function;
  12 +import io.reactivex.schedulers.Schedulers;
  13 +
  14 +public class HttpConn {
  15 + public static final int ON_START = 0;
  16 + public static final int ON_END = 1;
  17 +
  18 + public static HttpConn create() {
  19 + return new HttpConn();
  20 + }
  21 +
  22 + private static final String EXCEPTION_CODE = "-1";//异常
  23 +
  24 +
  25 + /**
  26 + * 统一处理单个请求
  27 + *
  28 + * @param observable
  29 + * @param callBack
  30 + * @param <T>
  31 + */
  32 + public static <T> Disposable action(Observable<BaseResult<T>> observable, final NetCallBack<T> callBack) {
  33 + Disposable disposable = null;
  34 + disposable = observable
  35 + .subscribeOn(Schedulers.io())
  36 + .observeOn(AndroidSchedulers.mainThread())
  37 + .doOnSubscribe(new Consumer<Disposable>() {
  38 + @Override
  39 + public void accept(Disposable disposable) throws Exception {
  40 + if (null != callBack) {
  41 + callBack.onRequestState(ON_START);
  42 + }
  43 + }
  44 + })
  45 + .doOnNext(new Consumer<BaseResult<T>>() {
  46 + @Override
  47 + public void accept(BaseResult<T> tBaseResult) throws Exception {
  48 + if (null != callBack) {
  49 + callBack.onRequestState(ON_END);
  50 + }
  51 + }
  52 + })
  53 + .onErrorReturn(new Function<Throwable, BaseResult<T>>() {
  54 + @Override
  55 + public BaseResult<T> apply(Throwable throwable) {
  56 + Log.e("Sdf", "apply: " + throwable.toString());
  57 + if (null != callBack) {
  58 + callBack.onFailure(EXCEPTION_CODE, throwable.toString());
  59 + }
  60 + return null;
  61 + }
  62 + })
  63 + .subscribe(new Consumer<BaseResult<T>>() {
  64 + @Override
  65 + public void accept(BaseResult<T> tBaseResponse) {
  66 + if (tBaseResponse.isSuccess()) {
  67 + if (null != callBack) {
  68 + callBack.onSuccess(tBaseResponse.getData());
  69 + }
  70 + } else {
  71 + if (null != callBack) {
  72 + callBack.onFailure(tBaseResponse.getErrorCode(), tBaseResponse.getErrorMessage());
  73 + }
  74 + }
  75 + }
  76 + }, new Consumer<Throwable>() {
  77 + @Override
  78 + public void accept(Throwable throwable) {
  79 +// if (null != callBack) {
  80 +// callBack.onFailure(EXCEPTION_CODE, throwable.getMessage());
  81 +// }
  82 +// Log.e("LinNetError", "单个请求的错误" + throwable.getMessage());
  83 + }
  84 + });
  85 + if (null != disposable) {
  86 + SubscriptionManager.getInstance().add(disposable);
  87 + }
  88 + return disposable;
  89 + }
  90 +
  91 +
  92 +}
core/base/src/main/java/com/cnlive/core/libs/base/network/NetCallBack.java 0 → 100644
  1 +package com.cnlive.core.libs.base.network;
  2 +
  3 +public interface NetCallBack<T> {
  4 + void onRequestState(int state);
  5 +
  6 +
  7 + /**
  8 + * 数据请求成功
  9 + *
  10 + * @param data 请求到的数据
  11 + */
  12 + void onSuccess(T data);
  13 +
  14 + /**
  15 + * 数据请求失败
  16 + */
  17 + void onFailure(String errCode, String errMsg);
  18 +
  19 +}
core/base/src/main/java/com/cnlive/core/libs/base/network/manager/SubscriptionManager.java 0 → 100644
  1 +package com.cnlive.core.libs.base.network.manager;
  2 +
  3 +
  4 +import android.text.TextUtils;
  5 +import android.util.Log;
  6 +
  7 +import java.util.HashMap;
  8 +
  9 +import io.reactivex.disposables.CompositeDisposable;
  10 +import io.reactivex.disposables.Disposable;
  11 +
  12 +public class SubscriptionManager {
  13 + public static SubscriptionManager instance;
  14 + // private CompositeDisposable mDisposables;//存放disposable容器
  15 + public HashMap<String, CompositeDisposable> hashDisposable;
  16 + public HashMap<Integer, String> hashTag;
  17 + private String currentClassName;
  18 +
  19 + /**
  20 + * 构造函数 new CompositeDisposable对象
  21 + */
  22 + public SubscriptionManager() {
  23 +// if (mDisposables == null) {
  24 +// mDisposables = new CompositeDisposable();
  25 +// }
  26 + if (null == hashDisposable) {
  27 + hashDisposable = new HashMap<>();
  28 + }
  29 + if (null == hashTag) {
  30 + hashTag = new HashMap<>();
  31 + }
  32 + }
  33 +
  34 + /**
  35 + * 单例
  36 + *
  37 + * @return
  38 + */
  39 + public static SubscriptionManager getInstance() {
  40 + if (instance == null) {
  41 + synchronized (SubscriptionManager.class) {
  42 + if (instance == null) {
  43 + instance = new SubscriptionManager();
  44 + }
  45 + }
  46 + }
  47 + return instance;
  48 + }
  49 +
  50 + public void setCurrentDisposables(String TAG) {
  51 + if (null == hashDisposable.get(TAG)) {
  52 + currentClassName = TAG;
  53 + hashDisposable.put(TAG, new CompositeDisposable());
  54 + //存放当前class映射
  55 + hashTag.put(hashDisposable.size() - 1, TAG);
  56 + }
  57 + }
  58 +
  59 + /**
  60 + * 取消订阅事件
  61 + */
  62 + public void cancel(String TAG) {
  63 + if (null != hashDisposable && hashDisposable.size() > 0) {
  64 + if (null != hashDisposable.get(TAG) && hashDisposable.get(TAG).size() > 0) {
  65 + CompositeDisposable mDisposables = hashDisposable.get(TAG);
  66 + if (!mDisposables.isDisposed()) {
  67 + Log.e(TAG, "cancel: 解除订阅");
  68 + mDisposables.clear();
  69 + }
  70 + }
  71 + }
  72 + }
  73 +
  74 + /**
  75 + * 订阅事件加入到CompositeDisposable容器中
  76 + *
  77 + * @param disposable 订阅事件
  78 + */
  79 + public void add(Disposable disposable) {
  80 + if (disposable == null) return;
  81 + if (null != hashDisposable && hashDisposable.size() > 0) {
  82 + if (!TextUtils.isEmpty(currentClassName)) {
  83 + if (null != hashDisposable.get(currentClassName)) {
  84 + //存放当前activity对应的订阅
  85 + hashDisposable.get(currentClassName).add(disposable);
  86 + Log.e(currentClassName, "add: 添加订阅");
  87 + }
  88 + }
  89 + }
  90 + }
  91 +
  92 +// /**
  93 +// * 取消订阅事件
  94 +// *
  95 +// * @param disposable 订阅事件
  96 +// */
  97 +// public void cancel(Disposable disposable) {
  98 +// if (disposable != null) {
  99 +// mDisposables.delete(disposable);
  100 +// }
  101 +// }
  102 +
  103 + /**
  104 + * 清除容器所有
  105 + */
  106 + public void cancelAll() {
  107 + //解除所有订阅
  108 + if (null != hashDisposable && hashDisposable.size() > 0) {
  109 + if (null != hashTag && hashTag.size() > 0) {
  110 + for (int i = 0; i < hashTag.size(); i++) {
  111 + if (null != hashTag.get(i)) {
  112 + if (null != hashDisposable.get(hashTag.get(i))) {
  113 + hashDisposable.get(hashTag.get(i)).clear();
  114 + }
  115 + }
  116 + }
  117 + }
  118 + }
  119 + }
  120 +}
core/base/src/main/java/com/cnlive/libs/base/util/ActivityCollector.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/ActivityCollector.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.app.Activity; 3 import android.app.Activity;
4 4
core/base/src/main/java/com/cnlive/libs/base/util/AppUtil.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/AppUtil.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.app.Activity; 3 import android.app.Activity;
4 import android.app.ActivityManager; 4 import android.app.ActivityManager;
core/base/src/main/java/com/cnlive/libs/base/util/BrandUtils.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/BrandUtils.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.os.Build; 3 import android.os.Build;
4 import android.os.Environment; 4 import android.os.Environment;
core/base/src/main/java/com/cnlive/libs/base/util/ChannelUtil.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/ChannelUtil.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.content.Context; 3 import android.content.Context;
4 import android.content.pm.ApplicationInfo; 4 import android.content.pm.ApplicationInfo;
@@ -6,7 +6,7 @@ import android.content.pm.PackageManager; @@ -6,7 +6,7 @@ import android.content.pm.PackageManager;
6 import android.text.TextUtils; 6 import android.text.TextUtils;
7 import android.util.Log; 7 import android.util.Log;
8 8
9 -import com.cnlive.libs.base.application.AppConfig; 9 +import com.cnlive.core.libs.base.application.AppConfig;
10 10
11 /** 11 /**
12 * Created by xiansong on 2014/12/26. 12 * Created by xiansong on 2014/12/26.
core/base/src/main/java/com/cnlive/libs/base/util/CheckUtil.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/CheckUtil.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.app.Activity; 3 import android.app.Activity;
4 import android.content.Intent; 4 import android.content.Intent;
core/base/src/main/java/com/cnlive/libs/base/util/DESUtil.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/DESUtil.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.util.Base64; 3 import android.util.Base64;
4 4
core/base/src/main/java/com/cnlive/libs/base/util/DensityUtils.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/DensityUtils.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 /** 3 /**
4 * Created by vclub on 15/5/15. 4 * Created by vclub on 15/5/15.
core/base/src/main/java/com/cnlive/libs/base/util/DoublePressed.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/DoublePressed.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 public class DoublePressed { 3 public class DoublePressed {
4 private static long time_pressed; 4 private static long time_pressed;
core/base/src/main/java/com/cnlive/libs/base/util/ExtractVideoInfoUtil.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/ExtractVideoInfoUtil.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.graphics.Bitmap; 3 import android.graphics.Bitmap;
4 import android.media.MediaMetadataRetriever; 4 import android.media.MediaMetadataRetriever;
core/base/src/main/java/com/cnlive/libs/base/util/FileTypeUtil.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/FileTypeUtil.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.text.TextUtils; 3 import android.text.TextUtils;
4 4
core/base/src/main/java/com/cnlive/libs/base/util/FileUtils.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/FileUtils.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.content.Context; 3 import android.content.Context;
4 import android.content.pm.PackageManager; 4 import android.content.pm.PackageManager;
core/base/src/main/java/com/cnlive/libs/base/util/GlideCacheUtil.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/GlideCacheUtil.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.content.Context; 3 import android.content.Context;
4 import android.os.Looper; 4 import android.os.Looper;
core/base/src/main/java/com/cnlive/libs/base/util/GlideRoundedCornersTransform.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/GlideRoundedCornersTransform.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.graphics.Bitmap; 3 import android.graphics.Bitmap;
4 import android.graphics.BitmapShader; 4 import android.graphics.BitmapShader;
core/base/src/main/java/com/cnlive/libs/base/util/GlideUtil.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/GlideUtil.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.content.Context; 3 import android.content.Context;
4 import android.graphics.Bitmap; 4 import android.graphics.Bitmap;
@@ -11,9 +11,9 @@ import android.widget.ImageView; @@ -11,9 +11,9 @@ import android.widget.ImageView;
11 11
12 import com.bumptech.glide.request.RequestOptions; 12 import com.bumptech.glide.request.RequestOptions;
13 import com.bumptech.glide.request.target.ViewTarget; 13 import com.bumptech.glide.request.target.ViewTarget;
14 -import com.cnlive.libs.base.application.GlideApp;  
15 -import com.cnlive.libs.base.application.GlideRequest;  
16 -import com.cnlive.libs.base.application.GlideRequests; 14 +import com.cnlive.core.libs.base.application.GlideApp;
  15 +import com.cnlive.core.libs.base.application.GlideRequest;
  16 +import com.cnlive.core.libs.base.application.GlideRequests;
17 17
18 public class GlideUtil { 18 public class GlideUtil {
19 19
core/base/src/main/java/com/cnlive/libs/base/util/GsonUtil.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/GsonUtil.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import com.google.gson.Gson; 3 import com.google.gson.Gson;
4 import com.google.gson.JsonArray; 4 import com.google.gson.JsonArray;
core/base/src/main/java/com/cnlive/libs/base/util/ImagePickerComUtils.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/ImagePickerComUtils.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.app.Activity; 3 import android.app.Activity;
4 import android.content.Context; 4 import android.content.Context;
core/base/src/main/java/com/cnlive/libs/base/util/LogUtil.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/LogUtil.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.util.Log; 3 import android.util.Log;
4 4
5 -import com.cnlive.libs.base.application.AppConfig; 5 +import com.cnlive.core.libs.base.application.AppConfig;
6 6
7 public class LogUtil { 7 public class LogUtil {
8 private static boolean ENABLED = AppConfig.isDebug(); 8 private static boolean ENABLED = AppConfig.isDebug();
core/base/src/main/java/com/cnlive/libs/base/util/MD5Util.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/MD5Util.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import java.io.File; 3 import java.io.File;
4 import java.io.FileInputStream; 4 import java.io.FileInputStream;
core/base/src/main/java/com/cnlive/libs/base/util/NetworkUtil.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/NetworkUtil.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.content.Context; 3 import android.content.Context;
4 import android.net.ConnectivityManager; 4 import android.net.ConnectivityManager;
core/base/src/main/java/com/cnlive/libs/base/util/PictureUtils.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/PictureUtils.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.content.Context; 3 import android.content.Context;
4 import android.graphics.Bitmap; 4 import android.graphics.Bitmap;
core/base/src/main/java/com/cnlive/libs/base/util/QMUITipDialogUtil.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/QMUITipDialogUtil.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.content.Context; 3 import android.content.Context;
4 import android.os.Handler; 4 import android.os.Handler;
core/base/src/main/java/com/cnlive/libs/base/util/ReflectUtil.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/ReflectUtil.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 3
4 import android.util.Log; 4 import android.util.Log;
core/base/src/main/java/com/cnlive/libs/base/util/ScreenUtil.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/ScreenUtil.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.content.Context; 3 import android.content.Context;
4 import android.view.WindowManager; 4 import android.view.WindowManager;
core/base/src/main/java/com/cnlive/libs/base/util/Sha1Util.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/Sha1Util.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.content.Context; 3 import android.content.Context;
4 import android.content.pm.PackageInfo; 4 import android.content.pm.PackageInfo;
core/base/src/main/java/com/cnlive/libs/base/util/SharedPreferencesHelper.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/SharedPreferencesHelper.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.content.Context; 3 import android.content.Context;
4 import android.content.SharedPreferences; 4 import android.content.SharedPreferences;
core/base/src/main/java/com/cnlive/libs/base/util/StatusBarConfig.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/StatusBarConfig.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 public class StatusBarConfig { 3 public class StatusBarConfig {
4 public static final int WHITE = 0;//白色 4 public static final int WHITE = 0;//白色
core/base/src/main/java/com/cnlive/libs/base/util/StatusBarUtil.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/StatusBarUtil.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.annotation.TargetApi; 3 import android.annotation.TargetApi;
4 import android.app.Activity; 4 import android.app.Activity;
core/base/src/main/java/com/cnlive/libs/base/util/StringUtils.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/StringUtils.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.annotation.TargetApi; 3 import android.annotation.TargetApi;
4 import android.nfc.NdefRecord; 4 import android.nfc.NdefRecord;
@@ -7,7 +7,6 @@ import android.text.TextPaint; @@ -7,7 +7,6 @@ import android.text.TextPaint;
7 import android.util.Base64; 7 import android.util.Base64;
8 import android.util.Log; 8 import android.util.Log;
9 9
10 -import java.io.UnsupportedEncodingException;  
11 import java.net.URLDecoder; 10 import java.net.URLDecoder;
12 import java.net.URLEncoder; 11 import java.net.URLEncoder;
13 import java.nio.charset.Charset; 12 import java.nio.charset.Charset;
core/base/src/main/java/com/cnlive/libs/base/util/TimerUtil.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/TimerUtil.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.os.Handler; 3 import android.os.Handler;
4 import android.os.Message; 4 import android.os.Message;
core/base/src/main/java/com/cnlive/libs/base/util/UUIDUtils.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/UUIDUtils.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.annotation.SuppressLint; 3 import android.annotation.SuppressLint;
4 import android.content.Context; 4 import android.content.Context;
core/base/src/main/java/com/cnlive/libs/base/util/WebPreviewShowImg.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/WebPreviewShowImg.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 /** 3 /**
4 * 作者: 吴奎庆 4 * 作者: 吴奎庆
core/base/src/main/java/com/cnlive/libs/base/util/WebViewUtil.java renamed to core/base/src/main/java/com/cnlive/core/libs/base/util/WebViewUtil.java
1 -package com.cnlive.libs.base.util; 1 +package com.cnlive.core.libs.base.util;
2 2
3 import android.app.Activity; 3 import android.app.Activity;
4 import android.text.TextUtils; 4 import android.text.TextUtils;
core/base/src/main/java/com/hannesdorfmann/mosby3/ActivityScopedCache.java 0 → 100644
  1 +/*
  2 + * Copyright 2017 Hannes Dorfmann.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + *
  16 + */
  17 +
  18 +package com.hannesdorfmann.mosby3;
  19 +
  20 +import android.os.Build;
  21 +import android.util.ArrayMap;
  22 +
  23 +import androidx.annotation.NonNull;
  24 +import androidx.annotation.Nullable;
  25 +import androidx.annotation.RequiresApi;
  26 +
  27 +import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
  28 +import com.hannesdorfmann.mosby3.mvp.MvpView;
  29 +import java.util.Map;
  30 +
  31 +/**
  32 + * This class basically represents a Map for View Id to the Presenter / ViewState.
  33 + * One instance of this class is also associated by {@link PresenterManager} to one Activity (kept
  34 + * across screen orientation changes)
  35 + *
  36 + * @author Hannes Dorfmann
  37 + * @since 3.0.0
  38 + */
  39 +@RequiresApi(api = Build.VERSION_CODES.KITKAT)
  40 +class ActivityScopedCache {
  41 +
  42 + private final Map<String, PresenterHolder> presenterMap = new ArrayMap<>();
  43 +
  44 + ActivityScopedCache() {
  45 + // package private
  46 + }
  47 +
  48 + public void clear() {
  49 + /*
  50 + // TODO: can this check if there are still Presenters in the internal cache that must be detached? Maybe post() / postDelayed() on the MainThreadLooper()
  51 + // it doesnt work out that well, because super.onDestroy() which then invokes PresenterManager.clear() might be called before the MviDelegates did their job to remove the Presenter from cache and detach the view permanently
  52 +
  53 + for (PresenterHolder holder : presenterMap.values()) {
  54 + // This should never be the case: If there were some presenters left in the internal cache,
  55 + // a delegate didn't work correctly as expected
  56 + if (holder.presenter != null) {
  57 + holder.presenter.detachView(false);
  58 + if (PresenterManager.DEBUG) {
  59 + Log.w(PresenterManager.DEBUG_TAG,
  60 + "Found a Presenter that is still alive. This should never happen. It seems that a MvpDelegate / MviDelegate didn't work correctly because this Delegate should have removed the presenter. The Presenter was "
  61 + + holder.presenter);
  62 + }
  63 + }
  64 + }
  65 + */
  66 + presenterMap.clear();
  67 + }
  68 +
  69 + /**
  70 + * Get the Presenter for a given {@link MvpView} if exists or <code>null</code>
  71 + *
  72 + * @param viewId The mosby internal view id
  73 + * @param <P> The type tof the {@link MvpPresenter}
  74 + * @return The Presenter for the given view id or <code>null</code>
  75 + */
  76 + @Nullable
  77 + public <P> P getPresenter(@NonNull String viewId) {
  78 + PresenterHolder holder = presenterMap.get(viewId);
  79 + return holder == null ? null : (P) holder.presenter;
  80 + }
  81 +
  82 + /**
  83 + * Get the ViewState for a given {@link MvpView} if exists or <code>null</code>
  84 + *
  85 + * @param viewId The mosby internal view id
  86 + * @param <VS> The type tof the {@link MvpPresenter}
  87 + * @return The ViewState for the given view id or <code>null</code>
  88 + */
  89 + @Nullable public <VS> VS getViewState(@NonNull String viewId) {
  90 + PresenterHolder holder = presenterMap.get(viewId);
  91 + return holder == null ? null : (VS) holder.viewState;
  92 + }
  93 +
  94 + /**
  95 + * Put the presenter in the internal cache
  96 + *
  97 + * @param viewId The mosby internal View id of the {@link MvpView} which the presenter is
  98 + * associated to.
  99 + * @param presenter The Presenter
  100 + */
  101 + public void putPresenter(@NonNull String viewId,
  102 + @NonNull MvpPresenter<? extends MvpView> presenter) {
  103 +
  104 + if (viewId == null) {
  105 + throw new NullPointerException("ViewId is null");
  106 + }
  107 +
  108 + if (presenter == null) {
  109 + throw new NullPointerException("Presenter is null");
  110 + }
  111 +
  112 + PresenterHolder presenterHolder = presenterMap.get(viewId);
  113 + if (presenterHolder == null) {
  114 + presenterHolder = new PresenterHolder();
  115 + presenterHolder.presenter = presenter;
  116 + presenterMap.put(viewId, presenterHolder);
  117 + } else {
  118 + presenterHolder.presenter = presenter;
  119 + }
  120 + }
  121 +
  122 +
  123 + /**
  124 + * Put the viewstate in the internal cache
  125 + *
  126 + * @param viewId The mosby internal View id of the {@link MvpView} which the presenter is
  127 + * associated to.
  128 + * @param viewState The Viewstate
  129 + */
  130 + public void putViewState(@NonNull String viewId,
  131 + @NonNull Object viewState) {
  132 +
  133 + if (viewId == null) {
  134 + throw new NullPointerException("ViewId is null");
  135 + }
  136 +
  137 + if (viewState == null) {
  138 + throw new NullPointerException("ViewState is null");
  139 + }
  140 +
  141 + PresenterHolder presenterHolder = presenterMap.get(viewId);
  142 + if (presenterHolder == null) {
  143 + presenterHolder = new PresenterHolder();
  144 + presenterHolder.viewState = viewState;
  145 + presenterMap.put(viewId, presenterHolder);
  146 + } else {
  147 + presenterHolder.viewState = viewState;
  148 + }
  149 + }
  150 +
  151 + /**
  152 + * Removes the Presenter (and ViewState) from the internal storage
  153 + *
  154 + * @param viewId The msoby internal view id
  155 + */
  156 + public void remove(@NonNull String viewId) {
  157 +
  158 + if (viewId == null) {
  159 + throw new NullPointerException("View Id is null");
  160 + }
  161 +
  162 + presenterMap.remove(viewId);
  163 + }
  164 +
  165 + /**
  166 + * Internal config change Cache entry
  167 + */
  168 + static final class PresenterHolder {
  169 + private MvpPresenter<?> presenter;
  170 + private Object viewState; // workaround: didn't want to introduce dependency to viewstate module
  171 + }
  172 +}
core/base/src/main/java/com/hannesdorfmann/mosby3/MosbySavedState.java 0 → 100644
  1 +/*
  2 + * Copyright 2016 Hannes Dorfmann.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + *
  16 + */
  17 +package com.hannesdorfmann.mosby3;
  18 +
  19 +import android.os.Build;
  20 +import android.os.Parcel;
  21 +import android.os.Parcelable;
  22 +import android.view.AbsSavedState;
  23 +
  24 +import androidx.annotation.RequiresApi;
  25 +import androidx.core.os.ParcelableCompat;
  26 +import androidx.core.os.ParcelableCompatCreatorCallbacks;
  27 +
  28 +/**
  29 + * The SavedState implementation to store the view's internal id to
  30 + *
  31 + * @author Hannes Dorfmann
  32 + * @since 3.0
  33 + */
  34 +public class MosbySavedState extends AbsSavedState {
  35 +
  36 + public static final Creator<MosbySavedState> CREATOR =
  37 + ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<MosbySavedState>() {
  38 + public MosbySavedState createFromParcel(Parcel in, ClassLoader loader) {
  39 + if (loader == null) {
  40 + loader = MosbySavedState.class.getClassLoader();
  41 + }
  42 + return new MosbySavedState(in, loader);
  43 + }
  44 +
  45 + public MosbySavedState[] newArray(int size) {
  46 + return new MosbySavedState[size];
  47 + }
  48 + });
  49 +
  50 + private String mosbyViewId;
  51 +
  52 + public MosbySavedState(Parcelable superState, String mosbyViewId) {
  53 + super(superState);
  54 + this.mosbyViewId = mosbyViewId;
  55 + }
  56 +
  57 + protected MosbySavedState(Parcel in, ClassLoader loader) {
  58 + super(in, loader);
  59 + this.mosbyViewId = in.readString();
  60 + }
  61 +
  62 + @Override public void writeToParcel(Parcel out, int flags) {
  63 + super.writeToParcel(out, flags);
  64 + out.writeString(mosbyViewId);
  65 + }
  66 +
  67 + public String getMosbyViewId() {
  68 + return mosbyViewId;
  69 + }
  70 +
  71 +}
core/base/src/main/java/com/hannesdorfmann/mosby3/PresenterManager.java 0 → 100644
  1 +package com.hannesdorfmann.mosby3;
  2 +
  3 +import android.app.Activity;
  4 +import android.app.Application;
  5 +import android.content.Context;
  6 +import android.content.ContextWrapper;
  7 +import android.os.Build;
  8 +import android.os.Bundle;
  9 +import android.util.ArrayMap;
  10 +import android.util.Log;
  11 +import android.view.View;
  12 +
  13 +import androidx.annotation.MainThread;
  14 +import androidx.annotation.NonNull;
  15 +import androidx.annotation.Nullable;
  16 +import androidx.annotation.RequiresApi;
  17 +
  18 +import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
  19 +import com.hannesdorfmann.mosby3.mvp.MvpView;
  20 +import java.util.Map;
  21 +import java.util.UUID;
  22 +
  23 +/**
  24 + * A internal class responsible to save internal presenter instances during screen orientation
  25 + * changes and reattach the presenter afterwards.
  26 + *
  27 + * <p>
  28 + * The idea is that each MVP View (like a Activity, Fragment, ViewGroup) will get a unique view id.
  29 + * This view id is
  30 + * used to store the presenter and viewstate in it. After screen orientation changes we can reuse
  31 + * the presenter and viewstate by querying for the given view id (must be saved in view's state
  32 + * somehow).
  33 + * </p>
  34 + *
  35 + * @author Hannes Dorfmann
  36 + * @since 3.0
  37 + */
  38 +@RequiresApi(api = Build.VERSION_CODES.KITKAT)
  39 +final public class PresenterManager {
  40 +
  41 + public static boolean DEBUG = false;
  42 + public static final String DEBUG_TAG = "PresenterManager";
  43 + final static String KEY_ACTIVITY_ID = "com.hannesdorfmann.mosby3.MosbyPresenterManagerActivityId";
  44 +
  45 + private final static Map<Activity, String> activityIdMap = new ArrayMap<>();
  46 + private final static Map<String, ActivityScopedCache> activityScopedCacheMap = new ArrayMap<>();
  47 +
  48 + static final Application.ActivityLifecycleCallbacks activityLifecycleCallbacks =
  49 + new Application.ActivityLifecycleCallbacks() {
  50 + @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
  51 + if (savedInstanceState != null) {
  52 + String activityId = savedInstanceState.getString(KEY_ACTIVITY_ID);
  53 + if (activityId != null) {
  54 + // After a screen orientation change we map the newly created Activity to the same
  55 + // Activity ID as the previous activity has had (before screen orientation change)
  56 + activityIdMap.put(activity, activityId);
  57 + }
  58 + }
  59 + }
  60 +
  61 + @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
  62 + // Save the activityId into bundle so that the other
  63 + String activityId = activityIdMap.get(activity);
  64 + if (activityId != null) {
  65 + outState.putString(KEY_ACTIVITY_ID, activityId);
  66 + }
  67 + }
  68 +
  69 + @Override public void onActivityStarted(Activity activity) {
  70 + }
  71 +
  72 + @Override public void onActivityResumed(Activity activity) {
  73 + }
  74 +
  75 + @Override public void onActivityPaused(Activity activity) {
  76 +
  77 + }
  78 +
  79 + @Override public void onActivityStopped(Activity activity) {
  80 + }
  81 +
  82 + @Override public void onActivityDestroyed(Activity activity) {
  83 + if (!activity.isChangingConfigurations()) {
  84 + // Activity will be destroyed permanently, so reset the cache
  85 + String activityId = activityIdMap.get(activity);
  86 + if (activityId != null) {
  87 + ActivityScopedCache scopedCache = activityScopedCacheMap.get(activityId);
  88 + if (scopedCache != null) {
  89 + scopedCache.clear();
  90 + activityScopedCacheMap.remove(activityId);
  91 + }
  92 +
  93 + // No Activity Scoped cache available, so unregister
  94 + if (activityScopedCacheMap.isEmpty()) {
  95 + // All Mosby related activities are destroyed, so we can remove the activity lifecylce listener
  96 + activity.getApplication()
  97 + .unregisterActivityLifecycleCallbacks(activityLifecycleCallbacks);
  98 + if (DEBUG) {
  99 + Log.d(DEBUG_TAG, "Unregistering ActivityLifecycleCallbacks");
  100 + }
  101 + }
  102 + }
  103 + }
  104 + activityIdMap.remove(activity);
  105 + }
  106 + };
  107 +
  108 + private PresenterManager() {
  109 + throw new RuntimeException("Not instantiatable!");
  110 + }
  111 +
  112 + /**
  113 + * Get an already existing {@link ActivityScopedCache} or creates a new one if not existing yet
  114 + *
  115 + * @param activity The Activitiy for which you want to get the activity scope for
  116 + * @return The {@link ActivityScopedCache} for the given Activity
  117 + */
  118 + @NonNull
  119 + @MainThread
  120 + static ActivityScopedCache getOrCreateActivityScopedCache(
  121 + @NonNull Activity activity) {
  122 + if (activity == null) {
  123 + throw new NullPointerException("Activity is null");
  124 + }
  125 +
  126 + String activityId = activityIdMap.get(activity);
  127 + if (activityId == null) {
  128 + // Activity not registered yet
  129 + activityId = UUID.randomUUID().toString();
  130 + activityIdMap.put(activity, activityId);
  131 +
  132 + if (activityIdMap.size() == 1) {
  133 + // Added the an Activity for the first time so register Activity LifecycleListener
  134 + activity.getApplication().registerActivityLifecycleCallbacks(activityLifecycleCallbacks);
  135 + if (DEBUG) {
  136 + Log.d(DEBUG_TAG, "Registering ActivityLifecycleCallbacks");
  137 + }
  138 + }
  139 + }
  140 +
  141 + ActivityScopedCache activityScopedCache = activityScopedCacheMap.get(activityId);
  142 + if (activityScopedCache == null) {
  143 + activityScopedCache = new ActivityScopedCache();
  144 + activityScopedCacheMap.put(activityId, activityScopedCache);
  145 + }
  146 +
  147 + return activityScopedCache;
  148 + }
  149 +
  150 + /**
  151 + * Get the {@link ActivityScopedCache} for the given Activity or <code>null</code> if no {@link
  152 + * ActivityScopedCache} exists for the given Activity
  153 + *
  154 + * @param activity The activity
  155 + * @return The {@link ActivityScopedCache} or null
  156 + * @see #getOrCreateActivityScopedCache(Activity)
  157 + */
  158 + @Nullable
  159 + @MainThread static ActivityScopedCache getActivityScope(@NonNull Activity activity) {
  160 + if (activity == null) {
  161 + throw new NullPointerException("Activity is null");
  162 + }
  163 + String activityId = activityIdMap.get(activity);
  164 + if (activityId == null) {
  165 + return null;
  166 + }
  167 +
  168 + return activityScopedCacheMap.get(activityId);
  169 + }
  170 +
  171 + /**
  172 + * Get the presenter for the View with the given (Mosby - internal) view Id or <code>null</code>
  173 + * if no presenter for the given view (via view id) exists.
  174 + *
  175 + * @param activity The Activity (used for scoping)
  176 + * @param viewId The mosby internal View Id (unique among all {@link MvpView}
  177 + * @param <P> The Presenter type
  178 + * @return The Presenter or <code>null</code>
  179 + */
  180 + @Nullable public static <P> P getPresenter(@NonNull Activity activity, @NonNull String viewId) {
  181 + if (activity == null) {
  182 + throw new NullPointerException("Activity is null");
  183 + }
  184 +
  185 + if (viewId == null) {
  186 + throw new NullPointerException("View id is null");
  187 + }
  188 +
  189 + ActivityScopedCache scopedCache = getActivityScope(activity);
  190 + return scopedCache == null ? null : (P) scopedCache.getPresenter(viewId);
  191 + }
  192 +
  193 + /**
  194 + * Get the ViewState (see mosby viestate modlue) for the View with the given (Mosby - internal)
  195 + * view Id or <code>null</code>
  196 + * if no viewstate for the given view exists.
  197 + *
  198 + * @param activity The Activity (used for scoping)
  199 + * @param viewId The mosby internal View Id (unique among all {@link MvpView}
  200 + * @param <VS> The type of the ViewState type
  201 + * @return The Presenter or <code>null</code>
  202 + */
  203 + @Nullable public static <VS> VS getViewState(@NonNull Activity activity, @NonNull String viewId) {
  204 + if (activity == null) {
  205 + throw new NullPointerException("Activity is null");
  206 + }
  207 +
  208 + if (viewId == null) {
  209 + throw new NullPointerException("View id is null");
  210 + }
  211 +
  212 + ActivityScopedCache scopedCache = getActivityScope(activity);
  213 + return scopedCache == null ? null : (VS) scopedCache.getViewState(viewId);
  214 + }
  215 +
  216 + /**
  217 + * Get the Activity of a context. This is typically used to determine the hosting activity of a
  218 + * {@link View}
  219 + *
  220 + * @param context The context
  221 + * @return The Activity or throws an Exception if Activity couldnt be determined
  222 + */
  223 + @NonNull public static Activity getActivity(@NonNull Context context) {
  224 + if (context == null) {
  225 + throw new NullPointerException("context == null");
  226 + }
  227 + if (context instanceof Activity) {
  228 + return (Activity) context;
  229 + }
  230 +
  231 + while (context instanceof ContextWrapper) {
  232 + if (context instanceof Activity) {
  233 + return (Activity) context;
  234 + }
  235 + context = ((ContextWrapper) context).getBaseContext();
  236 + }
  237 + throw new IllegalStateException("Could not find the surrounding Activity");
  238 + }
  239 +
  240 + /**
  241 + * Clears the internal (static) state. Used for testing.
  242 + */
  243 + static void reset() {
  244 + activityIdMap.clear();
  245 + for (ActivityScopedCache scopedCache : activityScopedCacheMap.values()) {
  246 + scopedCache.clear();
  247 + }
  248 +
  249 + activityScopedCacheMap.clear();
  250 + }
  251 +
  252 + /**
  253 + * Puts the presenter into the internal cache
  254 + *
  255 + * @param activity The parent activity
  256 + * @param viewId the view id (mosby internal)
  257 + * @param presenter the presenter
  258 + */
  259 + public static void putPresenter(@NonNull Activity activity, @NonNull String viewId,
  260 + @NonNull MvpPresenter<? extends MvpView> presenter) {
  261 + if (activity == null) {
  262 + throw new NullPointerException("Activity is null");
  263 + }
  264 +
  265 + ActivityScopedCache scopedCache = getOrCreateActivityScopedCache(activity);
  266 + scopedCache.putPresenter(viewId, presenter);
  267 + }
  268 +
  269 + /**
  270 + * Puts the presenter into the internal cache
  271 + *
  272 + * @param activity The parent activity
  273 + * @param viewId the view id (mosby internal)
  274 + * @param viewState the presenter
  275 + */
  276 + public static void putViewState(@NonNull Activity activity, @NonNull String viewId,
  277 + @NonNull Object viewState) {
  278 + if (activity == null) {
  279 + throw new NullPointerException("Activity is null");
  280 + }
  281 +
  282 + ActivityScopedCache scopedCache = getOrCreateActivityScopedCache(activity);
  283 + scopedCache.putViewState(viewId, viewState);
  284 + }
  285 +
  286 + /**
  287 + * Removes the Presenter (and ViewState) for the given View. Does nothing if no Presenter is
  288 + * stored internally with the given viewId
  289 + *
  290 + * @param activity The activity
  291 + * @param viewId The mosby internal view id
  292 + */
  293 + public static void remove(@NonNull Activity activity, @NonNull String viewId) {
  294 + if (activity == null) {
  295 + throw new NullPointerException("Activity is null");
  296 + }
  297 +
  298 + ActivityScopedCache activityScope = getActivityScope(activity);
  299 + if (activityScope != null) {
  300 + activityScope.remove(viewId);
  301 + }
  302 + }
  303 +}
  304 +
  305 +
  306 +
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/MvpActivity.java 0 → 100644
  1 +/*
  2 + * Copyright 2015 Hannes Dorfmann.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package com.hannesdorfmann.mosby3.mvp;
  18 +
  19 +import android.os.Bundle;
  20 +
  21 +import androidx.annotation.NonNull;
  22 +import androidx.appcompat.app.AppCompatActivity;
  23 +
  24 +import com.hannesdorfmann.mosby3.mvp.delegate.ActivityMvpDelegate;
  25 +import com.hannesdorfmann.mosby3.mvp.delegate.ActivityMvpDelegateImpl;
  26 +
  27 +/**
  28 + * An Activity that uses a {@link MvpPresenter} to implement a Model-View-Presenter
  29 + * architecture.
  30 + *
  31 + * @author Hannes Dorfmann
  32 + * @since 1.0.0
  33 + */
  34 +public abstract class MvpActivity<V extends MvpView, P extends MvpPresenter<V>>
  35 + extends AppCompatActivity implements MvpView,
  36 + com.hannesdorfmann.mosby3.mvp.delegate.MvpDelegateCallback<V,P> {
  37 +
  38 + protected ActivityMvpDelegate mvpDelegate;
  39 + protected P presenter;
  40 + protected boolean retainInstance;
  41 +
  42 + @Override protected void onCreate(Bundle savedInstanceState) {
  43 + super.onCreate(savedInstanceState);
  44 + getMvpDelegate().onCreate(savedInstanceState);
  45 + }
  46 +
  47 + @Override protected void onDestroy() {
  48 + super.onDestroy();
  49 + getMvpDelegate().onDestroy();
  50 + }
  51 +
  52 + @Override protected void onSaveInstanceState(Bundle outState) {
  53 + super.onSaveInstanceState(outState);
  54 + getMvpDelegate().onSaveInstanceState(outState);
  55 + }
  56 +
  57 + @Override protected void onPause() {
  58 + super.onPause();
  59 + getMvpDelegate().onPause();
  60 + }
  61 +
  62 + @Override protected void onResume() {
  63 + super.onResume();
  64 + getMvpDelegate().onResume();
  65 + }
  66 +
  67 + @Override protected void onStart() {
  68 + super.onStart();
  69 + getMvpDelegate().onStart();
  70 + }
  71 +
  72 + @Override protected void onStop() {
  73 + super.onStop();
  74 + getMvpDelegate().onStop();
  75 + }
  76 +
  77 + @Override protected void onRestart() {
  78 + super.onRestart();
  79 + getMvpDelegate().onRestart();
  80 + }
  81 +
  82 + @Override public void onContentChanged() {
  83 + super.onContentChanged();
  84 + getMvpDelegate().onContentChanged();
  85 + }
  86 +
  87 + @Override protected void onPostCreate(Bundle savedInstanceState) {
  88 + super.onPostCreate(savedInstanceState);
  89 + getMvpDelegate().onPostCreate(savedInstanceState);
  90 + }
  91 +
  92 + /**
  93 + * Instantiate a presenter instance
  94 + *
  95 + * @return The {@link MvpPresenter} for this view
  96 + */
  97 + @NonNull
  98 + public abstract P createPresenter();
  99 +
  100 + /**
  101 + * Get the mvp delegate. This is internally used for creating presenter, attaching and detaching
  102 + * view from presenter.
  103 + *
  104 + * <p><b>Please note that only one instance of mvp delegate should be used per Activity
  105 + * instance</b>.
  106 + * </p>
  107 + *
  108 + * <p>
  109 + * Only override this method if you really know what you are doing.
  110 + * </p>
  111 + *
  112 + * @return {@link ActivityMvpDelegateImpl}
  113 + */
  114 + @NonNull protected ActivityMvpDelegate<V, P> getMvpDelegate() {
  115 + if (mvpDelegate == null) {
  116 + mvpDelegate = new ActivityMvpDelegateImpl(this, this, true);
  117 + }
  118 +
  119 + return mvpDelegate;
  120 + }
  121 +
  122 + @NonNull @Override public P getPresenter() {
  123 + return presenter;
  124 + }
  125 +
  126 + @Override public void setPresenter(@NonNull P presenter) {
  127 + this.presenter = presenter;
  128 + }
  129 +
  130 + @NonNull @Override public V getMvpView() {
  131 + return (V) this;
  132 + }
  133 +}
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/MvpBasePresenter.java 0 → 100644
  1 +/*
  2 + * Copyright 2015 Hannes Dorfmann.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package com.hannesdorfmann.mosby3.mvp;
  18 +
  19 +
  20 +import androidx.annotation.NonNull;
  21 +import androidx.annotation.UiThread;
  22 +
  23 +import java.lang.ref.WeakReference;
  24 +
  25 +/**
  26 + * A base implementation of a {@link MvpPresenter} that uses a <b>WeakReference</b> for referring
  27 + * to the attached view.
  28 + * <p>
  29 + * Use {@link #ifViewAttached(ViewAction)} to interact with the view. Since the view is passive,
  30 + * usually a Presenter should not get any data from View: so calls like view.getUserId() should not be done.
  31 + * Rather write a method in your Presenter that takes the user id as parameter like this:
  32 + * {@code
  33 + * void doSomething(int userId){
  34 + * // do something
  35 + * ...
  36 + * <p>
  37 + * ifViewAttached( view -> view.showSuccessful())
  38 + * }
  39 + * <p>
  40 + * }
  41 + * </p>
  42 + *
  43 + * @param <V> type of the {@link MvpView}
  44 + * @author Hannes Dorfmann
  45 + * @since 1.0.0
  46 + */
  47 +public class MvpBasePresenter<V extends MvpView> implements MvpPresenter<V> {
  48 +
  49 + /**
  50 + * An Action that is executed to interact with the view.
  51 + * Usually a Presenter should not get any data from View: so calls like view.getUserId() should not be done.
  52 + * Rather write a method in your Presenter that takes the user id as parameter like this:
  53 + * {@code
  54 + * void doSomething(int userId){
  55 + * // do something
  56 + * ...
  57 + * <p>
  58 + * ifViewAttached( view -> view.showSuccessful())
  59 + * }
  60 + *
  61 + * @param <V> The Type of the View
  62 + */
  63 + public interface ViewAction<V> {
  64 +
  65 + /**
  66 + * This method will be invoked to run the action. Implement this method to interact with the view.
  67 + *
  68 + * @param view The reference to the view. Not null.
  69 + */
  70 + void run(@NonNull V view);
  71 + }
  72 +
  73 + private WeakReference<V> viewRef;
  74 + private boolean presenterDestroyed = false;
  75 +
  76 + @UiThread
  77 + @Override
  78 + public void attachView(V view) {
  79 + viewRef = new WeakReference<V>(view);
  80 + presenterDestroyed = false;
  81 + }
  82 +
  83 + /**
  84 + * Gets the attached view. You should always call {@link #isViewAttached()} to check if the view
  85 + * is attached to avoid NullPointerExceptions.
  86 + *
  87 + * @return <code>null</code>, if view is not attached, otherwise the concrete view instance
  88 + * @deprecated Use {@link #ifViewAttached(ViewAction)}
  89 + */
  90 + @Deprecated
  91 + @UiThread
  92 + public V getView() {
  93 + return viewRef == null ? null : viewRef.get();
  94 + }
  95 +
  96 + /**
  97 + * Checks if a view is attached to this presenter. You should always call this method before
  98 + * calling {@link #getView()} to get the view instance.
  99 + *
  100 + * @deprecated Use {@link #ifViewAttached(ViewAction)}
  101 + */
  102 + @Deprecated
  103 + @UiThread
  104 + public boolean isViewAttached() {
  105 + return viewRef != null && viewRef.get() != null;
  106 + }
  107 +
  108 + /**
  109 + * {@inheritDoc}
  110 + */
  111 + @Deprecated
  112 + @UiThread
  113 + @Override
  114 + public void detachView(boolean retainInstance) {
  115 + }
  116 +
  117 + /**
  118 + * Executes the passed Action only if the View is attached.
  119 + * If no View is attached, either an exception is thrown (if parameter exceptionIfViewNotAttached
  120 + * is true) or the action is just not executed (no exception thrown).
  121 + * Note that if no view is attached, this will not re-execute the given action if the View gets
  122 + * re-attached.
  123 + *
  124 + * @param exceptionIfViewNotAttached true, if an exception should be thrown if no view is
  125 + * attached while trying to execute the action. false, if no exception should be thrown (the action
  126 + * will not be executed since no view is attached)
  127 + * @param action The {@link ViewAction} that will be executed if a view is attached. This is
  128 + * where you call view.isLoading etc. Use the view reference passed as parameter to {@link
  129 + * ViewAction#run(Object)} and not deprecated method {@link #getView()}
  130 + */
  131 + protected final void ifViewAttached(boolean exceptionIfViewNotAttached, ViewAction<V> action) {
  132 + final V view = viewRef == null ? null : viewRef.get();
  133 + if (view != null) {
  134 + action.run(view);
  135 + } else if (exceptionIfViewNotAttached) {
  136 + throw new IllegalStateException(
  137 + "No View attached to Presenter. Presenter destroyed = " + presenterDestroyed);
  138 + }
  139 + }
  140 +
  141 + /**
  142 + * Calls {@link #ifViewAttached(boolean, ViewAction)} with false as first parameter (don't throw
  143 + * exception if view not attached).
  144 + *
  145 + * @see #ifViewAttached(boolean, ViewAction)
  146 + */
  147 + protected final void ifViewAttached(ViewAction<V> action) {
  148 + ifViewAttached(false, action);
  149 + }
  150 +
  151 + /**
  152 + * {@inheritDoc}
  153 + */
  154 + public void detachView() {
  155 + detachView(true);
  156 + if (viewRef != null) {
  157 + viewRef.clear();
  158 + viewRef = null;
  159 + }
  160 + }
  161 +
  162 + /**
  163 + * {@inheritDoc}
  164 + */
  165 + public void destroy() {
  166 + detachView(false);
  167 + presenterDestroyed = true;
  168 + }
  169 +}
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/MvpDialogFragment.java 0 → 100644
  1 +package com.hannesdorfmann.mosby3.mvp;
  2 +
  3 +import android.app.Activity;
  4 +import android.app.Dialog;
  5 +import android.content.Context;
  6 +import android.os.Bundle;
  7 +import android.view.View;
  8 +
  9 +import androidx.annotation.NonNull;
  10 +import androidx.annotation.Nullable;
  11 +import androidx.fragment.app.DialogFragment;
  12 +
  13 +import com.hannesdorfmann.mosby3.mvp.delegate.FragmentMvpDelegate;
  14 +import com.hannesdorfmann.mosby3.mvp.delegate.FragmentMvpDelegateImpl;
  15 +import com.hannesdorfmann.mosby3.mvp.delegate.MvpDelegateCallback;
  16 +
  17 +/**
  18 + * A DialogFragment that uses an {@link MvpPresenter} to implement a Model-View-Presenter
  19 + * architecture
  20 + *
  21 + * @author Hannes Dorfmann
  22 + * @author Michał Seroczyński
  23 + * @since 3.1.1
  24 + */
  25 +public abstract class MvpDialogFragment<V extends MvpView, P extends MvpPresenter<V>> extends DialogFragment
  26 + implements MvpDelegateCallback<V, P>, MvpView {
  27 +
  28 + protected FragmentMvpDelegate<V, P> mvpDelegate;
  29 +
  30 + /**
  31 + * The presenter for this view. Will be instantiated with {@link #createPresenter()}
  32 + */
  33 + protected P presenter;
  34 +
  35 + /**
  36 + * Creates a new presenter instance, if needed. Will reuse the previous presenter instance if
  37 + * {@link #setRetainInstance(boolean)} is set to true. This method will be called from
  38 + * {@link #onViewCreated(View, Bundle)}
  39 + */
  40 + public abstract P createPresenter();
  41 +
  42 + /**
  43 + * * Get the mvp delegate. This is internally used for creating presenter, attaching and
  44 + * detaching view from presenter.
  45 + *
  46 + * <p>
  47 + * <b>Please note that only one instance of mvp delegate should be used per fragment
  48 + * instance</b>.
  49 + * </p>
  50 + *
  51 + * <p>
  52 + * Only override this method if you really know what you are doing.
  53 + * </p>
  54 + *
  55 + * @return {@link FragmentMvpDelegateImpl}
  56 + */
  57 + @NonNull
  58 + protected FragmentMvpDelegate<V, P> getMvpDelegate() {
  59 + if (mvpDelegate == null) {
  60 + mvpDelegate = new FragmentMvpDelegateImpl<>(this, this, true, true);
  61 + }
  62 +
  63 + return mvpDelegate;
  64 + }
  65 +
  66 + @NonNull @Override public P getPresenter() {
  67 + return presenter;
  68 + }
  69 +
  70 + @Override public void setPresenter(@NonNull P presenter) {
  71 + this.presenter = presenter;
  72 + }
  73 +
  74 + @NonNull @Override public V getMvpView() {
  75 + return (V) this;
  76 + }
  77 +
  78 + @Override
  79 + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
  80 + super.onViewCreated(view, savedInstanceState);
  81 + getMvpDelegate().onViewCreated(view, savedInstanceState);
  82 + }
  83 +
  84 + @Override public void onDestroyView() {
  85 + Dialog dialog = getDialog();
  86 + // Handles https://code.google.com/p/android/issues/detail?id=17423
  87 + if (dialog != null && getRetainInstance()) {
  88 + dialog.setDismissMessage(null);
  89 + }
  90 +
  91 + super.onDestroyView();
  92 + getMvpDelegate().onDestroyView();
  93 + }
  94 +
  95 + @Override public void onCreate(Bundle savedInstanceState) {
  96 + super.onCreate(savedInstanceState);
  97 + getMvpDelegate().onCreate(savedInstanceState);
  98 + }
  99 +
  100 + @Override public void onDestroy() {
  101 + super.onDestroy();
  102 + getMvpDelegate().onDestroy();
  103 + }
  104 +
  105 + @Override public void onPause() {
  106 + super.onPause();
  107 + getMvpDelegate().onPause();
  108 + }
  109 +
  110 + @Override public void onResume() {
  111 + super.onResume();
  112 + getMvpDelegate().onResume();
  113 + }
  114 +
  115 + @Override public void onStart() {
  116 + super.onStart();
  117 + getMvpDelegate().onStart();
  118 + }
  119 +
  120 + @Override public void onStop() {
  121 + super.onStop();
  122 + getMvpDelegate().onStop();
  123 + }
  124 +
  125 + @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) {
  126 + super.onActivityCreated(savedInstanceState);
  127 + getMvpDelegate().onActivityCreated(savedInstanceState);
  128 + }
  129 +
  130 + @Override public void onAttach(Activity activity) {
  131 + super.onAttach(activity);
  132 + getMvpDelegate().onAttach(activity);
  133 + }
  134 +
  135 + @Override public void onAttach(Context context) {
  136 + super.onAttach(context);
  137 + getMvpDelegate().onAttach(context);
  138 + }
  139 +
  140 + @Override public void onDetach() {
  141 + super.onDetach();
  142 + getMvpDelegate().onDetach();
  143 + }
  144 +
  145 + @Override public void onSaveInstanceState(Bundle outState) {
  146 + super.onSaveInstanceState(outState);
  147 + getMvpDelegate().onSaveInstanceState(outState);
  148 + }
  149 +
  150 +}
0 \ No newline at end of file 151 \ No newline at end of file
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/MvpFragment.java 0 → 100644
  1 +/*
  2 + * Copyright 2015 Hannes Dorfmann.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package com.hannesdorfmann.mosby3.mvp;
  18 +
  19 +import android.app.Activity;
  20 +import android.content.Context;
  21 +import android.os.Bundle;
  22 +import android.view.View;
  23 +
  24 +import androidx.annotation.NonNull;
  25 +import androidx.annotation.Nullable;
  26 +import androidx.fragment.app.Fragment;
  27 +
  28 +import com.hannesdorfmann.mosby3.mvp.delegate.FragmentMvpDelegate;
  29 +import com.hannesdorfmann.mosby3.mvp.delegate.FragmentMvpDelegateImpl;
  30 +import com.hannesdorfmann.mosby3.mvp.delegate.MvpDelegateCallback;
  31 +
  32 +/**
  33 + * A Fragment that uses a {@link MvpPresenter} to implement a Model-View-Presenter architecture.
  34 + *
  35 + * @author Hannes Dorfmann
  36 + * @since 1.0.0
  37 + */
  38 +public abstract class MvpFragment<V extends MvpView, P extends MvpPresenter<V>> extends Fragment
  39 + implements MvpDelegateCallback<V, P>, MvpView {
  40 +
  41 + protected FragmentMvpDelegate<V, P> mvpDelegate;
  42 +
  43 + /**
  44 + * The presenter for this view. Will be instantiated with {@link #createPresenter()}
  45 + */
  46 + protected P presenter;
  47 +
  48 + /**
  49 + * Creates a new presenter instance, if needed. Will reuse the previous presenter instance if
  50 + * {@link #setRetainInstance(boolean)} is set to true. This method will be called from
  51 + * {@link #onViewCreated(View, Bundle)}
  52 + */
  53 + public abstract P createPresenter();
  54 +
  55 + /**
  56 + * Gets the mvp delegate. This is internally used for creating presenter, attaching and
  57 + * detaching view from presenter.
  58 + *
  59 + * <p>
  60 + * <b>Please note that only one instance of mvp delegate should be used per fragment instance</b>.
  61 + * </p>
  62 + *
  63 + * <p>
  64 + * Only override this method if you really know what you are doing.
  65 + * </p>
  66 + *
  67 + * @return {@link FragmentMvpDelegateImpl}
  68 + */
  69 + @NonNull
  70 + protected FragmentMvpDelegate<V, P> getMvpDelegate() {
  71 + if (mvpDelegate == null) {
  72 + mvpDelegate = new FragmentMvpDelegateImpl<>(this, this, true, true);
  73 + }
  74 +
  75 + return mvpDelegate;
  76 + }
  77 +
  78 + @NonNull @Override public P getPresenter() {
  79 + return presenter;
  80 + }
  81 +
  82 + @Override public void setPresenter(@NonNull P presenter) {
  83 + this.presenter = presenter;
  84 + }
  85 +
  86 + @NonNull @Override public V getMvpView() {
  87 + return (V) this;
  88 + }
  89 +
  90 + @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
  91 + super.onViewCreated(view, savedInstanceState);
  92 + getMvpDelegate().onViewCreated(view, savedInstanceState);
  93 + }
  94 +
  95 + @Override public void onDestroyView() {
  96 + super.onDestroyView();
  97 + getMvpDelegate().onDestroyView();
  98 + }
  99 +
  100 + @Override public void onCreate(Bundle savedInstanceState) {
  101 + super.onCreate(savedInstanceState);
  102 + getMvpDelegate().onCreate(savedInstanceState);
  103 + }
  104 +
  105 + @Override public void onDestroy() {
  106 + super.onDestroy();
  107 + getMvpDelegate().onDestroy();
  108 + }
  109 +
  110 + @Override public void onPause() {
  111 + super.onPause();
  112 + getMvpDelegate().onPause();
  113 + }
  114 +
  115 + @Override public void onResume() {
  116 + super.onResume();
  117 + getMvpDelegate().onResume();
  118 + }
  119 +
  120 + @Override public void onStart() {
  121 + super.onStart();
  122 + getMvpDelegate().onStart();
  123 + }
  124 +
  125 + @Override public void onStop() {
  126 + super.onStop();
  127 + getMvpDelegate().onStop();
  128 + }
  129 +
  130 + @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) {
  131 + super.onActivityCreated(savedInstanceState);
  132 + getMvpDelegate().onActivityCreated(savedInstanceState);
  133 + }
  134 +
  135 + @Deprecated @Override public void onAttach(Activity activity) {
  136 + super.onAttach(activity);
  137 + getMvpDelegate().onAttach(activity);
  138 + }
  139 +
  140 + @Override public void onAttach(Context context) {
  141 + super.onAttach(context);
  142 + getMvpDelegate().onAttach(context);
  143 + }
  144 +
  145 + @Override public void onDetach() {
  146 + super.onDetach();
  147 + getMvpDelegate().onDetach();
  148 + }
  149 +
  150 + @Override public void onSaveInstanceState(Bundle outState) {
  151 + super.onSaveInstanceState(outState);
  152 + getMvpDelegate().onSaveInstanceState(outState);
  153 + }
  154 +}
  155 +
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/MvpPresenter.java 0 → 100644
  1 +/*
  2 + * Copyright 2015 Hannes Dorfmann.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package com.hannesdorfmann.mosby3.mvp;
  18 +
  19 +
  20 +import androidx.annotation.NonNull;
  21 +import androidx.annotation.UiThread;
  22 +
  23 +/**
  24 + * The base interface for each mvp presenter.
  25 + *
  26 + * <p>
  27 + * Mosby assumes that all interaction (i.e. updating the View) between Presenter and View is
  28 + * executed on Android's main UI thread.
  29 + * </p>
  30 + *
  31 + * @author Hannes Dorfmann
  32 + * @since 1.0.0
  33 + */
  34 +public interface MvpPresenter<V extends MvpView> {
  35 +
  36 + /**
  37 + * Set or attach the view to this presenter
  38 + */
  39 + @UiThread
  40 + void attachView(@NonNull V view);
  41 +
  42 + /**
  43 + * Will be called if the view has been destroyed. Typically this method will be invoked from
  44 + * <code>Activity.detachView()</code> or <code>Fragment.onDestroyView()</code>
  45 + *
  46 + * @deprecated This method has been split into 2 methods: {@link #detachView()} and {@link #destroy()}
  47 + */
  48 + @UiThread
  49 + @Deprecated
  50 + void detachView(boolean retainInstance);
  51 +
  52 + /**
  53 + * Will be called if the view has been detached from the Presenter.
  54 + * Usually this happens on screen orientation changes or view (like fragment) has been put on the backstack.
  55 + */
  56 + @UiThread
  57 + void detachView();
  58 +
  59 + /**
  60 + * Will be called if the presenter is no longer needed because the View has been destroyed permanently.
  61 + * This is where you do clean up stuff.
  62 + */
  63 + @UiThread
  64 + void destroy();
  65 +}
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/MvpView.java 0 → 100644
  1 +/*
  2 + * Copyright 2015 Hannes Dorfmann.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package com.hannesdorfmann.mosby3.mvp;
  18 +
  19 +/**
  20 + * The root view interface for every mvp view
  21 + *
  22 + * @author Hannes Dorfmann
  23 + * @since 1.0.0
  24 + */
  25 +public interface MvpView {
  26 +}
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/delegate/ActivityMvpDelegate.java 0 → 100644
  1 +/*
  2 + * Copyright 2015 Hannes Dorfmann.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package com.hannesdorfmann.mosby3.mvp.delegate;
  18 +
  19 +import android.app.Activity;
  20 +import android.os.Bundle;
  21 +import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
  22 +import com.hannesdorfmann.mosby3.mvp.MvpView;
  23 +
  24 +/**
  25 + * A delegate for Activities to attach them to Mosby mvp.
  26 + *
  27 + * <p>
  28 + * The following methods must be invoked from the corresponding Activities lifecycle methods:
  29 + * <ul>
  30 + * <li>{@link #onCreate(Bundle)}</li>
  31 + * <li>{@link #onDestroy()}</li>
  32 + * <li>{@link #onPause()} </li>
  33 + * <li>{@link #onResume()} </li>
  34 + * <li>{@link #onStart()} </li>
  35 + * <li>{@link #onStop()} </li>
  36 + * <li>{@link #onRestart()} </li>
  37 + * <li>{@link #onContentChanged()} </li>
  38 + * <li>{@link #onSaveInstanceState(Bundle)} </li>
  39 + * <li>{@link #onPostCreate(Bundle)} </li>
  40 + * <li></li>
  41 + * </ul>
  42 + * </p>
  43 + *
  44 + * @param <V> The type of {@link MvpView}
  45 + * @param <P> The type of {@link MvpPresenter}
  46 + * @author Hannes Dorfmann
  47 + * @since 1.1.0
  48 + */
  49 +public interface ActivityMvpDelegate<V extends MvpView, P extends MvpPresenter<V>> {
  50 +
  51 + /**
  52 + * This method must be called from {@link Activity#onCreate(Bundle)}.
  53 + * This method internally creates the presenter and attaches the view to it.
  54 + */
  55 + void onCreate(Bundle bundle);
  56 +
  57 + /**
  58 + * This method must be called from {@link Activity#onDestroy()}}.
  59 + * This method internally detaches the view from presenter
  60 + */
  61 + void onDestroy();
  62 +
  63 + /**
  64 + * This method must be called from {@link Activity#onPause()}
  65 + */
  66 + void onPause();
  67 +
  68 + /**
  69 + * This method must be called from {@link Activity#onResume()}
  70 + */
  71 + void onResume();
  72 +
  73 + /**
  74 + * This method must be called from {@link Activity#onStart()}
  75 + */
  76 + void onStart();
  77 +
  78 + /**
  79 + * This method must be called from {@link Activity#onStop()}
  80 + */
  81 + void onStop();
  82 +
  83 + /**
  84 + * This method must be called from {@link Activity#onRestart()}
  85 + */
  86 + void onRestart();
  87 +
  88 + /**
  89 + * This method must be called from {@link Activity#onContentChanged()}
  90 + */
  91 + void onContentChanged();
  92 +
  93 + /**
  94 + * This method must be called from {@link Activity#onSaveInstanceState(Bundle)}
  95 + */
  96 + void onSaveInstanceState(Bundle outState);
  97 +
  98 + /**
  99 + * This method must be called from {@link Activity#onPostCreate(Bundle)}
  100 + */
  101 + void onPostCreate(Bundle savedInstanceState);
  102 +
  103 +}
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/delegate/ActivityMvpDelegateImpl.java 0 → 100644
  1 +/*
  2 + * Copyright 2015 Hannes Dorfmann.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package com.hannesdorfmann.mosby3.mvp.delegate;
  18 +
  19 +import android.app.Activity;
  20 +import android.os.Bundle;
  21 +import android.util.Log;
  22 +
  23 +import androidx.annotation.NonNull;
  24 +
  25 +import com.hannesdorfmann.mosby3.PresenterManager;
  26 +import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
  27 +import com.hannesdorfmann.mosby3.mvp.MvpView;
  28 +import java.util.UUID;
  29 +
  30 +/**
  31 + * The concrete implementation of {@link}
  32 + *
  33 + * @param <V> The type of {@link MvpView}
  34 + * @param <P> The type of {@link MvpPresenter}
  35 + * @author Hannes Dorfmann
  36 + * @see ActivityMvpDelegate
  37 + * @since 1.1.0
  38 + */
  39 +public class ActivityMvpDelegateImpl<V extends MvpView, P extends MvpPresenter<V>>
  40 + implements ActivityMvpDelegate {
  41 +
  42 + protected static final String KEY_MOSBY_VIEW_ID = "com.hannesdorfmann.mosby3.activity.mvp.id";
  43 +
  44 + public static boolean DEBUG = false;
  45 + private static final String DEBUG_TAG = "ActivityMvpDelegateImpl";
  46 +
  47 + private MvpDelegateCallback<V, P> delegateCallback;
  48 + protected boolean keepPresenterInstance;
  49 + protected Activity activity;
  50 + protected String mosbyViewId = null;
  51 +
  52 + /**
  53 + * @param activity The Activity
  54 + * @param delegateCallback The callback
  55 + * @param keepPresenterInstance true, if the presenter instance should be kept across screen
  56 + * orientation changes. Otherwise false.
  57 + */
  58 + public ActivityMvpDelegateImpl(@NonNull Activity activity,
  59 + @NonNull MvpDelegateCallback<V, P> delegateCallback, boolean keepPresenterInstance) {
  60 +
  61 + if (activity == null) {
  62 + throw new NullPointerException("Activity is null!");
  63 + }
  64 +
  65 + if (delegateCallback == null) {
  66 + throw new NullPointerException("MvpDelegateCallback is null!");
  67 + }
  68 + this.delegateCallback = delegateCallback;
  69 + this.activity = activity;
  70 + this.keepPresenterInstance = keepPresenterInstance;
  71 + }
  72 +
  73 + /**
  74 + * Determines whether or not a Presenter Instance should be kept
  75 + *
  76 + * @param keepPresenterInstance true, if the delegate has enabled keep
  77 + */
  78 + static boolean retainPresenterInstance(boolean keepPresenterInstance, Activity activity) {
  79 + return keepPresenterInstance && (activity.isChangingConfigurations()
  80 + || !activity.isFinishing());
  81 + }
  82 +
  83 + /**
  84 + * Generates the unique (mosby internal) view id and calls {@link
  85 + * MvpDelegateCallback#createPresenter()}
  86 + * to create a new presenter instance
  87 + *
  88 + * @return The new created presenter instance
  89 + */
  90 + private P createViewIdAndCreatePresenter() {
  91 +
  92 + P presenter = delegateCallback.createPresenter();
  93 + if (presenter == null) {
  94 + throw new NullPointerException(
  95 + "Presenter returned from createPresenter() is null. Activity is " + activity);
  96 + }
  97 + if (keepPresenterInstance) {
  98 + mosbyViewId = UUID.randomUUID().toString();
  99 + PresenterManager.putPresenter(activity, mosbyViewId, presenter);
  100 + }
  101 + return presenter;
  102 + }
  103 +
  104 + @Override public void onCreate(Bundle bundle) {
  105 +
  106 + P presenter = null;
  107 +
  108 + if (bundle != null && keepPresenterInstance) {
  109 +
  110 + mosbyViewId = bundle.getString(KEY_MOSBY_VIEW_ID);
  111 +
  112 + if (DEBUG) {
  113 + Log.d(DEBUG_TAG,
  114 + "MosbyView ID = " + mosbyViewId + " for MvpView: " + delegateCallback.getMvpView());
  115 + }
  116 +
  117 + if (mosbyViewId != null
  118 + && (presenter = PresenterManager.getPresenter(activity, mosbyViewId)) != null) {
  119 + //
  120 + // Presenter restored from cache
  121 + //
  122 + if (DEBUG) {
  123 + Log.d(DEBUG_TAG,
  124 + "Reused presenter " + presenter + " for view " + delegateCallback.getMvpView());
  125 + }
  126 + } else {
  127 + //
  128 + // No presenter found in cache, most likely caused by process death
  129 + //
  130 + presenter = createViewIdAndCreatePresenter();
  131 + if (DEBUG) {
  132 + Log.d(DEBUG_TAG, "No presenter found although view Id was here: "
  133 + + mosbyViewId
  134 + + ". Most likely this was caused by a process death. New Presenter created"
  135 + + presenter
  136 + + " for view "
  137 + + getMvpView());
  138 + }
  139 + }
  140 + } else {
  141 + //
  142 + // Activity starting first time, so create a new presenter
  143 + //
  144 + presenter = createViewIdAndCreatePresenter();
  145 + if (DEBUG) {
  146 + Log.d(DEBUG_TAG, "New presenter " + presenter + " for view " + getMvpView());
  147 + }
  148 + }
  149 +
  150 + if (presenter == null) {
  151 + throw new IllegalStateException(
  152 + "Oops, Presenter is null. This seems to be a Mosby internal bug. Please report this issue here: https://github.com/sockeqwe/mosby/issues");
  153 + }
  154 +
  155 + delegateCallback.setPresenter(presenter);
  156 + getPresenter().attachView(getMvpView());
  157 +
  158 + if (DEBUG) {
  159 + Log.d(DEBUG_TAG, "View" + getMvpView() + " attached to Presenter " + presenter);
  160 + }
  161 + }
  162 +
  163 + private P getPresenter() {
  164 + P presenter = delegateCallback.getPresenter();
  165 + if (presenter == null) {
  166 + throw new NullPointerException("Presenter returned from getPresenter() is null");
  167 + }
  168 + return presenter;
  169 + }
  170 +
  171 + private V getMvpView() {
  172 + V view = delegateCallback.getMvpView();
  173 + if (view == null) {
  174 + throw new NullPointerException("View returned from getMvpView() is null");
  175 + }
  176 + return view;
  177 + }
  178 +
  179 + @Override public void onDestroy() {
  180 + boolean retainPresenterInstance = retainPresenterInstance(keepPresenterInstance, activity);
  181 + getPresenter().detachView();
  182 + if (!retainPresenterInstance){
  183 + getPresenter().destroy();
  184 + }
  185 + if (!retainPresenterInstance && mosbyViewId != null) {
  186 + PresenterManager.remove(activity, mosbyViewId);
  187 + }
  188 +
  189 + if (DEBUG) {
  190 + if (retainPresenterInstance) {
  191 + Log.d(DEBUG_TAG, "View"
  192 + + getMvpView()
  193 + + " destroyed temporarily. View detached from presenter "
  194 + + getPresenter());
  195 + } else {
  196 + Log.d(DEBUG_TAG, "View"
  197 + + getMvpView()
  198 + + " destroyed permanently. View detached permanently from presenter "
  199 + + getPresenter());
  200 + }
  201 + }
  202 + }
  203 +
  204 + @Override public void onPause() {
  205 +
  206 + }
  207 +
  208 + @Override public void onResume() {
  209 +
  210 + }
  211 +
  212 + @Override public void onStart() {
  213 +
  214 + }
  215 +
  216 + @Override public void onStop() {
  217 +
  218 + }
  219 +
  220 + @Override public void onRestart() {
  221 +
  222 + }
  223 +
  224 + @Override public void onContentChanged() {
  225 +
  226 + }
  227 +
  228 + @Override public void onSaveInstanceState(Bundle outState) {
  229 + if (keepPresenterInstance && outState != null) {
  230 + outState.putString(KEY_MOSBY_VIEW_ID, mosbyViewId);
  231 + if (DEBUG) {
  232 + Log.d(DEBUG_TAG,
  233 + "Saving MosbyViewId into Bundle. ViewId: " + mosbyViewId + " for view " + getMvpView());
  234 + }
  235 + }
  236 + }
  237 +
  238 + @Override public void onPostCreate(Bundle savedInstanceState) {
  239 + }
  240 +}
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/delegate/BackstackAccessor.java 0 → 100644
  1 +/*
  2 + * Copyright 2016 Hannes Dorfmann.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + *
  16 + */
  17 +
  18 +package com.hannesdorfmann.mosby3.mvp.delegate;
  19 +
  20 +import androidx.fragment.app.Fragment;
  21 +
  22 +import java.io.PrintWriter;
  23 +import java.io.StringWriter;
  24 +
  25 +/**
  26 + * With this utility class one can access the fragment backstack
  27 + *
  28 + * @author Hannes Dorfmann
  29 + */
  30 +public class BackstackAccessor {
  31 +
  32 + private BackstackAccessor() {
  33 + throw new IllegalStateException("Not instantiatable");
  34 + }
  35 +
  36 + /**
  37 + * Checks whether or not a given fragment is on the backstack of the fragment manager (could also
  38 + * be on top of the backstack and hence visible)
  39 + *
  40 + * @param fragment The fragment you want to check if its on the back stack
  41 + * @return true, if the given Fragment is on the back stack, otherwise false (not on the back
  42 + * stack)
  43 + */
  44 + //todo
  45 +// public static boolean isFragmentOnBackStack(Fragment fragment) {
  46 +// try {
  47 +//// return fragment.isInBackStack();
  48 +// return true;
  49 +// } catch (IllegalAccessError e) {
  50 +// return isInBackStackAndroidX(fragment);
  51 +// }
  52 +// }
  53 +
  54 + /**
  55 + * As of version 1.0 of AndroidX - fragment.isInBackStack() is package private which leads to
  56 + * an IllegalAccessError being thrown when trying to use it.
  57 + * This method is a temporary workaround until the issue is resolved in AndroidX.
  58 + */
  59 + public static boolean isInBackStackAndroidX(final Fragment fragment) {
  60 + final StringWriter writer = new StringWriter();
  61 + fragment.dump("", null, new PrintWriter(writer), null);
  62 + final String dump = writer.toString();
  63 + return !dump.contains("mBackStackNesting=0");
  64 + }
  65 +/*
  66 + public static boolean isFragmentOnBackStack(Fragment fragment) {
  67 +
  68 + FragmentManager fragmentManager = fragment.getFragmentManager();
  69 + int backStackSize = fragmentManager.getBackStackEntryCount();
  70 + for (int i = 0; i < backStackSize; i++) {
  71 + BackStackRecord stackEntry = (BackStackRecord) fragmentManager.getBackStackEntryAt(i);
  72 + int opsCount = stackEntry.mOps == null ? 0 : stackEntry.mOps.size();
  73 + if (opsCount > 0) {
  74 + BackStackRecord.Op op = stackEntry.mOps.get(opsCount-1);
  75 + if (op.fragment == fragment) {
  76 + return true;
  77 + }
  78 + }
  79 + }
  80 +
  81 + return false;
  82 + }
  83 +*/
  84 +
  85 +/*
  86 + private static boolean findNext(@NonNull Fragment toFind, @Nullable BackStackRecord.Op next) {
  87 + if (next == null) {
  88 + return false;
  89 + }
  90 +
  91 + if (toFind == next.fragment) {
  92 + return true;
  93 + } else {
  94 + return findNext(toFind, next.next);
  95 + }
  96 + }
  97 +
  98 + private static boolean findPrevious(@NonNull Fragment toFind,
  99 + @Nullable BackStackRecord.Op previous) {
  100 + if (previous == null) {
  101 + return false;
  102 + }
  103 +
  104 + if (toFind == previous.fragment) {
  105 + return true;
  106 + } else {
  107 + return findPrevious(toFind, previous.prev);
  108 + }
  109 + }
  110 + */
  111 +}
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/delegate/FragmentMvpDelegate.java 0 → 100644
  1 +/*
  2 + * Copyright 2015 Hannes Dorfmann.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package com.hannesdorfmann.mosby3.mvp.delegate;
  18 +
  19 +import android.app.Activity;
  20 +import android.content.Context;
  21 +import android.os.Bundle;
  22 +import android.view.View;
  23 +
  24 +import androidx.annotation.Nullable;
  25 +
  26 +import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
  27 +import com.hannesdorfmann.mosby3.mvp.MvpView;
  28 +
  29 +/**
  30 + * A delegate for Fragments to attach them to mosby mvp.
  31 + * <p>
  32 + * The following methods must be invoked from the corresponding Fragments lifecycle methods:
  33 + *
  34 + * <ul>
  35 + * <li>{@link #onCreate(Bundle)}</li>
  36 + * <li>{@link #onDestroy()}</li>
  37 + * <li>{@link #onPause()} </li>
  38 + * <li>{@link #onResume()} </li>
  39 + * <li>{@link #onStart()} </li>
  40 + * <li>{@link #onStop()} </li>
  41 + * <li>{@link #onViewCreated(View, Bundle)} </li>
  42 + * <li>{@link #onActivityCreated(Bundle)} </li>
  43 + * <li>{@link #onSaveInstanceState(Bundle)} </li>
  44 + * <li>{@link #onAttach(Activity)} </li>
  45 + * <li>{@link #onAttach(Context)} </li>
  46 + * <li>{@link #onDetach()}</li>
  47 + * <li></li>
  48 + * </ul>
  49 + * </p>
  50 + *
  51 + * @param <V> The type of {@link MvpView}
  52 + * @param <P> The type of {@link MvpPresenter}
  53 + * @author Hannes Dorfmann
  54 + * @since 1.1.0
  55 + */
  56 +public interface FragmentMvpDelegate<V extends MvpView, P extends MvpPresenter<V>> {
  57 +
  58 + /**
  59 + * Must be called from {@link Fragment#onCreate(Bundle)}
  60 + *
  61 + * @param saved The bundle
  62 + */
  63 + void onCreate(Bundle saved);
  64 +
  65 + /**
  66 + * Must be called from {@link Fragment#onDestroy()}
  67 + */
  68 + void onDestroy();
  69 +
  70 + /**
  71 + * Must be called from {@link Fragment#onViewCreated(View, Bundle)}
  72 + *
  73 + * @param view The inflated view
  74 + * @param savedInstanceState the bundle with the viewstate
  75 + */
  76 + void onViewCreated(View view, @Nullable Bundle savedInstanceState);
  77 +
  78 + /**
  79 + * Must be called from {@link Fragment#onDestroyView()}
  80 + */
  81 + void onDestroyView();
  82 +
  83 + /**
  84 + * Must be called from {@link Fragment#onPause()}
  85 + */
  86 + void onPause();
  87 +
  88 + /**
  89 + * Must be called from {@link Fragment#onResume()}
  90 + */
  91 + void onResume();
  92 +
  93 + /**
  94 + * Must be called from {@link Fragment#onStart()}
  95 + */
  96 + void onStart();
  97 +
  98 + /**
  99 + * Must be called from {@link Fragment#onStop()}
  100 + */
  101 + void onStop();
  102 +
  103 + /**
  104 + * Must be called from {@link Fragment#onActivityCreated(Bundle)}
  105 + *
  106 + * @param savedInstanceState The saved bundle
  107 + */
  108 + void onActivityCreated(Bundle savedInstanceState);
  109 +
  110 + /**
  111 + * Must be called from {@link Fragment#onAttach(Activity)}
  112 + *
  113 + * @param activity The activity the fragment is attached to
  114 + */
  115 + @Deprecated
  116 + void onAttach(Activity activity);
  117 +
  118 + /**
  119 + * Must be called from {@link Fragment#onAttach(Context)}
  120 + *
  121 + * @param context The context the fragment is attached to
  122 + */
  123 + void onAttach(Context context);
  124 +
  125 + /**
  126 + * Must be called from {@link Fragment#onDetach()}
  127 + */
  128 + void onDetach();
  129 +
  130 + /**
  131 + * Must be called from {@link Fragment#onSaveInstanceState(Bundle)}
  132 + */
  133 + void onSaveInstanceState(Bundle outState);
  134 +}
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/delegate/FragmentMvpDelegateImpl.java 0 → 100644
  1 +/*
  2 + * Copyright 2015 Hannes Dorfmann.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package com.hannesdorfmann.mosby3.mvp.delegate;
  18 +
  19 +import android.app.Activity;
  20 +import android.content.Context;
  21 +import android.os.Bundle;
  22 +import android.util.Log;
  23 +import android.view.View;
  24 +
  25 +import androidx.annotation.NonNull;
  26 +import androidx.annotation.Nullable;
  27 +import androidx.fragment.app.Fragment;
  28 +
  29 +import com.hannesdorfmann.mosby3.PresenterManager;
  30 +import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
  31 +import com.hannesdorfmann.mosby3.mvp.MvpView;
  32 +
  33 +import java.util.UUID;
  34 +
  35 +/**
  36 + * The default implementation of {@link FragmentMvpDelegate}
  37 + * Presenter is available (has view that is attached) in {@link #onViewCreated(View, Bundle)} (after
  38 + * super.onViewCreated() is called). View will be detached in {@link #onDestroyView()} from presenter,
  39 + * and eventually presenter will be destroyed in {@link #onDestroy()}.
  40 + *
  41 + * @param <V> The type of {@link MvpView}
  42 + * @param <P> The type of {@link MvpPresenter}
  43 + * @author Hannes Dorfmann
  44 + * @see FragmentMvpDelegate
  45 + * @since 1.1.0
  46 + */
  47 +public class FragmentMvpDelegateImpl<V extends MvpView, P extends MvpPresenter<V>>
  48 + implements FragmentMvpDelegate<V, P> {
  49 +
  50 + protected static final String KEY_MOSBY_VIEW_ID = "com.hannesdorfmann.mosby3.fragment.mvp.id";
  51 +
  52 + public static boolean DEBUG = false;
  53 + private static final String DEBUG_TAG = "FragmentMvpVSDelegate";
  54 +
  55 + private MvpDelegateCallback<V, P> delegateCallback;
  56 + protected Fragment fragment;
  57 + protected final boolean keepPresenterInstanceDuringScreenOrientationChanges;
  58 + protected final boolean keepPresenterOnBackstack;
  59 + private boolean onViewCreatedCalled = false;
  60 + protected String mosbyViewId;
  61 +
  62 + /**
  63 + * @param fragment The Fragment
  64 + * @param delegateCallback the DelegateCallback
  65 + * @param keepPresenterDuringScreenOrientationChange true, if the presenter should be kept during
  66 + * screen orientation
  67 + * changes. Otherwise, false
  68 + * @param keepPresenterOnBackstack true, if the presenter should be kept when the fragment is
  69 + * destroyed because it is put on the backstack, Otherwise false
  70 + */
  71 + public FragmentMvpDelegateImpl(@NonNull Fragment fragment,
  72 + @NonNull MvpDelegateCallback<V, P> delegateCallback,
  73 + boolean keepPresenterDuringScreenOrientationChange, boolean keepPresenterOnBackstack) {
  74 + if (delegateCallback == null) {
  75 + throw new NullPointerException("MvpDelegateCallback is null!");
  76 + }
  77 +
  78 + if (fragment == null) {
  79 + throw new NullPointerException("Fragment is null!");
  80 + }
  81 +
  82 + if (!keepPresenterDuringScreenOrientationChange && keepPresenterOnBackstack) {
  83 + throw new IllegalArgumentException("It is not possible to keep the presenter on backstack, "
  84 + + "but NOT keep presenter through screen orientation changes. Keep presenter on backstack also "
  85 + + "requires keep presenter through screen orientation changes to be enabled");
  86 + }
  87 +
  88 + this.fragment = fragment;
  89 + this.delegateCallback = delegateCallback;
  90 + this.keepPresenterInstanceDuringScreenOrientationChanges =
  91 + keepPresenterDuringScreenOrientationChange;
  92 + this.keepPresenterOnBackstack = keepPresenterOnBackstack;
  93 + }
  94 +
  95 + /**
  96 + * Generates the unique (mosby internal) view id and calls {@link
  97 + * MvpDelegateCallback#createPresenter()}
  98 + * to create a new presenter instance
  99 + *
  100 + * @return The new created presenter instance
  101 + */
  102 + private P createViewIdAndCreatePresenter() {
  103 +
  104 + P presenter = delegateCallback.createPresenter();
  105 + if (presenter == null) {
  106 + throw new NullPointerException(
  107 + "Presenter returned from createPresenter() is null. Activity is " + getActivity());
  108 + }
  109 + if (keepPresenterInstanceDuringScreenOrientationChanges) {
  110 + mosbyViewId = UUID.randomUUID().toString();
  111 + PresenterManager.putPresenter(getActivity(), mosbyViewId, presenter);
  112 + }
  113 + return presenter;
  114 + }
  115 +
  116 + @Override
  117 + public void onViewCreated(View view, @Nullable Bundle bundle) {
  118 +
  119 + P presenter = getPresenter();
  120 + presenter.attachView(getMvpView());
  121 +
  122 + if (DEBUG) {
  123 + Log.d(DEBUG_TAG, "View" + getMvpView() + " attached to Presenter " + presenter);
  124 + }
  125 +
  126 + onViewCreatedCalled = true;
  127 + }
  128 +
  129 + @NonNull
  130 + private Activity getActivity() {
  131 + Activity activity = fragment.getActivity();
  132 + if (activity == null) {
  133 + throw new NullPointerException(
  134 + "Activity returned by Fragment.getActivity() is null. Fragment is " + fragment);
  135 + }
  136 +
  137 + return activity;
  138 + }
  139 +
  140 + private P getPresenter() {
  141 + P presenter = delegateCallback.getPresenter();
  142 + if (presenter == null) {
  143 + throw new NullPointerException("Presenter returned from getPresenter() is null");
  144 + }
  145 + return presenter;
  146 + }
  147 +
  148 + private V getMvpView() {
  149 + V view = delegateCallback.getMvpView();
  150 + if (view == null) {
  151 + throw new NullPointerException("View returned from getMvpView() is null");
  152 + }
  153 + return view;
  154 + }
  155 +
  156 + static boolean retainPresenterInstance(Activity activity, Fragment fragment,
  157 + boolean keepPresenterInstanceDuringScreenOrientationChanges,
  158 + boolean keepPresenterOnBackstack) {
  159 +
  160 + if (activity.isChangingConfigurations()) {
  161 + return keepPresenterInstanceDuringScreenOrientationChanges;
  162 + }
  163 +
  164 + if (activity.isFinishing()) {
  165 + return false;
  166 + }
  167 +//todo 修改androidx
  168 + if (keepPresenterOnBackstack && BackstackAccessor.isInBackStackAndroidX(fragment)) {
  169 + return true;
  170 + }
  171 +
  172 + return !fragment.isRemoving();
  173 + }
  174 +
  175 + @Override
  176 + public void onDestroyView() {
  177 +
  178 + onViewCreatedCalled = false;
  179 +
  180 + getPresenter().detachView();
  181 +
  182 + if (DEBUG) {
  183 + Log.d(DEBUG_TAG, "detached MvpView from Presenter. MvpView "
  184 + + delegateCallback.getMvpView()
  185 + + " Presenter: "
  186 + + getPresenter());
  187 + }
  188 + }
  189 +
  190 + @Override
  191 + public void onPause() {
  192 +
  193 + }
  194 +
  195 + @Override
  196 + public void onResume() {
  197 +
  198 + }
  199 +
  200 + @Override
  201 + public void onStart() {
  202 +
  203 + if (!onViewCreatedCalled) {
  204 + throw new IllegalStateException("It seems that you are using "
  205 + + delegateCallback.getClass().getCanonicalName()
  206 + + " as headless (UI less) fragment (because onViewCreated() has not been called or maybe delegation misses that part). Having a Presenter without a View (UI) doesn't make sense. Simply use an usual fragment instead of an MvpFragment if you want to use a UI less Fragment");
  207 + }
  208 + }
  209 +
  210 + @Override
  211 + public void onStop() {
  212 +
  213 + }
  214 +
  215 + @Override
  216 + public void onActivityCreated(Bundle savedInstanceState) {
  217 +
  218 + }
  219 +
  220 + @Override
  221 + public void onAttach(Activity activity) {
  222 +
  223 + }
  224 +
  225 + @Override
  226 + public void onAttach(Context context) {
  227 +
  228 + }
  229 +
  230 + @Override
  231 + public void onDetach() {
  232 +
  233 + }
  234 +
  235 + @Override
  236 + public void onSaveInstanceState(Bundle outState) {
  237 + if ((keepPresenterInstanceDuringScreenOrientationChanges || keepPresenterOnBackstack)
  238 + && outState != null) {
  239 + outState.putString(KEY_MOSBY_VIEW_ID, mosbyViewId);
  240 +
  241 + if (DEBUG) {
  242 + Log.d(DEBUG_TAG, "Saving MosbyViewId into Bundle. ViewId: " + mosbyViewId);
  243 + }
  244 + }
  245 + }
  246 +
  247 + @Override
  248 + public void onCreate(Bundle bundle) {
  249 +
  250 + P presenter = null;
  251 +
  252 + if (bundle != null && keepPresenterInstanceDuringScreenOrientationChanges) {
  253 +
  254 + mosbyViewId = bundle.getString(KEY_MOSBY_VIEW_ID);
  255 +
  256 + if (DEBUG) {
  257 + Log.d(DEBUG_TAG,
  258 + "MosbyView ID = " + mosbyViewId + " for MvpView: " + delegateCallback.getMvpView());
  259 + }
  260 +
  261 + if (mosbyViewId != null
  262 + && (presenter = PresenterManager.getPresenter(getActivity(), mosbyViewId)) != null) {
  263 + //
  264 + // Presenter restored from cache
  265 + //
  266 + if (DEBUG) {
  267 + Log.d(DEBUG_TAG,
  268 + "Reused presenter " + presenter + " for view " + delegateCallback.getMvpView());
  269 + }
  270 + } else {
  271 + //
  272 + // No presenter found in cache, most likely caused by process death
  273 + //
  274 + presenter = createViewIdAndCreatePresenter();
  275 + if (DEBUG) {
  276 + Log.d(DEBUG_TAG, "No presenter found although view Id was here: "
  277 + + mosbyViewId
  278 + + ". Most likely this was caused by a process death. New Presenter created"
  279 + + presenter
  280 + + " for view "
  281 + + getMvpView());
  282 + }
  283 + }
  284 + } else {
  285 + //
  286 + // Activity starting first time, so create a new presenter
  287 + //
  288 + presenter = createViewIdAndCreatePresenter();
  289 + if (DEBUG) {
  290 + Log.d(DEBUG_TAG, "New presenter " + presenter + " for view " + getMvpView());
  291 + }
  292 + }
  293 +
  294 + if (presenter == null) {
  295 + throw new IllegalStateException(
  296 + "Oops, Presenter is null. This seems to be a Mosby internal bug. Please report this issue here: https://github.com/sockeqwe/mosby/issues");
  297 + }
  298 +
  299 + delegateCallback.setPresenter(presenter);
  300 + }
  301 +
  302 + @Override
  303 + public void onDestroy() {
  304 +
  305 + Activity activity = getActivity();
  306 + boolean retainPresenterInstance = retainPresenterInstance(activity, fragment,
  307 + keepPresenterInstanceDuringScreenOrientationChanges, keepPresenterOnBackstack);
  308 +
  309 + P presenter = getPresenter();
  310 + if (!retainPresenterInstance) {
  311 + presenter.destroy();
  312 + if (DEBUG) {
  313 + Log.d(DEBUG_TAG, "Presenter destroyed. MvpView "
  314 + + delegateCallback.getMvpView()
  315 + + " Presenter: "
  316 + + presenter);
  317 + }
  318 + }
  319 +
  320 + if (!retainPresenterInstance && mosbyViewId != null) {
  321 + // mosbyViewId is null if keepPresenterInstanceDuringScreenOrientationChanges == false
  322 + PresenterManager.remove(activity, mosbyViewId);
  323 + }
  324 + }
  325 +}
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/delegate/MvpDelegateCallback.java 0 → 100644
  1 +/*
  2 + * Copyright 2015 Hannes Dorfmann.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package com.hannesdorfmann.mosby3.mvp.delegate;
  18 +
  19 +
  20 +import androidx.annotation.NonNull;
  21 +
  22 +import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
  23 +import com.hannesdorfmann.mosby3.mvp.MvpView;
  24 +
  25 +/**
  26 + * The MvpDelegate callback that will be called from {@link
  27 + * FragmentMvpDelegate} or {@link ViewGroupMvpDelegate}. This interface must be implemented by all
  28 + * Fragment or android.view.View that you want to support Mosby mvp.
  29 + *
  30 + * @param <V> The type of {@link MvpView}
  31 + * @param <P> The type of {@link MvpPresenter}
  32 + * @author Hannes Dorfmann
  33 + * @since 1.1.0
  34 + */
  35 +public interface MvpDelegateCallback<V extends MvpView, P extends MvpPresenter<V>> {
  36 +
  37 + /**
  38 + * Creates the presenter instance
  39 + *
  40 + * @return the created presenter instance
  41 + */
  42 + @NonNull
  43 + P createPresenter();
  44 +
  45 + /**
  46 + * Gets the presenter. If null is returned, then a internally a new presenter instance gets
  47 + * created by calling {@link #createPresenter()}
  48 + *
  49 + * @return the presenter instance. can be null.
  50 + */
  51 + P getPresenter();
  52 +
  53 + /**
  54 + * Sets the presenter instance
  55 + *
  56 + * @param presenter The presenter instance
  57 + */
  58 + void setPresenter(P presenter);
  59 +
  60 + /**
  61 + * Gets the MvpView for the presenter
  62 + *
  63 + * @return The view associated with the presenter
  64 + */
  65 + V getMvpView();
  66 +}
  67 +
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/delegate/ViewGroupDelegateCallback.java 0 → 100644
  1 +/*
  2 + * Copyright 2015 Hannes Dorfmann.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package com.hannesdorfmann.mosby3.mvp.delegate;
  18 +
  19 +import android.content.Context;
  20 +import android.os.Parcelable;
  21 +import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
  22 +import com.hannesdorfmann.mosby3.mvp.MvpView;
  23 +
  24 +/**
  25 + * An enhanced version of {@link MvpDelegateCallback} that adds support for
  26 + * android.view.View like FrameLayout etc.
  27 + *
  28 + * @author Hannes Dorfmann
  29 + * @since 3.0
  30 + */
  31 +public interface ViewGroupDelegateCallback<V extends MvpView, P extends MvpPresenter<V>>
  32 + extends MvpDelegateCallback<V, P> {
  33 +
  34 + /**
  35 + * This method must call super.onSaveInstanceState() within any view
  36 + */
  37 + Parcelable superOnSaveInstanceState();
  38 +
  39 + /**
  40 + * This method must call super.onRestoreInstanceState(state)
  41 + *
  42 + * @param state The parcelable containing the state
  43 + */
  44 + void superOnRestoreInstanceState(Parcelable state);
  45 +
  46 + /**
  47 + * Get the context
  48 + *
  49 + * @return Get the context
  50 + * @since 3.0
  51 + */
  52 + Context getContext();
  53 +}
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/delegate/ViewGroupMvpDelegate.java 0 → 100644
  1 +/*
  2 + * Copyright 2015 Hannes Dorfmann.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package com.hannesdorfmann.mosby3.mvp.delegate;
  18 +
  19 +import android.os.Parcelable;
  20 +import android.view.View;
  21 +import android.widget.FrameLayout;
  22 +import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
  23 +import com.hannesdorfmann.mosby3.mvp.MvpView;
  24 +
  25 +/**
  26 + * The mvp delegate used for everything that derives from {@link View} like {@link FrameLayout}
  27 + * etc.
  28 + *
  29 + * <p>
  30 + * The following methods must be called from the corresponding View lifecycle method:
  31 + * <ul>
  32 + * <li>{@link #onAttachedToWindow()}</li>
  33 + * <li>{@link #onDetachedFromWindow()}</li>
  34 + * </ul>
  35 + * </p>
  36 + *
  37 + * @author Hannes Dorfmann
  38 + * @since 1.1.0
  39 + */
  40 +public interface ViewGroupMvpDelegate<V extends MvpView, P extends MvpPresenter<V>> {
  41 +
  42 + /**
  43 + * Must be called from {@link View#onAttachedToWindow()}
  44 + */
  45 + void onAttachedToWindow();
  46 +
  47 + /**
  48 + * Must be called from {@link View#onDetachedFromWindow()}
  49 + */
  50 + void onDetachedFromWindow();
  51 +
  52 + /**
  53 + * Must be called from {@link View#onRestoreInstanceState(Parcelable)}
  54 + *
  55 + * @param state The parcelable state
  56 + */
  57 + void onRestoreInstanceState(Parcelable state);
  58 +
  59 + /**
  60 + * Save the instatnce state
  61 + *
  62 + * @return The state with all the saved data
  63 + */
  64 + Parcelable onSaveInstanceState();
  65 +}
core/base/src/main/java/com/hannesdorfmann/mosby3/mvp/delegate/ViewGroupMvpDelegateImpl.java 0 → 100644
  1 +/*
  2 + * Copyright 2017 Hannes Dorfmann.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + *
  16 + */
  17 +
  18 +package com.hannesdorfmann.mosby3.mvp.delegate;
  19 +
  20 +import android.app.Activity;
  21 +import android.app.Application;
  22 +import android.content.Context;
  23 +import android.os.Bundle;
  24 +import android.os.Parcelable;
  25 +import android.util.Log;
  26 +import android.view.View;
  27 +import android.widget.FrameLayout;
  28 +
  29 +import androidx.annotation.NonNull;
  30 +
  31 +import com.hannesdorfmann.mosby3.MosbySavedState;
  32 +import com.hannesdorfmann.mosby3.PresenterManager;
  33 +import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
  34 +import com.hannesdorfmann.mosby3.mvp.MvpView;
  35 +import java.util.UUID;
  36 +
  37 +/**
  38 + * The mvp delegate used for everything that derives from {@link View} like {@link FrameLayout}
  39 + * etc.
  40 + *
  41 + * <p>
  42 + * The following methods must be called from the corresponding View lifecycle method:
  43 + * <ul>
  44 + * <li>{@link #onAttachedToWindow()}</li>
  45 + * <li>{@link #onDetachedFromWindow()}</li>
  46 + * </ul>
  47 + * </p>
  48 + *
  49 + * @author Hannes Dorfmann
  50 + * @since 1.1.0
  51 + */
  52 +public class ViewGroupMvpDelegateImpl<V extends MvpView, P extends MvpPresenter<V>>
  53 + implements ViewGroupMvpDelegate<V, P>, Application.ActivityLifecycleCallbacks {
  54 +
  55 + // TODO allow custom save state hook in
  56 +
  57 + public static boolean DEBUG = false;
  58 + private static final String DEBUG_TAG = "ViewGroupMvpDelegateImp";
  59 +
  60 + private ViewGroupDelegateCallback<V, P> delegateCallback;
  61 + private String mosbyViewId;
  62 + private final boolean keepPresenterDuringScreenOrientationChange;
  63 + private final Activity activity;
  64 + private final boolean isInEditMode;
  65 +
  66 + private boolean checkedActivityFinishing = false;
  67 + private boolean presenterDetached = false;
  68 + private boolean presenterDestroyed = false;
  69 +
  70 + public ViewGroupMvpDelegateImpl(@NonNull View view,
  71 + @NonNull ViewGroupDelegateCallback<V, P> delegateCallback,
  72 + boolean keepPresenterDuringScreenOrientationChange) {
  73 + if (view == null) {
  74 + throw new NullPointerException("View is null!");
  75 + }
  76 +
  77 + if (delegateCallback == null) {
  78 + throw new NullPointerException("MvpDelegateCallback is null!");
  79 + }
  80 +
  81 + this.delegateCallback = delegateCallback;
  82 + this.keepPresenterDuringScreenOrientationChange = keepPresenterDuringScreenOrientationChange;
  83 +
  84 + isInEditMode = view.isInEditMode();
  85 +
  86 + if (!isInEditMode) {
  87 + this.activity = PresenterManager.getActivity(delegateCallback.getContext());
  88 + this.activity.getApplication().registerActivityLifecycleCallbacks(this);
  89 + } else {
  90 + this.activity = null;
  91 + }
  92 + }
  93 +
  94 + /**
  95 + * Generates the unique (mosby internal) viewState id and calls {@link
  96 + * MvpDelegateCallback#createPresenter()}
  97 + * to create a new presenter instance
  98 + *
  99 + * @return The new created presenter instance
  100 + */
  101 + protected P createViewIdAndCreatePresenter() {
  102 +
  103 + P presenter = delegateCallback.createPresenter();
  104 + if (presenter == null) {
  105 + throw new NullPointerException("Presenter returned from createPresenter() is null.");
  106 + }
  107 + if (keepPresenterDuringScreenOrientationChange) {
  108 + Context context = delegateCallback.getContext();
  109 + mosbyViewId = UUID.randomUUID().toString();
  110 + PresenterManager.putPresenter(PresenterManager.getActivity(context), mosbyViewId, presenter);
  111 + }
  112 + return presenter;
  113 + }
  114 +
  115 + @NonNull private Context getContext() {
  116 + Context c = delegateCallback.getContext();
  117 + if (c == null) {
  118 + throw new NullPointerException("Context returned from " + delegateCallback + " is null");
  119 + }
  120 + return c;
  121 + }
  122 +
  123 + @Override public void onAttachedToWindow() {
  124 + if (isInEditMode) return;
  125 +
  126 + P presenter = null;
  127 + if (mosbyViewId == null) {
  128 + // No presenter available,
  129 + // Activity is starting for the first time (or keepPresenterInstance == false)
  130 + presenter = createViewIdAndCreatePresenter();
  131 + if (DEBUG) {
  132 + Log.d(DEBUG_TAG, "new Presenter instance created: " + presenter);
  133 + }
  134 + } else {
  135 + presenter = PresenterManager.getPresenter(activity, mosbyViewId);
  136 + if (presenter == null) {
  137 + // Process death,
  138 + // hence no presenter with the given viewState id stored, although we have a viewState id
  139 + presenter = createViewIdAndCreatePresenter();
  140 + if (DEBUG) {
  141 + Log.d(DEBUG_TAG,
  142 + "No Presenter instance found in cache, although MosbyView ID present. This was caused by process death, therefore new Presenter instance created: "
  143 + + presenter);
  144 + }
  145 + } else {
  146 + if (DEBUG) {
  147 + Log.d(DEBUG_TAG, "Presenter instance reused from internal cache: " + presenter);
  148 + }
  149 + }
  150 + }
  151 +
  152 + // presenter is ready, so attach viewState
  153 + V view = delegateCallback.getMvpView();
  154 + if (view == null) {
  155 + throw new NullPointerException(
  156 + "MvpView returned from getMvpView() is null. Returned by " + delegateCallback);
  157 + }
  158 +
  159 + if (presenter == null) {
  160 + throw new IllegalStateException(
  161 + "Oops, Presenter is null. This seems to be a Mosby internal bug. Please report this issue here: https://github.com/sockeqwe/mosby/issues");
  162 + }
  163 +
  164 + /*
  165 + if (viewStateWillBeRestored) {
  166 + delegateCallback.setRestoringViewState(true);
  167 + }
  168 + */
  169 +
  170 + delegateCallback.setPresenter(presenter);
  171 + presenter.attachView(view);
  172 +
  173 + /*
  174 + if (viewStateWillBeRestored) {
  175 + delegateCallback.setRestoringViewState(false);
  176 + }
  177 + */
  178 +
  179 + if (DEBUG) {
  180 + Log.d(DEBUG_TAG,
  181 + "MvpView attached to Presenter. MvpView: " + view + " Presenter: " + presenter);
  182 + }
  183 + }
  184 +
  185 + /**
  186 + * Must be called from {@link View#onSaveInstanceState()}
  187 + */
  188 + public Parcelable onSaveInstanceState() {
  189 + if (isInEditMode) return null;
  190 +
  191 + Parcelable superState = delegateCallback.superOnSaveInstanceState();
  192 +
  193 + if (keepPresenterDuringScreenOrientationChange) {
  194 + return new MosbySavedState(superState, mosbyViewId);
  195 + } else {
  196 + return superState;
  197 + }
  198 + }
  199 +
  200 + /**
  201 + * Restore the data from SavedState
  202 + *
  203 + * @param state The state to read data from
  204 + */
  205 + private void restoreSavedState(MosbySavedState state) {
  206 + mosbyViewId = state.getMosbyViewId();
  207 + }
  208 +
  209 + /**
  210 + * Must be called from {@link View#onRestoreInstanceState(Parcelable)}
  211 + */
  212 + public void onRestoreInstanceState(Parcelable state) {
  213 + if (isInEditMode) return;
  214 +
  215 + if (!(state instanceof MosbySavedState)) {
  216 + delegateCallback.superOnRestoreInstanceState(state);
  217 + return;
  218 + }
  219 +
  220 + MosbySavedState savedState = (MosbySavedState) state;
  221 + restoreSavedState(savedState);
  222 + delegateCallback.superOnRestoreInstanceState(savedState.getSuperState());
  223 + }
  224 +
  225 + @Override public void onDetachedFromWindow() {
  226 + if (isInEditMode) return;
  227 +
  228 + detachPresenterIfNotDoneYet();
  229 +
  230 + if (!checkedActivityFinishing) {
  231 +
  232 + boolean destroyPermanently = !ActivityMvpDelegateImpl.retainPresenterInstance(
  233 + keepPresenterDuringScreenOrientationChange, activity);
  234 +
  235 + if (destroyPermanently) {
  236 + destroyPresenterIfNotDoneYet();
  237 + } else if (!activity.isChangingConfigurations()) {
  238 + // View removed manually from screen
  239 + destroyPresenterIfNotDoneYet();
  240 + }
  241 + } // else --> see onActivityDestroyed()
  242 + }
  243 +
  244 + @Override public void onActivityDestroyed(Activity activity) {
  245 +
  246 + if (activity == this.activity) {
  247 + // The hosting activity of this view has been destroyed, so time to destroy the presenter too?
  248 +
  249 + activity.getApplication().unregisterActivityLifecycleCallbacks(this);
  250 + checkedActivityFinishing = true;
  251 +
  252 + boolean destroyedPermanently = !ActivityMvpDelegateImpl.retainPresenterInstance(
  253 + keepPresenterDuringScreenOrientationChange, activity);
  254 +
  255 + if (destroyedPermanently) {
  256 + // Whole activity will be destroyed
  257 + detachPresenterIfNotDoneYet();
  258 + destroyPresenterIfNotDoneYet();
  259 + }
  260 + }
  261 +
  262 + }
  263 +
  264 + @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
  265 + }
  266 +
  267 + @Override public void onActivityStarted(Activity activity) {
  268 + }
  269 +
  270 + @Override public void onActivityResumed(Activity activity) {
  271 + }
  272 +
  273 + @Override public void onActivityPaused(Activity activity) {
  274 + }
  275 +
  276 + @Override public void onActivityStopped(Activity activity) {
  277 + }
  278 +
  279 + @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
  280 + }
  281 +
  282 + private void destroyPresenterIfNotDoneYet() {
  283 + if (!presenterDestroyed) {
  284 + P presenter = delegateCallback.getPresenter();
  285 + if (presenter != null) {
  286 + presenter.destroy();
  287 + }
  288 + presenterDestroyed = true;
  289 + activity.getApplication().unregisterActivityLifecycleCallbacks(this);
  290 + if (DEBUG) {
  291 + Log.d(DEBUG_TAG, "Presenter destroyed: " + presenter);
  292 + }
  293 +
  294 + if (mosbyViewId != null) {
  295 + // mosbyViewId == null if keepPresenterDuringScreenOrientationChange == false
  296 + PresenterManager.remove(activity, mosbyViewId);
  297 + }
  298 + mosbyViewId = null;
  299 + }
  300 + }
  301 +
  302 + private void detachPresenterIfNotDoneYet() {
  303 + if (!presenterDetached) {
  304 + P presenter = delegateCallback.getPresenter();
  305 + if (presenter != null) {
  306 + presenter.detachView();
  307 + }
  308 + presenterDetached = true;
  309 + if (DEBUG) {
  310 + Log.d(DEBUG_TAG,
  311 + "view " + delegateCallback.getMvpView() + " detached from Presenter " + presenter);
  312 + }
  313 + }
  314 + }
  315 +}
core/network/src/main/AndroidManifest.xml
1 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 1 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2 - package="com.cnlive.strike.network" /> 2 + package="com.cnlive.strike.network">
  3 +
  4 + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  5 + <uses-permission android:name="android.permission.INTERNET" />
  6 +</manifest>
core/network/src/main/java/com/cnlive/core/network/converter/GsonConverterFactory.java 0 → 100644
  1 +package com.cnlive.core.network.converter;
  2 +
  3 +import com.google.gson.Gson;
  4 +import com.google.gson.TypeAdapter;
  5 +import com.google.gson.reflect.TypeToken;
  6 +
  7 +import java.lang.annotation.Annotation;
  8 +import java.lang.reflect.Type;
  9 +
  10 +import okhttp3.RequestBody;
  11 +import okhttp3.ResponseBody;
  12 +import retrofit2.Converter;
  13 +import retrofit2.Retrofit;
  14 +
  15 +public final class GsonConverterFactory extends Converter.Factory {
  16 +
  17 + private boolean decode = false;
  18 +
  19 + /**
  20 + * Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
  21 + * decoding from JSON (when no charset is specified by a header) will use UTF-8.
  22 + */
  23 + public static GsonConverterFactory create() {
  24 + return create(new Gson(), false);
  25 + }
  26 +
  27 + public static GsonConverterFactory create(boolean decode) {
  28 + return create(new Gson(), decode);
  29 + }
  30 +
  31 + /**
  32 + * Create an instance using {@code gson} for conversion. Encoding to JSON and
  33 + * decoding from JSON (when no charset is specified by a header) will use UTF-8.
  34 + */
  35 + @SuppressWarnings("ConstantConditions") // Guarding public API nullability.
  36 + public static GsonConverterFactory create(Gson gson, boolean decode) {
  37 + if (gson == null) throw new NullPointerException("gson == null");
  38 + return new GsonConverterFactory(gson, decode);
  39 + }
  40 +
  41 + private final Gson gson;
  42 +
  43 + private GsonConverterFactory(Gson gson, boolean decode) {
  44 + this.gson = gson;
  45 + this.decode = decode;
  46 + }
  47 +
  48 + @Override
  49 + public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
  50 + Retrofit retrofit) {
  51 + TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
  52 + return new GsonResponseBodyConverter<>(gson, adapter, decode);
  53 + }
  54 +
  55 + @Override
  56 + public Converter<?, RequestBody> requestBodyConverter(Type type,
  57 + Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
  58 + TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
  59 + return new GsonRequestBodyConverter<>(gson, adapter);
  60 + }
  61 +}
core/network/src/main/java/com/cnlive/core/network/converter/GsonRequestBodyConverter.java 0 → 100644
  1 +package com.cnlive.core.network.converter;
  2 +
  3 +import com.google.gson.Gson;
  4 +import com.google.gson.TypeAdapter;
  5 +import com.google.gson.stream.JsonWriter;
  6 +
  7 +import java.io.IOException;
  8 +import java.io.OutputStreamWriter;
  9 +import java.io.Writer;
  10 +import java.nio.charset.Charset;
  11 +
  12 +import okhttp3.MediaType;
  13 +import okhttp3.RequestBody;
  14 +import okio.Buffer;
  15 +import retrofit2.Converter;
  16 +
  17 +final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
  18 + private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
  19 + private static final Charset UTF_8 = Charset.forName("UTF-8");
  20 +
  21 + private final Gson gson;
  22 + private final TypeAdapter<T> adapter;
  23 +
  24 + GsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
  25 + this.gson = gson;
  26 + this.adapter = adapter;
  27 + }
  28 +
  29 + @Override
  30 + public RequestBody convert(T value) throws IOException {
  31 + Buffer buffer = new Buffer();
  32 + Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
  33 + JsonWriter jsonWriter = gson.newJsonWriter(writer);
  34 + adapter.write(jsonWriter, value);
  35 + jsonWriter.close();
  36 + return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
  37 + }
  38 +}
0 \ No newline at end of file 39 \ No newline at end of file
core/network/src/main/java/com/cnlive/core/network/converter/GsonResponseBodyConverter.java 0 → 100644
  1 +package com.cnlive.core.network.converter;
  2 +
  3 +import com.cnlive.core.libs.base.util.StringUtils;
  4 +import com.google.gson.Gson;
  5 +import com.google.gson.TypeAdapter;
  6 +import com.google.gson.stream.JsonReader;
  7 +
  8 +import java.io.BufferedReader;
  9 +import java.io.IOException;
  10 +import java.io.Reader;
  11 +
  12 +import okhttp3.ResponseBody;
  13 +import retrofit2.Converter;
  14 +
  15 +final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
  16 + private boolean decode;
  17 + private final Gson gson;
  18 + private final TypeAdapter<T> adapter;
  19 +
  20 + GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter, boolean decode) {
  21 + this.gson = gson;
  22 + this.adapter = adapter;
  23 + this.decode = decode;
  24 + }
  25 +
  26 + @Override
  27 + public T convert(ResponseBody value) throws IOException {
  28 + if (decode) {
  29 + try {
  30 + return adapter.fromJson(convert(value.charStream()));
  31 + } finally {
  32 + value.close();
  33 + }
  34 + } else {
  35 + JsonReader jsonReader = gson.newJsonReader(value.charStream());
  36 + try {
  37 + return adapter.read(jsonReader);
  38 + } finally {
  39 + value.close();
  40 + }
  41 + }
  42 + }
  43 +
  44 + private static String convert(Reader reader) throws IOException {
  45 + BufferedReader r = new BufferedReader(reader);
  46 + StringBuilder b = new StringBuilder();
  47 + String line;
  48 + while ((line = r.readLine()) != null) b.append(line);
  49 + return StringUtils.decode(b.toString());
  50 + }
  51 +}
0 \ No newline at end of file 52 \ No newline at end of file
core/network/src/main/java/com/cnlive/core/network/interceptor/ClientInterceptor.java 0 → 100644
  1 +package com.cnlive.core.network.interceptor;
  2 +
  3 +
  4 +import android.content.Context;
  5 +
  6 +import com.cnlive.core.libs.base.util.NetworkUtil;
  7 +
  8 +import java.io.IOException;
  9 +
  10 +import okhttp3.Interceptor;
  11 +import okhttp3.Request;
  12 +import okhttp3.Response;
  13 +
  14 +class ClientInterceptor implements Interceptor {
  15 +
  16 + private Context mContext;
  17 +
  18 + ClientInterceptor(Context context) {
  19 + mContext = context;
  20 + }
  21 +
  22 + @Override
  23 + public Response intercept(Chain chain) throws IOException {
  24 + Request request = chain.request();
  25 +
  26 + Response response = chain.proceed(request);
  27 + if (NetworkUtil.isConnectInternet(mContext)) {
  28 + int maxAge = 60 * 60; // read from cache for 1 minute
  29 + response.newBuilder()
  30 + .addHeader("Cache-Control", "public, max-age=" + maxAge)
  31 + .build();
  32 +
  33 + } else {
  34 + int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale
  35 + response.newBuilder()
  36 + .addHeader("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
  37 + .build();
  38 + }
  39 +
  40 + return response;
  41 + }
  42 +}
0 \ No newline at end of file 43 \ No newline at end of file
core/network/src/main/java/com/cnlive/core/network/interceptor/DESEncryptInterceptor.java 0 → 100644
  1 +package com.cnlive.core.network.interceptor;
  2 +
  3 +
  4 +import com.cnlive.core.network.util.SignUtil;
  5 +import com.cnlive.core.libs.base.application.AppConfig;
  6 +import com.cnlive.libs.encipher.CNLiveEncipher;
  7 +
  8 +import java.io.IOException;
  9 +import java.util.HashMap;
  10 +import java.util.Map;
  11 +
  12 +import okhttp3.FormBody;
  13 +import okhttp3.HttpUrl;
  14 +import okhttp3.Interceptor;
  15 +import okhttp3.MultipartBody;
  16 +import okhttp3.Request;
  17 +import okhttp3.RequestBody;
  18 +import okhttp3.Response;
  19 +
  20 +public class DESEncryptInterceptor implements Interceptor {
  21 + @Override
  22 + public Response intercept(Chain chain) throws IOException {
  23 + Request request = chain.request();
  24 +
  25 + if (request.body() instanceof FormBody) {
  26 + //处理方式 1
  27 + Map<String, String> parameter = new HashMap<>();
  28 +
  29 + FormBody body = ((FormBody) request.body());
  30 + FormBody.Builder builder = new FormBody.Builder();
  31 +
  32 + for (int i = 0; i < body.size(); i++) {
  33 + parameter.put(body.name(i), body.value(i));
  34 + }
  35 +
  36 + String param = SignUtil.mapJoin(parameter, false);
  37 +
  38 + String encrypt = CNLiveEncipher.encryptDES(AppConfig.getAppId(), param);
  39 +
  40 + Map<String, String> paramete = new HashMap<>();
  41 + paramete.put("id", AppConfig.getAppId());
  42 + paramete.put("param", encrypt);
  43 +
  44 + for (Map.Entry<String, String> entity : SignUtil.getOpenSignMap(paramete).entrySet()) {
  45 + builder.addEncoded(entity.getKey(), entity.getValue());
  46 + }
  47 + RequestBody newBody = builder.build();
  48 +
  49 + Request newRequest = request.newBuilder()
  50 + .method(request.method(), newBody)
  51 + .url(request.url())
  52 + .build();
  53 + return chain.proceed(newRequest);
  54 + } else if (request.body() instanceof MultipartBody) {
  55 + //处理方式 2 (暂时不签名)
  56 + } else {
  57 + //处理方式 3
  58 + HttpUrl.Builder authorizedUrlBuilder = request.url().newBuilder();
  59 +
  60 + Map<String, String> parameter = new HashMap<>();
  61 +
  62 + for (String key : request.url().queryParameterNames()) {
  63 + parameter.put(key, request.url().queryParameter(key));
  64 + authorizedUrlBuilder.removeAllQueryParameters(key);
  65 + }
  66 +
  67 + String param = SignUtil.mapJoin(parameter, false);
  68 +
  69 + String encrypt = CNLiveEncipher.encryptDES(AppConfig.getAppId(), param);
  70 +
  71 + Map<String, String> paramete = new HashMap<>();
  72 + paramete.put("id", AppConfig.getAppId());
  73 + paramete.put("param", encrypt);
  74 +
  75 + for (Map.Entry<String, String> entity : SignUtil.getOpenSignMap(paramete).entrySet()) {
  76 + authorizedUrlBuilder.addQueryParameter(entity.getKey(), entity.getValue());
  77 + }
  78 +
  79 + authorizedUrlBuilder.scheme(request.url().scheme());
  80 + authorizedUrlBuilder.host(request.url().host());
  81 +
  82 + Request newRequest = request.newBuilder()
  83 + .method(request.method(), request.body())
  84 + .url(authorizedUrlBuilder.build())
  85 + .build();
  86 + return chain.proceed(newRequest);
  87 + }
  88 +
  89 +
  90 + return chain.proceed(request);
  91 + }
  92 +
  93 +
  94 +}
0 \ No newline at end of file 95 \ No newline at end of file
core/network/src/main/java/com/cnlive/core/network/interceptor/DefaultEncryptInterceptor.java 0 → 100644
  1 +package com.cnlive.core.network.interceptor;
  2 +
  3 +
  4 +import java.io.IOException;
  5 +
  6 +import okhttp3.Interceptor;
  7 +import okhttp3.Request;
  8 +import okhttp3.Response;
  9 +
  10 +public class DefaultEncryptInterceptor implements Interceptor {
  11 + @Override
  12 + public Response intercept(Chain chain) throws IOException {
  13 + Request request = chain.request();
  14 + return chain.proceed(request);
  15 + }
  16 +}
0 \ No newline at end of file 17 \ No newline at end of file
core/network/src/main/java/com/cnlive/core/network/interceptor/NetPPEncryptInterceptor.java 0 → 100644
  1 +package com.cnlive.core.network.interceptor;
  2 +
  3 +
  4 +import com.cnlive.core.network.util.SignUtil;
  5 +
  6 +import java.io.IOException;
  7 +import java.util.HashMap;
  8 +import java.util.Map;
  9 +
  10 +import okhttp3.FormBody;
  11 +import okhttp3.HttpUrl;
  12 +import okhttp3.Interceptor;
  13 +import okhttp3.MultipartBody;
  14 +import okhttp3.Request;
  15 +import okhttp3.RequestBody;
  16 +import okhttp3.Response;
  17 +
  18 +public class NetPPEncryptInterceptor implements Interceptor {
  19 + @Override
  20 + public Response intercept(Chain chain) throws IOException {
  21 + Request request = chain.request();
  22 +
  23 + if (request.body() instanceof FormBody) {
  24 + //处理方式 1
  25 + Map<String, String> parameter = new HashMap<>();
  26 +
  27 + FormBody body = ((FormBody) request.body());
  28 + FormBody.Builder builder = new FormBody.Builder();
  29 +
  30 + for (int i = 0; i < body.size(); i++) {
  31 + parameter.put(body.name(i), body.value(i));
  32 + }
  33 +
  34 + for (Map.Entry<String, String> entity : SignUtil.getNetPPSignString(parameter).entrySet()) {
  35 + builder.addEncoded(entity.getKey(), entity.getValue());
  36 + }
  37 +
  38 + RequestBody newBody = builder.build();
  39 +
  40 + Request newRequest = request.newBuilder()
  41 + .method(request.method(), newBody)
  42 + .url(request.url())
  43 + .build();
  44 + return chain.proceed(newRequest);
  45 + } else if (request.body() instanceof MultipartBody) {
  46 + //处理方式 2 (暂时不签名)
  47 + } else {
  48 + if ("POST".equals(request.method())) {
  49 + //处理方式 3
  50 + HttpUrl.Builder authorizedUrlBuilder = request.url().newBuilder();
  51 + Map<String, String> parameter = new HashMap<>();
  52 +
  53 + for (String key : request.url().queryParameterNames()) {
  54 + parameter.put(key, request.url().queryParameter(key));
  55 + authorizedUrlBuilder.removeAllQueryParameters(key);
  56 + }
  57 +
  58 + FormBody.Builder builder = new FormBody.Builder();
  59 +
  60 + for (Map.Entry<String, String> entity : SignUtil.getNetPPSignString(parameter).entrySet()) {
  61 + builder.add(entity.getKey(), entity.getValue());
  62 + }
  63 +
  64 + RequestBody newBody = builder.build();
  65 +
  66 + Request newRequest = request.newBuilder()
  67 + .method(request.method(), newBody)
  68 + .url(authorizedUrlBuilder.build())
  69 + .build();
  70 + return chain.proceed(newRequest);
  71 + } else {
  72 + //处理方式 3
  73 + HttpUrl.Builder authorizedUrlBuilder = request.url().newBuilder();
  74 + Map<String, String> parameter = new HashMap<>();
  75 +
  76 + for (String key : request.url().queryParameterNames()) {
  77 + parameter.put(key, request.url().queryParameter(key));
  78 + authorizedUrlBuilder.removeAllQueryParameters(key);
  79 + }
  80 +
  81 + for (Map.Entry<String, String> entity : SignUtil.getNetPPSignString(parameter).entrySet()) {
  82 + authorizedUrlBuilder.addQueryParameter(entity.getKey(), entity.getValue());
  83 + }
  84 +
  85 + authorizedUrlBuilder.scheme(request.url().scheme());
  86 + authorizedUrlBuilder.host(request.url().host());
  87 +
  88 + Request newRequest = request.newBuilder()
  89 + .method(request.method(), request.body())
  90 + .url(authorizedUrlBuilder.build())
  91 + .build();
  92 + return chain.proceed(newRequest);
  93 + }
  94 + }
  95 +
  96 +
  97 + return chain.proceed(request);
  98 + }
  99 +
  100 +
  101 +}
0 \ No newline at end of file 102 \ No newline at end of file
core/network/src/main/java/com/cnlive/core/network/interceptor/NetPPPayEncryptInterceptor.java 0 → 100644
  1 +package com.cnlive.core.network.interceptor;
  2 +
  3 +
  4 +
  5 +import com.cnlive.core.network.util.SignUtil;
  6 +
  7 +import java.io.IOException;
  8 +import java.util.HashMap;
  9 +import java.util.Map;
  10 +
  11 +import okhttp3.FormBody;
  12 +import okhttp3.HttpUrl;
  13 +import okhttp3.Interceptor;
  14 +import okhttp3.MultipartBody;
  15 +import okhttp3.Request;
  16 +import okhttp3.RequestBody;
  17 +import okhttp3.Response;
  18 +
  19 +public class NetPPPayEncryptInterceptor implements Interceptor {
  20 + @Override
  21 + public Response intercept(Chain chain) throws IOException {
  22 + Request request = chain.request();
  23 +
  24 + if (request.body() instanceof FormBody) {
  25 + //处理方式 1
  26 + Map<String, String> parameter = new HashMap<>();
  27 +
  28 + FormBody body = ((FormBody) request.body());
  29 + FormBody.Builder builder = new FormBody.Builder();
  30 +
  31 + for (int i = 0; i < body.size(); i++) {
  32 + parameter.put(body.name(i), body.value(i));
  33 + }
  34 +
  35 + for (Map.Entry<String, String> entity : SignUtil.getNetPPPaySignString(parameter).entrySet()) {
  36 + builder.addEncoded(entity.getKey(), entity.getValue());
  37 + }
  38 +
  39 + RequestBody newBody = builder.build();
  40 +
  41 + Request newRequest = request.newBuilder()
  42 + .method(request.method(), newBody)
  43 + .url(request.url())
  44 + .build();
  45 + return chain.proceed(newRequest);
  46 + } else if (request.body() instanceof MultipartBody) {
  47 + //处理方式 2 (暂时不签名)
  48 + } else {
  49 + if ("POST".equals(request.method())) {
  50 + //处理方式 3
  51 + HttpUrl.Builder authorizedUrlBuilder = request.url().newBuilder();
  52 +
  53 + Map<String, String> parameter = new HashMap<>();
  54 +
  55 + for (String key : request.url().queryParameterNames()) {
  56 + parameter.put(key, request.url().queryParameter(key));
  57 + authorizedUrlBuilder.removeAllQueryParameters(key);
  58 + }
  59 +
  60 + FormBody.Builder builder = new FormBody.Builder();
  61 +
  62 + for (Map.Entry<String, String> entity : SignUtil.getNetPPPaySignString(parameter).entrySet()) {
  63 + builder.add(entity.getKey(), entity.getValue());
  64 + }
  65 +
  66 + RequestBody newBody = builder.build();
  67 +
  68 + Request newRequest = request.newBuilder()
  69 + .method(request.method(), newBody)
  70 + .url(authorizedUrlBuilder.build())
  71 + .build();
  72 + return chain.proceed(newRequest);
  73 + }else{
  74 + //处理方式 3
  75 + HttpUrl.Builder authorizedUrlBuilder = request.url().newBuilder();
  76 +
  77 + Map<String, String> parameter = new HashMap<>();
  78 +
  79 + for (String key : request.url().queryParameterNames()) {
  80 + parameter.put(key, request.url().queryParameter(key));
  81 + authorizedUrlBuilder.removeAllQueryParameters(key);
  82 + }
  83 +
  84 + for (Map.Entry<String, String> entity : SignUtil.getNetPPPaySignString(parameter).entrySet()) {
  85 + authorizedUrlBuilder.addQueryParameter(entity.getKey(), entity.getValue());
  86 + }
  87 +
  88 + authorizedUrlBuilder.scheme(request.url().scheme());
  89 + authorizedUrlBuilder.host(request.url().host());
  90 +
  91 + Request newRequest = request.newBuilder()
  92 + .method(request.method(), request.body())
  93 + .url(authorizedUrlBuilder.build())
  94 + .build();
  95 + return chain.proceed(newRequest);
  96 + }
  97 + }
  98 +
  99 +
  100 + return chain.proceed(request);
  101 + }
  102 +
  103 +
  104 +}
0 \ No newline at end of file 105 \ No newline at end of file
core/network/src/main/java/com/cnlive/core/network/interceptor/OffLineInterceptor.java 0 → 100644
  1 +package com.cnlive.core.network.interceptor;
  2 +
  3 +import android.content.Context;
  4 +
  5 +import com.cnlive.core.libs.base.util.NetworkUtil;
  6 +
  7 +import java.io.IOException;
  8 +
  9 +import okhttp3.Interceptor;
  10 +import okhttp3.Request;
  11 +
  12 +/**
  13 + * Created by xiansong on 2018/4/4.
  14 + */
  15 +
  16 +public class OffLineInterceptor implements Interceptor {
  17 +
  18 + private static final int TIMEOUT_DISCONNECT = 60 * 60 * 24 * 7; //7天
  19 +
  20 + private Context mContext;
  21 +
  22 + public OffLineInterceptor(Context context) {
  23 + mContext = context;
  24 + }
  25 +
  26 + @Override
  27 + public okhttp3.Response intercept(Chain chain) throws IOException {
  28 + Request request = chain.request();
  29 + //离线的时候为7天的缓存。
  30 + if (!NetworkUtil.isConnectInternet(mContext)) {
  31 + request = request.newBuilder()
  32 + .header("Cache-Control", "public, only-if-cached, max-stale=" + TIMEOUT_DISCONNECT)
  33 + .build();
  34 + }
  35 + return chain.proceed(request);
  36 + }
  37 +}
core/network/src/main/java/com/cnlive/core/network/interceptor/OnLineInterceptor.java 0 → 100644
  1 +package com.cnlive.core.network.interceptor;
  2 +
  3 +import java.io.IOException;
  4 +
  5 +import okhttp3.Interceptor;
  6 +
  7 +/**
  8 + * Created by xiansong on 2018/4/4.
  9 + */
  10 +
  11 +public class OnLineInterceptor implements Interceptor {
  12 +
  13 + private static final int TIMEOUT_CONNECT = 5; //5秒
  14 +
  15 + @Override
  16 + public okhttp3.Response intercept(Chain chain) throws IOException {
  17 + //获取retrofit @headers里面的参数,参数可以自己定义,在本例我自己定义的是cache,跟@headers里面对应就可以了
  18 + String cache = chain.request().header("cache");
  19 + okhttp3.Response originalResponse = chain.proceed(chain.request());
  20 + String cacheControl = originalResponse.header("Cache-Control");
  21 + //如果cacheControl为空,就让他TIMEOUT_CONNECT秒的缓存,本例是5秒,方便观察。注意这里的cacheControl是服务器返回的
  22 + if (cacheControl == null) {
  23 + //如果cache没值,缓存时间为TIMEOUT_CONNECT,有的话就为cache的值
  24 + if (cache == null || "".equals(cache)) {
  25 + cache = TIMEOUT_CONNECT + "";
  26 + }
  27 + originalResponse = originalResponse.newBuilder()
  28 + .header("Cache-Control", "public, max-age=" + cache)
  29 + .build();
  30 + return originalResponse;
  31 + } else {
  32 + return originalResponse;
  33 + }
  34 + }
  35 +}
0 \ No newline at end of file 36 \ No newline at end of file
core/network/src/main/java/com/cnlive/core/network/interceptor/SignEncrypt2Interceptor.java 0 → 100644
  1 +package com.cnlive.core.network.interceptor;
  2 +
  3 +
  4 +import com.cnlive.core.network.util.SignUtil;
  5 +
  6 +import java.io.IOException;
  7 +import java.net.URLEncoder;
  8 +import java.util.HashMap;
  9 +import java.util.Map;
  10 +
  11 +import okhttp3.FormBody;
  12 +import okhttp3.HttpUrl;
  13 +import okhttp3.Interceptor;
  14 +import okhttp3.MultipartBody;
  15 +import okhttp3.Request;
  16 +import okhttp3.RequestBody;
  17 +import okhttp3.Response;
  18 +
  19 +public class SignEncrypt2Interceptor implements Interceptor {
  20 +
  21 + private boolean valueUrlencode = false;
  22 +
  23 + public SignEncrypt2Interceptor() {
  24 +
  25 + }
  26 +
  27 + public SignEncrypt2Interceptor(boolean valueUrlencode) {
  28 + this.valueUrlencode = valueUrlencode;
  29 + }
  30 +
  31 + @Override
  32 + public Response intercept(Chain chain) throws IOException {
  33 + Request request = chain.request();
  34 +
  35 + if (request.body() instanceof FormBody) {
  36 + //处理方式 1
  37 + Map<String, String> parameter = new HashMap<>();
  38 +
  39 + FormBody body = ((FormBody) request.body());
  40 + FormBody.Builder builder = new FormBody.Builder();
  41 +
  42 + for (int i = 0; i < body.size(); i++) {
  43 + parameter.put(body.name(i), body.value(i));
  44 + }
  45 +
  46 + for (Map.Entry<String, String> entity : SignUtil.getOpenSignMap(parameter, valueUrlencode).entrySet()) {
  47 + builder.add(entity.getKey(), URLEncoder.encode(entity.getValue(), "UTF-8"));
  48 + }
  49 + RequestBody newBody = builder.build();
  50 +
  51 + Request newRequest = request.newBuilder()
  52 + .method(request.method(), newBody)
  53 + .url(request.url())
  54 + .build();
  55 + return chain.proceed(newRequest);
  56 + } else if (request.body() instanceof MultipartBody) {
  57 + //处理方式 2 (暂时不签名)
  58 + } else {
  59 + if ("POST".equals(request.method())) {
  60 + HttpUrl.Builder authorizedUrlBuilder = request.url().newBuilder();
  61 +
  62 + Map<String, String> parameter = new HashMap<>();
  63 +
  64 + for (String key : request.url().queryParameterNames()) {
  65 + parameter.put(key, request.url().queryParameter(key));
  66 + authorizedUrlBuilder.removeAllQueryParameters(key);
  67 + }
  68 +
  69 + FormBody.Builder builder = new FormBody.Builder();
  70 +
  71 + for (Map.Entry<String, String> entity : SignUtil.getOpenSignMap(parameter, valueUrlencode).entrySet()) {
  72 + builder.add(entity.getKey(), URLEncoder.encode(entity.getValue(), "UTF-8"));
  73 + }
  74 + RequestBody newBody = builder.build();
  75 +
  76 + Request newRequest = request.newBuilder()
  77 + .method(request.method(), newBody)
  78 + .url(authorizedUrlBuilder.build())
  79 + .build();
  80 + return chain.proceed(newRequest);
  81 + } else {
  82 + HttpUrl.Builder authorizedUrlBuilder = request.url().newBuilder();
  83 +
  84 + Map<String, String> parameter = new HashMap<>();
  85 +
  86 + for (String key : request.url().queryParameterNames()) {
  87 + parameter.put(key, request.url().queryParameter(key));
  88 + authorizedUrlBuilder.removeAllQueryParameters(key);
  89 + }
  90 +
  91 + for (Map.Entry<String, String> entity : SignUtil.getOpenSignMap(parameter, valueUrlencode).entrySet()) {
  92 + authorizedUrlBuilder.addQueryParameter(entity.getKey(), URLEncoder.encode(entity.getValue(), "UTF-8"));
  93 + }
  94 +
  95 + authorizedUrlBuilder.scheme(request.url().scheme());
  96 + authorizedUrlBuilder.host(request.url().host());
  97 +
  98 + Request newRequest = request.newBuilder()
  99 + .method(request.method(), request.body())
  100 + .url(authorizedUrlBuilder.build())
  101 + .build();
  102 + return chain.proceed(newRequest);
  103 + }
  104 + }
  105 +
  106 + return chain.proceed(request);
  107 + }
  108 +
  109 +
  110 +}
0 \ No newline at end of file 111 \ No newline at end of file
core/network/src/main/java/com/cnlive/core/network/interceptor/SignEncryptInterceptor.java 0 → 100644
  1 +package com.cnlive.core.network.interceptor;
  2 +
  3 +
  4 +
  5 +import com.cnlive.core.network.util.SignUtil;
  6 +
  7 +import java.io.IOException;
  8 +import java.util.HashMap;
  9 +import java.util.Map;
  10 +
  11 +import okhttp3.FormBody;
  12 +import okhttp3.HttpUrl;
  13 +import okhttp3.Interceptor;
  14 +import okhttp3.MultipartBody;
  15 +import okhttp3.Request;
  16 +import okhttp3.RequestBody;
  17 +import okhttp3.Response;
  18 +
  19 +public class SignEncryptInterceptor implements Interceptor {
  20 +
  21 + private boolean valueUrlencode = false;
  22 +
  23 + public SignEncryptInterceptor() {
  24 +
  25 + }
  26 +
  27 + public SignEncryptInterceptor(boolean valueUrlencode) {
  28 + this.valueUrlencode = valueUrlencode;
  29 + }
  30 +
  31 + @Override
  32 + public Response intercept(Chain chain) throws IOException {
  33 + Request request = chain.request();
  34 +
  35 + if (request.body() instanceof FormBody) {
  36 + //处理方式 1
  37 + Map<String, String> parameter = new HashMap<>();
  38 +
  39 + FormBody body = ((FormBody) request.body());
  40 + FormBody.Builder builder = new FormBody.Builder();
  41 +
  42 + for (int i = 0; i < body.size(); i++) {
  43 + parameter.put(body.name(i), body.value(i));
  44 + }
  45 +
  46 + for (Map.Entry<String, String> entity : SignUtil.getOpenSignMap(parameter, valueUrlencode).entrySet()) {
  47 + builder.add(entity.getKey(), entity.getValue());
  48 + }
  49 + RequestBody newBody = builder.build();
  50 +
  51 + Request newRequest = request.newBuilder()
  52 + .method(request.method(), newBody)
  53 + .url(request.url())
  54 + .build();
  55 + return chain.proceed(newRequest);
  56 + } else if (request.body() instanceof MultipartBody) {
  57 + //处理方式 2 (暂时不签名)
  58 + } else {
  59 + if ("POST".equals(request.method())) {
  60 + HttpUrl.Builder authorizedUrlBuilder = request.url().newBuilder();
  61 +
  62 + Map<String, String> parameter = new HashMap<>();
  63 +
  64 + for (String key : request.url().queryParameterNames()) {
  65 + parameter.put(key, request.url().queryParameter(key));
  66 + authorizedUrlBuilder.removeAllQueryParameters(key);
  67 + }
  68 +
  69 + FormBody.Builder builder = new FormBody.Builder();
  70 +
  71 + for (Map.Entry<String, String> entity : SignUtil.getOpenSignMap(parameter, valueUrlencode).entrySet()) {
  72 + builder.add(entity.getKey(), entity.getValue());
  73 + }
  74 + RequestBody newBody = builder.build();
  75 +
  76 + Request newRequest = request.newBuilder()
  77 + .method(request.method(), newBody)
  78 + .url(authorizedUrlBuilder.build())
  79 + .build();
  80 + return chain.proceed(newRequest);
  81 + } else {
  82 + HttpUrl.Builder authorizedUrlBuilder = request.url().newBuilder();
  83 +
  84 + Map<String, String> parameter = new HashMap<>();
  85 +
  86 + for (String key : request.url().queryParameterNames()) {
  87 + parameter.put(key, request.url().queryParameter(key));
  88 + authorizedUrlBuilder.removeAllQueryParameters(key);
  89 + }
  90 +
  91 + for (Map.Entry<String, String> entity : SignUtil.getOpenSignMap(parameter, valueUrlencode).entrySet()) {
  92 + authorizedUrlBuilder.addQueryParameter(entity.getKey(), entity.getValue());
  93 + }
  94 +
  95 + authorizedUrlBuilder.scheme(request.url().scheme());
  96 + authorizedUrlBuilder.host(request.url().host());
  97 +
  98 + Request newRequest = request.newBuilder()
  99 + .method(request.method(), request.body())
  100 + .url(authorizedUrlBuilder.build())
  101 + .build();
  102 + return chain.proceed(newRequest);
  103 + }
  104 + }
  105 +
  106 + return chain.proceed(request);
  107 + }
  108 +
  109 +
  110 +}
0 \ No newline at end of file 111 \ No newline at end of file
core/network/src/main/java/com/cnlive/core/network/request/BaseObserver.java 0 → 100644
  1 +package com.cnlive.core.network.request;
  2 +
  3 +import android.accounts.NetworkErrorException;
  4 +import android.content.Context;
  5 +
  6 +import com.cnlive.core.libs.base.network.BaseResult;
  7 +
  8 +import java.net.ConnectException;
  9 +import java.net.UnknownHostException;
  10 +import java.util.concurrent.TimeoutException;
  11 +
  12 +import io.reactivex.Observer;
  13 +import io.reactivex.disposables.Disposable;
  14 +
  15 +/**
  16 + * Observer基类
  17 + *
  18 + * @param <T>
  19 + */
  20 +public abstract class BaseObserver<T> implements Observer<BaseResult<T>> {
  21 + protected Context context;
  22 +
  23 + public BaseObserver() {
  24 + }
  25 +
  26 + public BaseObserver(Context context) {
  27 + this.context = context;
  28 + }
  29 +
  30 + @Override
  31 + public void onSubscribe(Disposable d) {
  32 + onRequestStart();
  33 + }
  34 +
  35 + @Override
  36 + public void onNext(BaseResult<T> tBaseResult) {
  37 + //请求结束
  38 + onRequestEnd();
  39 + //判断是否请求成功
  40 + if (tBaseResult.isSuccess()) {
  41 + try {
  42 + onSuccess(tBaseResult);
  43 + } catch (Exception e) {
  44 + e.printStackTrace();
  45 + }
  46 + } else {
  47 + //状态码不对
  48 + try {
  49 + onCodeError(tBaseResult.getErrorCode(), tBaseResult.getErrorMessage());
  50 + } catch (Exception e) {
  51 + e.printStackTrace();
  52 + }
  53 + }
  54 + }
  55 +
  56 + @Override
  57 + public void onError(Throwable e) {
  58 + //请求结束
  59 + onRequestEnd();
  60 + try {
  61 + //判断是否是网络请求相关错误
  62 + if (e instanceof ConnectException
  63 + || e instanceof TimeoutException
  64 + || e instanceof NetworkErrorException
  65 + || e instanceof UnknownHostException) {
  66 + onFailure(e, true);
  67 + } else {
  68 + onFailure(e, false);
  69 + }
  70 + } catch (Exception e1) {
  71 + e1.printStackTrace();
  72 + try {
  73 + onFailure(e1, false);
  74 + } catch (Exception ex) {
  75 + ex.printStackTrace();
  76 + }
  77 + }
  78 +
  79 + }
  80 +
  81 + @Override
  82 + public void onComplete() {
  83 +
  84 + }
  85 +
  86 + protected void onRequestStart() {
  87 + }
  88 +
  89 + protected void onRequestEnd() {
  90 + }
  91 +
  92 + /**
  93 + * 返回成功
  94 + *
  95 + * @throws Exception
  96 + */
  97 + protected abstract void onSuccess(BaseResult<T> result) throws Exception;
  98 +
  99 + /**
  100 + * 返回成功了,但是code错误
  101 + *
  102 + * @throws Exception
  103 + */
  104 + protected abstract void onCodeError(String errorCode, String msg) throws Exception;
  105 +
  106 + /**
  107 + * 返回失败
  108 + *
  109 + * @param e
  110 + * @param isNetWorkError 是否是网络错误
  111 + * @throws Exception
  112 + */
  113 + protected abstract void onFailure(Throwable e, boolean isNetWorkError) throws Exception;
  114 +
  115 +}
core/network/src/main/java/com/cnlive/core/network/request/BaseRequest.java 0 → 100644
  1 +package com.cnlive.core.network.request;
  2 +
  3 +
  4 +
  5 +import java.util.ArrayList;
  6 +import java.util.List;
  7 +
  8 +import okhttp3.Interceptor;
  9 +import retrofit2.Retrofit;
  10 +
  11 +public class BaseRequest {
  12 + private static String baseUrl = "http://gank.io/api/data/";
  13 + private static BaseRequest request;
  14 + private static Retrofit retrofit;
  15 + private static List<Interceptor> interceptorList;
  16 + private Class clzz;
  17 + private static final String DEFAULT_URL = "http://gank.io/api/data/";//默认请求地址
  18 + private static long connectTimeout;//连接超时
  19 + private static long readTimeout;//读取超时
  20 + private static long writeTimeout;//写入超时
  21 + private static final String SP_CMS_URL_DEBUT = "http://cmstest.cnlive.com:8768/";
  22 + private static final String SP_CMS_URL = "http://cms.cnlive.com:8768/";
  23 +
  24 + //网++ 接口域名
  25 + public static final String SP_BASE_URL = "https://apiwjj.cnlive.com/";
  26 + //网++ 测试环境 接口域名
  27 + public static final String SP_DEBUG_URL = "http://apiwjjtest.cnlive.com/";
  28 + //OPEN API 接口域名
  29 + private static final String SP_OPEN_URL = "https://api.cnlive.com/";
  30 +
  31 +
  32 + public BaseRequest setConnectTimeout(long connectTimeout) {
  33 + init();
  34 + this.connectTimeout = connectTimeout;
  35 + return request;
  36 + }
  37 +
  38 + public BaseRequest setReadTimeout(long readTimeout) {
  39 + init();
  40 + this.readTimeout = readTimeout;
  41 + return request;
  42 + }
  43 +
  44 + public BaseRequest setWriteTimeout(long writeTimeout) {
  45 + init();
  46 + this.writeTimeout = writeTimeout;
  47 + return request;
  48 + }
  49 +
  50 + public BaseRequest() {
  51 + interceptorList = new ArrayList<>();
  52 + initBaseUrl();
  53 + }
  54 +
  55 + /**
  56 + * 初始化接口地址
  57 + */
  58 + private static void initBaseUrl() {
  59 + baseUrl = SP_DEBUG_URL;//还原初始地址
  60 + }
  61 +
  62 + /**
  63 + * 设置连接地址
  64 + *
  65 + * @param url
  66 + * @return
  67 + */
  68 + public static BaseRequest setUrl(String url) {
  69 + init();
  70 + baseUrl = url;
  71 + return request;
  72 + }
  73 +
  74 + /**
  75 + * 添加拦截器
  76 + *
  77 + * @param interceptor
  78 + * @return
  79 + */
  80 + public static BaseRequest addInterceptor(Interceptor interceptor) {
  81 + init();
  82 + if (null != interceptor) {
  83 + interceptorList.add(interceptor);
  84 + }
  85 + return request;
  86 + }
  87 +
  88 + /**
  89 + * @return
  90 + */
  91 + private static synchronized BaseRequest init() {
  92 + if (null == request) {
  93 + request = new BaseRequest();
  94 + }
  95 + return request;
  96 + }
  97 +
  98 + public static <NetService> NetService service(Class<NetService> clz) {
  99 + init();
  100 + NetService service = null;
  101 + NetBuilder builder = new NetBuilder(clz);
  102 + if (connectTimeout > 0) {
  103 + builder.setConnectTimeout(connectTimeout);
  104 + }
  105 + if (readTimeout > 0) {
  106 + builder.setReadTimeout(readTimeout);
  107 + }
  108 + if (writeTimeout > 0) {
  109 + builder.setWriteTimeout(writeTimeout);
  110 + }
  111 + if (null!=interceptorList&&interceptorList.size()>0){
  112 + builder.addInterceptors(interceptorList);
  113 + }
  114 + builder.setBaseUrl(baseUrl);
  115 + service = (NetService) builder.getService();
  116 + initBaseUrl();
  117 + return service;
  118 +
  119 + }
  120 +
  121 +
  122 +}
0 \ No newline at end of file 123 \ No newline at end of file
core/network/src/main/java/com/cnlive/core/network/request/HttpConfig.java 0 → 100644
  1 +package com.cnlive.core.network.request;
  2 +
  3 +public class HttpConfig {
  4 + public static final int CONNECT_TIMEOUT = 20;//连接超时时间(秒)
  5 + public static final int READ_TIMEOUT = 20;//读取超时时间(秒)
  6 + public static final int WRITE_TIMEOUT = 20;//设置写入超时时间(秒)
  7 +
  8 +
  9 +}
core/network/src/main/java/com/cnlive/core/network/request/NetBuilder.java 0 → 100644
  1 +package com.cnlive.core.network.request;
  2 +
  3 +import com.cnlive.core.network.converter.GsonConverterFactory;
  4 +import com.cnlive.core.network.interceptor.SignEncryptInterceptor;
  5 +
  6 +import java.util.ArrayList;
  7 +import java.util.List;
  8 +import java.util.concurrent.TimeUnit;
  9 +
  10 +import okhttp3.Interceptor;
  11 +import okhttp3.OkHttpClient;
  12 +import retrofit2.Retrofit;
  13 +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
  14 +
  15 +public class NetBuilder<NetService> {
  16 + private Class<NetService> netServiceClass;//网络接口类
  17 + private long connectTimeout = HttpConfig.CONNECT_TIMEOUT;//连接超时
  18 + private long readTimeout = HttpConfig.READ_TIMEOUT;//读取超时
  19 + private long writeTimeout = HttpConfig.WRITE_TIMEOUT;//写入超时
  20 + private List<Interceptor> interceptorList;//拦截器
  21 + private String baseUrl;
  22 + private NetBuilder instance;
  23 +
  24 + public NetBuilder(Class<NetService> clz) {
  25 + this.netServiceClass = clz;
  26 + interceptorList = new ArrayList<>();
  27 + }
  28 +
  29 + public NetBuilder setBaseUrl(String baseUrl) {
  30 + this.baseUrl = baseUrl;
  31 + return this;
  32 + }
  33 +
  34 + public NetService getService() {
  35 + OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient().newBuilder();
  36 + okHttpClientBuilder.connectTimeout(connectTimeout, TimeUnit.SECONDS);
  37 + okHttpClientBuilder.readTimeout(readTimeout, TimeUnit.SECONDS);
  38 + okHttpClientBuilder.writeTimeout(writeTimeout, TimeUnit.SECONDS);
  39 + if (null != interceptorList && interceptorList.size() > 0) {
  40 + for (Interceptor interceptor : interceptorList) {
  41 + if (null != interceptor) {
  42 + okHttpClientBuilder.addInterceptor(interceptor);
  43 + }
  44 + }
  45 + }
  46 + //判断是否是网家家的接口
  47 + if (baseUrl.indexOf("cnlive.com") != -1) {
  48 + boolean isAdd = false;
  49 + //判断是否添加签名校验
  50 + for (Interceptor interceptor : interceptorList) {
  51 + if (interceptor instanceof SignEncryptInterceptor) {
  52 + isAdd = true;
  53 + break;
  54 + }
  55 + }
  56 + if (!isAdd) {
  57 + okHttpClientBuilder.addInterceptor(new SignEncryptInterceptor());
  58 + }
  59 + }
  60 + return new Retrofit.Builder()
  61 + .baseUrl(baseUrl)
  62 + .client(okHttpClientBuilder.build())
  63 + .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
  64 + .addConverterFactory(GsonConverterFactory.create(true)) //添加Gson转换器
  65 + .build()
  66 + .create(netServiceClass);
  67 + }
  68 +
  69 + /**
  70 + * 设置拦截器
  71 + */
  72 + public NetBuilder addInterceptors(List<Interceptor> interceptors) {
  73 + this.interceptorList.addAll(interceptors);
  74 + return this;
  75 + }
  76 +
  77 + /**
  78 + * 设置连接超时
  79 + *
  80 + * @param time
  81 + * @return
  82 + */
  83 + public NetBuilder setConnectTimeout(long time) {
  84 + this.connectTimeout = time;
  85 + return this;
  86 + }
  87 +
  88 + /**
  89 + * 设置读取超时
  90 + *
  91 + * @param time
  92 + * @return
  93 + */
  94 + public NetBuilder setReadTimeout(long time) {
  95 + this.readTimeout = time;
  96 + return this;
  97 + }
  98 +
  99 + /**
  100 + * 设置写入超时
  101 + *
  102 + * @param time
  103 + * @return
  104 + */
  105 + public NetBuilder setWriteTimeout(long time) {
  106 + this.writeTimeout = time;
  107 + return this;
  108 + }
  109 +}
core/network/src/main/java/com/cnlive/core/network/util/DESUtil.java 0 → 100644
  1 +package com.cnlive.core.network.util;
  2 +
  3 +import android.util.Base64;
  4 +
  5 +import java.security.Key;
  6 +
  7 +import javax.crypto.Cipher;
  8 +import javax.crypto.SecretKeyFactory;
  9 +import javax.crypto.spec.DESKeySpec;
  10 +
  11 +import static javax.crypto.Cipher.getInstance;
  12 +
  13 +/**
  14 + * 加密工具
  15 + */
  16 +public class DESUtil {
  17 +
  18 + public static final String DES_KEY = "cnliveIm";
  19 + private static String encoding = "UTF-8";
  20 +
  21 + /**
  22 + * 加密字符串
  23 + */
  24 + public static String ebotongEncrypto(String str, String key) {
  25 + String result = str;
  26 + if (str != null && str.length() > 0) {
  27 + try {
  28 + byte[] encodeByte = symmetricEncrypto(str.getBytes(encoding), key);
  29 + result = Base64.encodeToString(encodeByte, Base64.DEFAULT);
  30 +
  31 + } catch (Exception e) {
  32 + // e.printStackTrace();
  33 + }
  34 + }
  35 + return result;
  36 + }
  37 +
  38 + /**
  39 + * 解密字符串
  40 + */
  41 + public static String ebotongDecrypto(String str, String key) {
  42 + String result = str;
  43 + if (str != null && str.length() > 0) {
  44 + try {
  45 + byte[] encodeByte = Base64.decode(str, Base64.DEFAULT);
  46 +
  47 + byte[] decoder = symmetricDecrypto(encodeByte, key);
  48 + result = new String(decoder, encoding);
  49 + } catch (Exception e) {
  50 + // e.printStackTrace();
  51 + }
  52 + }
  53 + return result;
  54 + }
  55 +
  56 + /**
  57 + * 加密byte[]
  58 + */
  59 + public static byte[] ebotongEncrypto(byte[] str, String key) {
  60 + byte[] result = null;
  61 + if (str != null && str.length > 0) {
  62 + try {
  63 + byte[] encodeByte = symmetricEncrypto(str, key);
  64 + result = Base64.encode(encodeByte, Base64.DEFAULT);
  65 +
  66 + } catch (Exception e) {
  67 + // e.printStackTrace();
  68 + }
  69 + }
  70 + return result;
  71 + }
  72 +
  73 + /**
  74 + * 解密byte[]
  75 + */
  76 + public static byte[] ebotongDecrypto(byte[] str, String key) {
  77 + byte[] result = null;
  78 + if (str != null && str.length > 0) {
  79 + try {
  80 +
  81 + byte[] encodeByte = Base64.decode(new String(str, encoding), Base64.DEFAULT);
  82 + //byte[] encodeByte = base64decoder.decodeBuffer(new String(str));
  83 + byte[] decoder = symmetricDecrypto(encodeByte, key);
  84 + result = new String(decoder).getBytes(encoding);
  85 + result = new String(decoder).getBytes();
  86 + } catch (Exception e) {
  87 + // e.printStackTrace();
  88 + }
  89 + }
  90 + return result;
  91 + }
  92 +
  93 + /**
  94 + * 对称加密字节数组并返回
  95 + *
  96 + * @param byteSource 需要加密的数据
  97 + * @return 经过加密的数据
  98 + * @throws Exception
  99 + */
  100 + public static byte[] symmetricEncrypto(byte[] byteSource, String sKey) throws Exception {
  101 + try {
  102 + int mode = Cipher.ENCRYPT_MODE;
  103 + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
  104 + byte[] keyData = sKey.getBytes();
  105 + DESKeySpec keySpec = new DESKeySpec(keyData);
  106 + Key key = keyFactory.generateSecret(keySpec);
  107 + Cipher cipher = getInstance("DES");
  108 + cipher.init(mode, key);
  109 +
  110 + return cipher.doFinal(byteSource);
  111 + } catch (Exception e) {
  112 + return null;
  113 + }
  114 + }
  115 +
  116 + /**
  117 + * 对称解密字节数组并返回
  118 + *
  119 + * @param byteSource 需要解密的数据
  120 + * @return 经过解密的数据
  121 + * @throws Exception
  122 + */
  123 + public static byte[] symmetricDecrypto(byte[] byteSource, String sKey) throws Exception {
  124 + try {
  125 + int mode = Cipher.DECRYPT_MODE;
  126 + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
  127 + byte[] keyData = sKey.getBytes();
  128 + DESKeySpec keySpec = new DESKeySpec(keyData);
  129 + Key key = keyFactory.generateSecret(keySpec);
  130 + Cipher cipher = getInstance("DES");
  131 + cipher.init(mode, key);
  132 + return cipher.doFinal(byteSource);
  133 + } catch (Exception e) {
  134 + return null;
  135 + }
  136 + }
  137 +}
core/network/src/main/java/com/cnlive/core/network/util/NetworkUtil.java 0 → 100644
  1 +package com.cnlive.core.network.util;
  2 +
  3 +import android.content.Context;
  4 +import android.net.ConnectivityManager;
  5 +import android.net.NetworkInfo;
  6 +
  7 +public class NetworkUtil {
  8 +
  9 + public static boolean isConnectInternet(Context context) {
  10 + if (context == null) return false;
  11 + ConnectivityManager connectManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
  12 + if (connectManager != null) {
  13 + NetworkInfo networkinfo = connectManager.getActiveNetworkInfo();
  14 + return networkinfo != null && networkinfo.isAvailable();
  15 + }
  16 + return false;
  17 + }
  18 +
  19 +}
0 \ No newline at end of file 20 \ No newline at end of file
core/network/src/main/java/com/cnlive/core/network/util/SHA1Util.java 0 → 100644
  1 +package com.cnlive.core.network.util;
  2 +
  3 +import java.io.UnsupportedEncodingException;
  4 +import java.math.BigInteger;
  5 +import java.security.MessageDigest;
  6 +import java.security.NoSuchAlgorithmException;
  7 +
  8 +public class SHA1Util {
  9 + private final int[] abcde = {0x67452301, 0xefcdab89, 0x98badcfe,
  10 + 0x10325476, 0xc3d2e1f0};
  11 +
  12 + // 摘要数据存储数组
  13 + private int[] digestInt = new int[5];
  14 +
  15 + // 计算过程中的临时数据存储数组
  16 + private int[] tmpData = new int[80];
  17 +
  18 + /**
  19 + * 将字节转换为十六进制字符串
  20 + *
  21 + * @param ib
  22 + * @return
  23 + */
  24 + private static String byteToHexString(byte ib) {
  25 + char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
  26 + 'B', 'C', 'D', 'E', 'F'};
  27 + char[] ob = new char[2];
  28 + ob[0] = Digit[(ib >>> 4) & 0X0F];
  29 + ob[1] = Digit[ib & 0X0F];
  30 + String s = new String(ob);
  31 + return s;
  32 + }
  33 +
  34 + /**
  35 + * 将字节数组转换为十六进制字符串
  36 + *
  37 + * @param bytearray
  38 + * @return
  39 + */
  40 + private static String byteArrayToHexString(byte[] bytearray) {
  41 + String strDigest = "";
  42 + for (byte aBytearray : bytearray) {
  43 + strDigest += byteToHexString(aBytearray);
  44 + }
  45 + return strDigest;
  46 + }
  47 +
  48 + /**
  49 + * @param text
  50 + * @return
  51 + */
  52 + public static String SHA1Digest(String text) {
  53 + String pwd = "";
  54 + try {
  55 + MessageDigest md = MessageDigest.getInstance("SHA1");
  56 + md.update(text.getBytes());
  57 + pwd = new BigInteger(1, md.digest()).toString(16);
  58 + } catch (NoSuchAlgorithmException e) {
  59 + e.printStackTrace();
  60 + }
  61 + return pwd;
  62 + }
  63 +
  64 + /**
  65 + * 计算sha-1摘要
  66 + *
  67 + * @param bytedata
  68 + * @return
  69 + */
  70 + private int process_input_bytes(byte[] bytedata) {
  71 + // 初试化常量
  72 + System.arraycopy(abcde, 0, digestInt, 0, abcde.length);
  73 + // 格式化输入字节数组,补10及长度数据
  74 + byte[] newbyte = byteArrayFormatData(bytedata);
  75 + // 获取数据摘要计算的数据单元个数
  76 + int MCount = newbyte.length / 64;
  77 + // 循环对每个数据单元进行摘要计算
  78 + for (int pos = 0; pos < MCount; pos++) {
  79 + // 将每个单元的数据转换成16个整型数据,并保存到tmpData的前16个数组元素中
  80 + for (int j = 0; j < 16; j++) {
  81 + tmpData[j] = byteArrayToInt(newbyte, (pos * 64) + (j * 4));
  82 + }
  83 + // 摘要计算函数
  84 + encrypt();
  85 + }
  86 + return 20;
  87 + }
  88 +
  89 + /**
  90 + * 格式化输入字节数组格式
  91 + *
  92 + * @param bytedata
  93 + * @return
  94 + */
  95 + private byte[] byteArrayFormatData(byte[] bytedata) {
  96 + // 补0数量
  97 + int zeros = 0;
  98 + // 补位后总位数
  99 + int size = 0;
  100 + // 原始数据长度
  101 + int n = bytedata.length;
  102 + // 模64后的剩余位数
  103 + int m = n % 64;
  104 + // 计算添加0的个数以及添加10后的总长度
  105 + if (m < 56) {
  106 + zeros = 55 - m;
  107 + size = n - m + 64;
  108 + } else if (m == 56) {
  109 + zeros = 63;
  110 + size = n + 8 + 64;
  111 + } else {
  112 + zeros = 63 - m + 56;
  113 + size = (n + 64) - m + 64;
  114 + }
  115 + // 补位后生成的新数组内容
  116 + byte[] newbyte = new byte[size];
  117 + // 复制数组的前面部分
  118 + System.arraycopy(bytedata, 0, newbyte, 0, n);
  119 + // 获得数组Append数据元素的位置
  120 + int l = n;
  121 + // 补1操作
  122 + newbyte[l++] = (byte) 0x80;
  123 + // 补0操作
  124 + for (int i = 0; i < zeros; i++) {
  125 + newbyte[l++] = (byte) 0x00;
  126 + }
  127 + // 计算数据长度,补数据长度位共8字节,长整型
  128 + long N = (long) n * 8;
  129 + byte h8 = (byte) (N & 0xFF);
  130 + byte h7 = (byte) ((N >> 8) & 0xFF);
  131 + byte h6 = (byte) ((N >> 16) & 0xFF);
  132 + byte h5 = (byte) ((N >> 24) & 0xFF);
  133 + byte h4 = (byte) ((N >> 32) & 0xFF);
  134 + byte h3 = (byte) ((N >> 40) & 0xFF);
  135 + byte h2 = (byte) ((N >> 48) & 0xFF);
  136 + byte h1 = (byte) (N >> 56);
  137 + newbyte[l++] = h1;
  138 + newbyte[l++] = h2;
  139 + newbyte[l++] = h3;
  140 + newbyte[l++] = h4;
  141 + newbyte[l++] = h5;
  142 + newbyte[l++] = h6;
  143 + newbyte[l++] = h7;
  144 + newbyte[l++] = h8;
  145 + return newbyte;
  146 + }
  147 +
  148 + private int f1(int x, int y, int z) {
  149 + return (x & y) | (~x & z);
  150 + }
  151 +
  152 + private int f2(int x, int y, int z) {
  153 + return x ^ y ^ z;
  154 + }
  155 +
  156 + private int f3(int x, int y, int z) {
  157 + return (x & y) | (x & z) | (y & z);
  158 + }
  159 +
  160 + //
  161 +
  162 + private int f4(int x, int y) {
  163 + return (x << y) | x >>> (32 - y);
  164 + }
  165 +
  166 + /**
  167 + * 单元摘要计算函数
  168 + */
  169 + private void encrypt() {
  170 + for (int i = 16; i <= 79; i++) {
  171 + tmpData[i] = f4(tmpData[i - 3] ^ tmpData[i - 8] ^ tmpData[i - 14]
  172 + ^ tmpData[i - 16], 1);
  173 + }
  174 + int[] tmpabcde = new int[5];
  175 + System.arraycopy(digestInt, 0, tmpabcde, 0, tmpabcde.length);
  176 + for (int j = 0; j <= 19; j++) {
  177 + int tmp = f4(tmpabcde[0], 5)
  178 + + f1(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4]
  179 + + tmpData[j] + 0x5a827999;
  180 + tmpabcde[4] = tmpabcde[3];
  181 + tmpabcde[3] = tmpabcde[2];
  182 + tmpabcde[2] = f4(tmpabcde[1], 30);
  183 + tmpabcde[1] = tmpabcde[0];
  184 + tmpabcde[0] = tmp;
  185 + }
  186 + for (int k = 20; k <= 39; k++) {
  187 + int tmp = f4(tmpabcde[0], 5)
  188 + + f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4]
  189 + + tmpData[k] + 0x6ed9eba1;
  190 + tmpabcde[4] = tmpabcde[3];
  191 + tmpabcde[3] = tmpabcde[2];
  192 + tmpabcde[2] = f4(tmpabcde[1], 30);
  193 + tmpabcde[1] = tmpabcde[0];
  194 + tmpabcde[0] = tmp;
  195 + }
  196 + for (int l = 40; l <= 59; l++) {
  197 + int tmp = f4(tmpabcde[0], 5)
  198 + + f3(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4]
  199 + + tmpData[l] + 0x8f1bbcdc;
  200 + tmpabcde[4] = tmpabcde[3];
  201 + tmpabcde[3] = tmpabcde[2];
  202 + tmpabcde[2] = f4(tmpabcde[1], 30);
  203 + tmpabcde[1] = tmpabcde[0];
  204 + tmpabcde[0] = tmp;
  205 + }
  206 + for (int m = 60; m <= 79; m++) {
  207 + int tmp = f4(tmpabcde[0], 5)
  208 + + f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4]
  209 + + tmpData[m] + 0xca62c1d6;
  210 + tmpabcde[4] = tmpabcde[3];
  211 + tmpabcde[3] = tmpabcde[2];
  212 + tmpabcde[2] = f4(tmpabcde[1], 30);
  213 + tmpabcde[1] = tmpabcde[0];
  214 + tmpabcde[0] = tmp;
  215 + }
  216 + for (int i2 = 0; i2 < tmpabcde.length; i2++) {
  217 + digestInt[i2] = digestInt[i2] + tmpabcde[i2];
  218 + }
  219 + for (int n = 0; n < tmpData.length; n++) {
  220 + tmpData[n] = 0;
  221 + }
  222 + }
  223 +
  224 + /**
  225 + * 4字节数组转换为整数
  226 + *
  227 + * @param bytedata
  228 + * @param i
  229 + * @return
  230 + */
  231 + private int byteArrayToInt(byte[] bytedata, int i) {
  232 + return ((bytedata[i] & 0xff) << 24) | ((bytedata[i + 1] & 0xff) << 16)
  233 + | ((bytedata[i + 2] & 0xff) << 8) | (bytedata[i + 3] & 0xff);
  234 + }
  235 +
  236 + /**
  237 + * 整数转换为4字节数组
  238 + *
  239 + * @param intValue
  240 + * @param byteData
  241 + * @param i
  242 + */
  243 + private void intToByteArray(int intValue, byte[] byteData, int i) {
  244 + byteData[i] = (byte) (intValue >>> 24);
  245 + byteData[i + 1] = (byte) (intValue >>> 16);
  246 + byteData[i + 2] = (byte) (intValue >>> 8);
  247 + byteData[i + 3] = (byte) intValue;
  248 + }
  249 +
  250 + /**
  251 + * 计算sha-1摘要,返回相应的字节数组
  252 + *
  253 + * @param byteData
  254 + * @return
  255 + */
  256 + public byte[] getDigestOfBytes(byte[] byteData) {
  257 + process_input_bytes(byteData);
  258 + byte[] digest = new byte[20];
  259 + for (int i = 0; i < digestInt.length; i++) {
  260 + intToByteArray(digestInt[i], digest, i * 4);
  261 + }
  262 + return digest;
  263 + }
  264 +
  265 + /**
  266 + * 计算sha-1摘要,返回相应的十六进制字符串
  267 + *
  268 + * @param byteData
  269 + * @return
  270 + */
  271 + public String getDigestOfString(byte[] byteData) {
  272 + return byteArrayToHexString(getDigestOfBytes(byteData));
  273 + }
  274 +
  275 + /**
  276 + * @param data
  277 + * @return
  278 + */
  279 + public String Digest(String data) {
  280 + return this.getDigestOfString(data.getBytes());
  281 + }
  282 +
  283 + /**
  284 + * @param data
  285 + * @return
  286 + */
  287 + public String Digest(String data, String encode) {
  288 + try {
  289 + return this.getDigestOfString(data.getBytes(encode));
  290 + } catch (UnsupportedEncodingException e) {
  291 + return this.Digest(data);
  292 + }
  293 + }
  294 +}
core/network/src/main/java/com/cnlive/core/network/util/SignUtil.java 0 → 100644
  1 +package com.cnlive.core.network.util;
  2 +
  3 +import android.os.Build;
  4 +import android.text.TextUtils;
  5 +
  6 +import com.cnlive.core.libs.base.application.AppConfig;
  7 +import com.cnlive.core.libs.base.util.StringUtils;
  8 +import com.cnlive.libs.encipher.CNLiveEncipher;
  9 +
  10 +import java.util.ArrayList;
  11 +import java.util.Collections;
  12 +import java.util.Date;
  13 +import java.util.HashMap;
  14 +import java.util.LinkedHashMap;
  15 +import java.util.List;
  16 +import java.util.Locale;
  17 +import java.util.Map;
  18 +
  19 +import io.reactivex.Observable;
  20 +import io.reactivex.ObservableEmitter;
  21 +import io.reactivex.ObservableOnSubscribe;
  22 +import io.reactivex.android.schedulers.AndroidSchedulers;
  23 +import io.reactivex.schedulers.Schedulers;
  24 +import okhttp3.Headers;
  25 +import okhttp3.MediaType;
  26 +import okhttp3.OkHttpClient;
  27 +import okhttp3.Request;
  28 +import okhttp3.RequestBody;
  29 +import okhttp3.Response;
  30 +
  31 +public class SignUtil {
  32 + //服务器地址-获取时间
  33 + public static final String URL_TIME_SERVICE = "https://api.cnlive.com/open/api2/timestamp";
  34 + //服务器=时间戳缓存
  35 + public static long service_time = 0;
  36 + private static final long cache_time = 4 * 60_000;
  37 +
  38 + private static final String TAG = "SignUtil";
  39 +
  40 + /**
  41 + * 接口签名方法,返回rxJava观察者 (特殊接口单独调用)
  42 + *
  43 + * @param params 接口参数Map数组
  44 + * @return rxJava Observable<Map<String, String>>
  45 + */
  46 + public static Observable<Map<String, String>> getSignMapObservable(final Map<String, String> params) {
  47 + return Observable.create((ObservableOnSubscribe<Map<String, String>>) oe -> {
  48 + oe.onNext(getOpenSignMap(params));
  49 + oe.onComplete();
  50 + }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
  51 + }
  52 +
  53 + /**
  54 + * 接口签名方法,返回rxJava观察者 (特殊接口单独调用)
  55 + *
  56 + * @param params 接口参数Map数组
  57 + * @return rxJava Observable<Map<String, String>>
  58 + */
  59 + public static Observable<Map<String, RequestBody>> getRequestBodySignMapObservable(Map<String, String> params) {
  60 + return getRequestBodySignMapObservable(params, false);
  61 + }
  62 +
  63 + public static Observable<Map<String, RequestBody>> getRequestBodySignMapObservable(Map<String, String> params, boolean valueUrlencode) {
  64 + return Observable.create((ObservableEmitter<Map<String, RequestBody>> oe) -> {
  65 + oe.onNext(orderRequestBody(getOpenSignMap(params, valueUrlencode)));
  66 + oe.onComplete();
  67 + }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
  68 + }
  69 +
  70 + public static Map<String, RequestBody> orderRequestBody(Map<String, String> map) {
  71 + HashMap<String, RequestBody> tempMap = new LinkedHashMap<>();
  72 + List<Map.Entry<String, String>> infoIds = new ArrayList<>(map.entrySet());
  73 +
  74 + Collections.sort(infoIds, (o1, o2) -> o1.getKey().compareTo(o2.getKey()));
  75 +
  76 + for (int i = 0; i < infoIds.size(); i++) {
  77 + Map.Entry<String, String> item = infoIds.get(i);
  78 + if (item != null && item.getValue() != null)
  79 + tempMap.put(item.getKey(), RequestBody.create(MediaType.parse("text/plain"), item.getValue()));
  80 + }
  81 + return tempMap;
  82 + }
  83 +
  84 + public static Map<String, String> getOpenSignMap(Map<String, String> params) {
  85 + return getOpenSignMap(params, false, false);
  86 + }
  87 +
  88 + public static Map<String, String> getOpenSignMap(Map<String, String> params, boolean valueUrlencode) {
  89 + return getOpenSignMap(params, valueUrlencode, false);
  90 + }
  91 +
  92 + public static Map<String, String> getOpenSignMap(Map<String, String> params, boolean valueUrlencode, boolean replace) {
  93 + if (params == null) return new HashMap<>();
  94 +
  95 + if (replace || !params.containsKey("platform_id")) {
  96 + params.put("platform_id", AppConfig.getAppPackeg());
  97 + }
  98 + if (AppConfig.isDebug() && (replace || !params.containsKey("test"))) {
  99 + params.put("test", "0");
  100 + }
  101 + if (replace || !params.containsKey("appId")) {
  102 + params.put("appId", AppConfig.getAppId());
  103 + }
  104 + if (replace || !params.containsKey("plat")) {
  105 + params.put("plat", "a");
  106 + }
  107 + if (replace || !params.containsKey("app_channel_id")) {
  108 + params.put("app_channel_id", AppConfig.getAppChannel());
  109 + }
  110 + if (replace || !params.containsKey("timestamp")) {
  111 + long time = getTime();
  112 + params.put("timestamp", String.valueOf(time / 1000));
  113 + }
  114 + if (replace || !params.containsKey("ver")) {
  115 + params.put("ver", AppConfig.getAppVersion());
  116 + }
  117 + if (replace || !params.containsKey("uuid")) {
  118 + params.put("uuid", AppConfig.getAppUUID());
  119 + }
  120 + if (replace || !params.containsKey("loginSid")) {
  121 + params.put("loginSid", AppConfig.getSid());
  122 + }
  123 +
  124 + //拼接推广渠道
  125 + if (replace || !params.containsKey("promoFrom")) {
  126 + if (!TextUtils.isEmpty(AppConfig.getPromoFrom())) {
  127 + params.put("promoFrom", AppConfig.getPromoFrom());
  128 + }
  129 + }
  130 +
  131 + Map<String, String> map = order(params, valueUrlencode);
  132 +
  133 + if (map.containsKey("sign")) {
  134 + map.remove("sign");
  135 + }
  136 +
  137 + String signValue = SHA1Util
  138 + .SHA1Digest(mapJoin(map, valueUrlencode).concat("&key=").concat(AppConfig.getAppKey()))
  139 + .toUpperCase(Locale.getDefault());
  140 + map.put("sign", signValue);
  141 + return map;
  142 + }
  143 +
  144 +
  145 + public static String getOpenSignString(Map<String, String> params) {
  146 + return getOpenSignString(params, false, false);
  147 + }
  148 +
  149 + public static String getOpenSignString(Map<String, String> params, boolean valueUrlencode) {
  150 + return getOpenSignString(params, valueUrlencode, false);
  151 + }
  152 +
  153 + public static String getOpenSignString(Map<String, String> params, boolean valueUrlencode, boolean replace) {
  154 + if (params == null) return "";
  155 +
  156 + if (replace || !params.containsKey("platform_id")) {
  157 + params.put("platform_id", AppConfig.getAppPackeg());
  158 + }
  159 + if (AppConfig.isDebug() && (replace || !params.containsKey("test"))) {
  160 + params.put("test", "0");
  161 + }
  162 + if (replace || !params.containsKey("appId")) {
  163 + params.put("appId", AppConfig.getAppId());
  164 + }
  165 + if (replace || !params.containsKey("plat")) {
  166 + params.put("plat", "a");
  167 + }
  168 + if (replace || !params.containsKey("app_channel_id")) {
  169 + params.put("app_channel_id", AppConfig.getAppChannel());
  170 + }
  171 + if (replace || !params.containsKey("timestamp")) {
  172 + long time = getTime();
  173 + params.put("timestamp", String.valueOf(time / 1000));
  174 + }
  175 + if (replace || !params.containsKey("ver")) {
  176 + params.put("ver", AppConfig.getAppVersion());
  177 + }
  178 + if (replace || !params.containsKey("uuid")) {
  179 + params.put("uuid", AppConfig.getAppUUID());
  180 + }
  181 + if (replace || !params.containsKey("androidVersion")) {
  182 + params.put("androidVersion", Build.VERSION.SDK_INT + "");
  183 + }
  184 +
  185 + //拼接推广渠道
  186 + if (replace || !params.containsKey("promoFrom")) {
  187 + if (!TextUtils.isEmpty(AppConfig.getPromoFrom())) {
  188 + params.put("promoFrom", AppConfig.getPromoFrom());
  189 + }
  190 + }
  191 +
  192 + String signParam = mapParam(params);
  193 +
  194 + Map<String, String> map = order(params, valueUrlencode);
  195 +
  196 + if (map.containsKey("sign")) {
  197 + map.remove("sign");
  198 + }
  199 +
  200 + String signValue = SHA1Util
  201 + .SHA1Digest(mapJoin(map, valueUrlencode).concat("&key=").concat(AppConfig.getAppKey()))
  202 + .toUpperCase(Locale.getDefault());
  203 +
  204 + return signParam.concat("&sign=").concat(signValue);
  205 + }
  206 +
  207 + public static Map<String, String> getNetPPSignString(Map<String, String> params) {
  208 +
  209 + if (params == null) return null;
  210 +
  211 + if (!params.containsKey("platFormId")) {
  212 + params.put("platFormId", AppConfig.getAppPackeg());
  213 + }
  214 + if (!params.containsKey("timestamp")) {
  215 + params.put("timestamp", String.valueOf(getTime() / 1000));
  216 + }
  217 +
  218 + String mapJoin = mapJoin(order(params, false), false);
  219 +
  220 + Map<String, String> map = new HashMap<>();
  221 + map.put("appId", AppConfig.getAppId());
  222 + map.put("sign", CNLiveEncipher.encryptSHA1(AppConfig.getAppId(), mapJoin).replaceAll("[\r\n]", ""));
  223 + map.put("p1", CNLiveEncipher.encryptAES(AppConfig.getAppId(), mapJoin).replaceAll("[\r\n]", ""));
  224 +
  225 + return map;
  226 + }
  227 +
  228 + public static Map<String, String> getNetPPPaySignString(Map<String, String> params) {
  229 +
  230 + if (params == null) return null;
  231 +
  232 + if (!params.containsKey("platFormId")) {
  233 + params.put("platFormId", AppConfig.getAppPackeg());
  234 + }
  235 + if (!params.containsKey("timestamp")) {
  236 + params.put("timestamp", String.valueOf(getTime() / 1000));
  237 + }
  238 +
  239 + String publicKey = "";
  240 + String randomAesKey = "";
  241 +
  242 + if (params.containsKey("publicKey")) {
  243 + publicKey = CNLiveEncipher.decryptAES(AppConfig.getAppId(), params.get("publicKey"));
  244 + params.remove("publicKey");
  245 + }
  246 + if (params.containsKey("randomAesKey")) {
  247 + randomAesKey = CNLiveEncipher.decryptAES(AppConfig.getAppId(), params.get("randomAesKey"));
  248 + params.remove("randomAesKey");
  249 + }
  250 +
  251 + String mapJoin = mapJoin(order(params, false), false);
  252 +
  253 + Map<String, String> map = new HashMap<>();
  254 + map.put("appId", AppConfig.getAppId());
  255 + map.put("sign", CNLiveEncipher.encryptSHA1(AppConfig.getAppId(), mapJoin).replaceAll("[\r\n]", ""));
  256 + map.put("p1", CNLiveEncipher.encryptAES(randomAesKey, mapJoin).replaceAll("[\r\n]", ""));
  257 + map.put("p2", CNLiveEncipher.encryptRSA(publicKey, "aesKey=" + randomAesKey).replaceAll("[\r\n]", ""));
  258 +
  259 + return map;
  260 + }
  261 +
  262 + private static String mapParam(Map<String, String> map) {
  263 + StringBuilder stringBuilder = new StringBuilder();
  264 + for (String key : map.keySet()) {
  265 + stringBuilder.append(key).append("=").append(map.get(key)).append("&");
  266 + }
  267 + if (stringBuilder.length() > 0) {
  268 + stringBuilder.deleteCharAt(stringBuilder.length() - 1);
  269 + }
  270 + return stringBuilder.toString();
  271 + }
  272 +
  273 + public static long getTime() {
  274 + long local_time = System.currentTimeMillis();
  275 +
  276 + if (Math.abs(service_time - local_time) < cache_time) return local_time;
  277 +
  278 + OkHttpClient okHttpClient = new OkHttpClient();
  279 + try {
  280 + Request request = new Request.Builder().url(URL_TIME_SERVICE).build();
  281 +
  282 + Response response = okHttpClient.newCall(request).execute();
  283 +
  284 + Headers headers = response.headers();
  285 +
  286 + Date date = headers.getDate("Date");
  287 + return date == null ? local_time : (service_time = date.getTime());
  288 + } catch (Exception ignored) {
  289 + }
  290 + return local_time;
  291 + }
  292 +
  293 + private static Map<String, String> order(Map<String, String> map, boolean valueUrlencode) {
  294 + HashMap<String, String> tempMap = new LinkedHashMap<>();
  295 + List<Map.Entry<String, String>> infoIds = new ArrayList<>(map.entrySet());
  296 +
  297 + Collections.sort(infoIds, (o1, o2) -> o1.getKey().compareTo(o2.getKey()));
  298 +
  299 + for (int i = 0; i < infoIds.size(); i++) {
  300 + Map.Entry<String, String> item = infoIds.get(i);
  301 + tempMap.put(item.getKey(), valueUrlencode ? StringUtils.encode(item.getValue()) : item.getValue());
  302 + }
  303 + return tempMap;
  304 + }
  305 +
  306 + public static String mapJoin(Map<String, String> map, boolean valueUrlencode) {
  307 + StringBuilder stringBuilder = new StringBuilder();
  308 + for (String key : map.keySet()) {
  309 + if (map.get(key) != null && !"".equals(map.get(key))) {
  310 + stringBuilder.append(key)
  311 + .append("=")
  312 + .append(valueUrlencode ? map.get(key).replace("+", "%20") : map.get(key))
  313 + .append("&");
  314 + }
  315 + }
  316 + if (stringBuilder.length() > 0) {
  317 + stringBuilder.deleteCharAt(stringBuilder.length() - 1);
  318 + }
  319 + return stringBuilder.toString();
  320 + }
  321 +}
core/network/src/main/java/com/cnlive/core/network/util/TransformUtil.java 0 → 100644
  1 +package com.cnlive.core.network.util;
  2 +
  3 +import com.google.gson.Gson;
  4 +
  5 +public class TransformUtil {
  6 +
  7 + public static <T> T transform(Class<T> clazz, Object object) {
  8 + Gson gson = new Gson();
  9 + String json = gson.toJson(object);
  10 + return gson.fromJson(json, clazz);
  11 + }
  12 +}
core/network/src/main/java/com/cnlive/core/network/util/UriUtil.java 0 → 100644
  1 +package com.cnlive.core.network.util;
  2 +
  3 +import android.net.Uri;
  4 +import android.text.TextUtils;
  5 +
  6 +import java.util.HashMap;
  7 +import java.util.Map;
  8 +
  9 +import io.reactivex.Observable;
  10 +import io.reactivex.ObservableOnSubscribe;
  11 +import io.reactivex.android.schedulers.AndroidSchedulers;
  12 +import io.reactivex.disposables.Disposable;
  13 +import io.reactivex.schedulers.Schedulers;
  14 +
  15 +/**
  16 + * Created by Granzon on 2018/9/15.
  17 + */
  18 +
  19 +public class UriUtil {
  20 + private final String link;
  21 + private final Uri uri;
  22 + private Map<String, String> map;
  23 +
  24 + public UriUtil(String link) {
  25 + this.link = link == null ? "" : link;
  26 + this.uri = Uri.parse(link);
  27 + this.map = initParameter();
  28 + }
  29 +
  30 + public boolean isValid() {
  31 + if (TextUtils.isEmpty(link)) return false;
  32 + if (uri.isOpaque()) return false;
  33 + return true;
  34 + }
  35 +
  36 + private Map<String, String> initParameter() {
  37 + Map<String, String> map = new HashMap<>();
  38 + if (isValid()) for (String name : uri.getQueryParameterNames())
  39 + map.put(name, uri.getQueryParameter(name));
  40 + return map;
  41 + }
  42 +
  43 + public void addQueryParameter(String key, String value) {
  44 + if (TextUtils.isEmpty(key) || value == null) return;
  45 + if (map != null && map.get(key) == null) map.put(key, value);
  46 + }
  47 +
  48 + public void setQueryParameter(String key, String value) {
  49 + if (TextUtils.isEmpty(key) || value == null) return;
  50 + if (map != null) map.put(key, value);
  51 + }
  52 +
  53 + public interface SignCallback {
  54 + void onCall(String url);
  55 + }
  56 +
  57 + private boolean canSign(String... signPaths) {
  58 + if (signPaths == null || signPaths.length == 0) return true;
  59 + if (TextUtils.isEmpty(link)) return true;
  60 + for (String path : signPaths) if (path != null && link.contains(path)) return true;
  61 + return false;
  62 + }
  63 +
  64 + private String getPathString() {
  65 + if (map == null) return "";
  66 + StringBuilder stringBuilder = new StringBuilder();
  67 + for (String key : map.keySet()) {
  68 + stringBuilder.append(key).append("=").append(map.get(key)).append("&");
  69 + }
  70 + if (stringBuilder.length() > 0) {
  71 + stringBuilder.deleteCharAt(stringBuilder.length() - 1);
  72 + }
  73 + return stringBuilder.toString();
  74 + }
  75 +
  76 + public Disposable sign(SignCallback callback, String... signPaths) {
  77 + return Observable
  78 + .create((ObservableOnSubscribe<String>) emitter -> emitter.onNext(canSign(signPaths) ?
  79 + SignUtil.getOpenSignString(map, false, true) :
  80 + getPathString()))
  81 + .subscribeOn(Schedulers.io())
  82 + .observeOn(AndroidSchedulers.mainThread())
  83 + .subscribe(query -> {
  84 + if (TextUtils.isEmpty(query)) {
  85 + if (callback != null) callback.onCall(link);
  86 + } else {
  87 + Uri.Builder builder = new Uri.Builder();
  88 + builder.scheme(uri.getScheme());
  89 + builder.encodedAuthority(uri.getAuthority());
  90 + builder.encodedPath(uri.getPath() == null ? "" : uri.getPath().trim());
  91 + builder.encodedQuery(query);
  92 + builder.encodedFragment(uri.getFragment());
  93 + String url = Uri.encode(builder.build().toString(), "-![.:/,%?&=]");
  94 + if (callback != null) callback.onCall(url);
  95 + }
  96 + });
  97 + }
  98 +
  99 +
  100 + public String build() {
  101 + Uri.Builder builder = new Uri.Builder();
  102 + builder.scheme(uri.getScheme());
  103 + builder.encodedAuthority(uri.getAuthority());
  104 + builder.encodedPath(uri.getPath());
  105 +
  106 + StringBuilder stringBuilder = new StringBuilder();
  107 + for (String key : map.keySet()) {
  108 + stringBuilder.append(key).append("=").append(map.get(key)).append("&");
  109 + }
  110 + if (stringBuilder.length() > 0) {
  111 + stringBuilder.deleteCharAt(stringBuilder.length() - 1);
  112 + }
  113 +
  114 + builder.encodedQuery(stringBuilder.toString());
  115 + builder.encodedFragment(uri.getFragment());
  116 + return builder.build().toString();
  117 + }
  118 +
  119 + public static String getQueryParameterWithDecode(String query, String key) {
  120 + if (TextUtils.isEmpty(query) || TextUtils.isEmpty(key)) return "";
  121 +
  122 + int start = 0;
  123 + do {
  124 + int nextAmpersand = query.indexOf('&', start);
  125 + int end = nextAmpersand != -1 ? nextAmpersand : query.length();
  126 + int separator = query.indexOf('=', start);
  127 +
  128 + if (separator > end || separator == -1) separator = end;
  129 + if (separator - start == key.length() && query.regionMatches(start, key, 0, key.length()))
  130 + if (separator == end) return "";
  131 + else return Uri.decode(query.substring(separator + 1, end));
  132 + if (nextAmpersand != -1) start = nextAmpersand + 1;
  133 + else break;
  134 + } while (true);
  135 + return null;
  136 + }
  137 +
  138 + public static String getQueryParameter(String query, String key) {
  139 + if (TextUtils.isEmpty(query) || TextUtils.isEmpty(key)) return "";
  140 +
  141 + int start = 0;
  142 + do {
  143 + int nextAmpersand = query.indexOf('&', start);
  144 + int end = nextAmpersand != -1 ? nextAmpersand : query.length();
  145 + int separator = query.indexOf('=', start);
  146 +
  147 + if (separator > end || separator == -1) separator = end;
  148 + if (separator - start == key.length() && query.regionMatches(start, key, 0, key.length()))
  149 + if (separator == end) return "";
  150 + else return Uri.decode(query.substring(separator + 1, end));
  151 + if (nextAmpersand != -1) start = nextAmpersand + 1;
  152 + else break;
  153 + } while (true);
  154 + return null;
  155 + }
  156 +}