Commit bc416ae58356fb0dcfb8adef5b9ff87a3213f837
1 parent
31cde7c5
搭建网络请求框架
Showing
93 changed files
with
4175 additions
and
99 deletions
Too many changes to show.
To preserve performance only 93 of 103 files are displayed.
app/strike/build.gradle
app/strike/src/main/AndroidManifest.xml
| ... | ... | @@ -10,6 +10,7 @@ |
| 10 | 10 | android:allowBackup="true" |
| 11 | 11 | android:icon="@mipmap/ic_launcher" |
| 12 | 12 | android:label="@string/app_name" |
| 13 | + android:networkSecurityConfig="@xml/network_security_config" | |
| 13 | 14 | android:roundIcon="@mipmap/ic_launcher_round" |
| 14 | 15 | android:supportsRtl="true" |
| 15 | 16 | android:theme="@style/AppTheme"> | ... | ... |
app/strike/src/main/java/com/cnlive/strike/MainActivity.java
| 1 | 1 | package com.cnlive.strike; |
| 2 | 2 | |
| 3 | 3 | |
| 4 | -import android.content.Context; | |
| 5 | 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 | 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 | 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 | 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
app/strike/src/main/java/com/cnlive/strike/MyActivityTest1.java
app/strike/src/main/java/com/cnlive/strike/MyApp.java
| ... | ... | @@ -2,9 +2,18 @@ package com.cnlive.strike; |
| 2 | 2 | |
| 3 | 3 | import android.app.Application; |
| 4 | 4 | |
| 5 | +import com.cnlive.core.libs.base.application.AppConfig; | |
| 6 | + | |
| 5 | 7 | public class MyApp extends Application { |
| 6 | 8 | @Override |
| 7 | 9 | public void onCreate() { |
| 8 | 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 | 3 | |
| 4 | 4 | import android.content.Intent; |
| 5 | 5 | import android.os.Bundle; |
| 6 | +import android.os.Handler; | |
| 7 | +import android.util.Log; | |
| 6 | 8 | import android.view.LayoutInflater; |
| 7 | 9 | import android.view.View; |
| 8 | 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 | 23 | import androidx.annotation.NonNull; |
| 14 | 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 | 35 | public class MyFragment extends BaseFragment<MyFragmentView, MyPresenter> { |
| 18 | 36 | private View view; |
| 37 | + public TextView textView; | |
| 19 | 38 | |
| 20 | 39 | @Nullable |
| 21 | 40 | @Override |
| 22 | 41 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { |
| 23 | 42 | view = inflater.inflate(R.layout.activity_main1, container, false); |
| 43 | + textView = view.findViewById(R.id.tv1); | |
| 24 | 44 | return view; |
| 25 | 45 | } |
| 26 | 46 | |
| ... | ... | @@ -31,7 +51,58 @@ public class MyFragment extends BaseFragment<MyFragmentView, MyPresenter> { |
| 31 | 51 | view.findViewById(R.id.btn_test).setOnClickListener(new View.OnClickListener() { |
| 32 | 52 | @Override |
| 33 | 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 | 1 | package com.cnlive.strike; |
| 2 | 2 | |
| 3 | 3 | |
| 4 | -import android.content.Intent; | |
| 5 | 4 | import android.os.Bundle; |
| 6 | 5 | import android.view.LayoutInflater; |
| 7 | 6 | import android.view.View; |
| ... | ... | @@ -10,8 +9,8 @@ import android.view.ViewGroup; |
| 10 | 9 | import androidx.annotation.NonNull; |
| 11 | 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 | 16 | public class MyFragment1 extends BaseFragment { | ... | ... |
app/strike/src/main/java/com/cnlive/strike/MyFragment1View.java
app/strike/src/main/java/com/cnlive/strike/MyFragmentView.java
| 1 | 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 | 5 | public class MyFragmentView extends BaseView { |
| 6 | 6 | MyFragment fragment; |
| ... | ... | @@ -9,7 +9,7 @@ public class MyFragmentView extends BaseView { |
| 9 | 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 | 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 | 5 | public class MyPresenter extends BasePresenter<MyFragmentView> { |
| 7 | 6 | public void setData(String msg) { | ... | ... |
app/strike/src/main/java/com/cnlive/strike/MyPresenter1.java
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 | 1 | <?xml version="1.0" encoding="utf-8"?> |
| 2 | 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 | 5 | xmlns:app="http://schemas.android.com/apk/res-auto" |
| 6 | 6 | xmlns:tools="http://schemas.android.com/tools" |
| 7 | 7 | android:layout_width="match_parent" |
| ... | ... | @@ -20,5 +20,5 @@ |
| 20 | 20 | android:layout_width="wrap_content" |
| 21 | 21 | android:layout_height="wrap_content" |
| 22 | 22 | android:text="测试view" /> |
| 23 | - </RelativeLayout> | |
| 23 | + </LinearLayout> | |
| 24 | 24 | </layout> |
| 25 | 25 | \ No newline at end of file | ... | ... |
app/strike/src/main/res/xml/network_security_config.xml
0 → 100644
config.gradle
| ... | ... | @@ -71,6 +71,10 @@ ext { |
| 71 | 71 | rxjava : 'io.reactivex.rxjava2:rxjava:2.2.9', |
| 72 | 72 | rxandroid : 'io.reactivex.rxjava2:rxandroid:2.1.1', |
| 73 | 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 | 78 | //Retrofit |
| 75 | 79 | retrofit : 'com.squareup.retrofit2:retrofit:2.6.0', |
| 76 | 80 | retrofitConverterGson : 'com.squareup.retrofit2:converter-gson:2.6.0', |
| ... | ... | @@ -108,10 +112,10 @@ ext { |
| 108 | 112 | library.qmui, |
| 109 | 113 | library.qmui_arch, |
| 110 | 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 | 119 | //图片加载Glide |
| 116 | 120 | glide.api, |
| 117 | 121 | glide.transformations, |
| ... | ... | @@ -136,7 +140,8 @@ ext { |
| 136 | 140 | library.okhttp, |
| 137 | 141 | library.okhttpLoggingInterceptor, |
| 138 | 142 | library.greendao, |
| 139 | - | |
| 143 | + //管理rxjava生命周期 | |
| 144 | +// library.rx | |
| 140 | 145 | router.api, |
| 141 | 146 | |
| 142 | 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 | 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
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 | 4 | import android.annotation.SuppressLint; |
| ... | ... | @@ -6,6 +6,7 @@ import android.content.Context; |
| 6 | 6 | import android.content.pm.ActivityInfo; |
| 7 | 7 | import android.os.Bundle; |
| 8 | 8 | import android.os.Looper; |
| 9 | +import android.util.Log; | |
| 9 | 10 | import android.view.View; |
| 10 | 11 | import android.view.Window; |
| 11 | 12 | import android.view.WindowManager; |
| ... | ... | @@ -20,9 +21,10 @@ import androidx.core.content.ContextCompat; |
| 20 | 21 | import androidx.databinding.DataBindingUtil; |
| 21 | 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 | 30 | * @author ys |
| ... | ... | @@ -49,6 +51,8 @@ public abstract class BaseActivity extends AppCompatActivity { |
| 49 | 51 | context = this; |
| 50 | 52 | //activity管理 |
| 51 | 53 | ActivityCollector.addActivity(this); |
| 54 | + //创建订阅映射 | |
| 55 | + SubscriptionManager.getInstance().setCurrentDisposables(TAG); | |
| 52 | 56 | if (!isShowTitle) { |
| 53 | 57 | requestWindowFeature(Window.FEATURE_NO_TITLE); |
| 54 | 58 | } |
| ... | ... | @@ -210,6 +214,8 @@ public abstract class BaseActivity extends AppCompatActivity { |
| 210 | 214 | super.onDestroy(); |
| 211 | 215 | //activity管理 |
| 212 | 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 | 3 | import android.os.Bundle; |
| 4 | 4 | |
| 5 | 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 | 8 | import com.hannesdorfmann.mosby3.mvp.MvpPresenter; |
| 9 | 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 | 3 | import android.os.Bundle; |
| 4 | 4 | |
| ... | ... | @@ -6,7 +6,7 @@ import androidx.annotation.NonNull; |
| 6 | 6 | import androidx.databinding.DataBindingUtil; |
| 7 | 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 | 10 | import com.hannesdorfmann.mosby3.mvp.MvpPresenter; |
| 11 | 11 | import com.hannesdorfmann.mosby3.mvp.MvpView; |
| 12 | 12 | |
| ... | ... | @@ -17,7 +17,7 @@ import com.hannesdorfmann.mosby3.mvp.MvpView; |
| 17 | 17 | * @param <D> Databind Page Data |
| 18 | 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 | 22 | public T binding; |
| 23 | 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 | 3 | import android.os.Bundle; |
| 4 | 4 | import android.view.View; |
| ... | ... | @@ -9,11 +9,11 @@ import androidx.annotation.NonNull; |
| 9 | 9 | import androidx.annotation.Nullable; |
| 10 | 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 | 19 | * 基类fragment |
| ... | ... | @@ -25,6 +25,7 @@ import com.cnlive.libs.base.util.StatusBarUtil; |
| 25 | 25 | public abstract class BaseFragment<V extends BaseView, P extends BasePresenter<V>> extends com.hannesdorfmann.mosby3.mvp.MvpFragment<V, P> { |
| 26 | 26 | public V view; |
| 27 | 27 | public P presenter; |
| 28 | + protected final String TAG = this.getClass().getSimpleName(); | |
| 28 | 29 | |
| 29 | 30 | @Override |
| 30 | 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 | 4 | import com.hannesdorfmann.mosby3.mvp.MvpBasePresenter; |
| 5 | 5 | |
| 6 | 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
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
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
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
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 | 3 | import android.content.Context; |
| 4 | 4 | import android.content.pm.ApplicationInfo; |
| ... | ... | @@ -6,7 +6,7 @@ import android.content.pm.PackageManager; |
| 6 | 6 | import android.text.TextUtils; |
| 7 | 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 | 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
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
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
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
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
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
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
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
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
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 | 3 | import android.content.Context; |
| 4 | 4 | import android.graphics.Bitmap; |
| ... | ... | @@ -11,9 +11,9 @@ import android.widget.ImageView; |
| 11 | 11 | |
| 12 | 12 | import com.bumptech.glide.request.RequestOptions; |
| 13 | 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 | 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
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
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 | 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 | 7 | public class LogUtil { |
| 8 | 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
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
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
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
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
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
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
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
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
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
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 | 3 | import android.annotation.TargetApi; |
| 4 | 4 | import android.nfc.NdefRecord; |
| ... | ... | @@ -7,7 +7,6 @@ import android.text.TextPaint; |
| 7 | 7 | import android.util.Base64; |
| 8 | 8 | import android.util.Log; |
| 9 | 9 | |
| 10 | -import java.io.UnsupportedEncodingException; | |
| 11 | 10 | import java.net.URLDecoder; |
| 12 | 11 | import java.net.URLEncoder; |
| 13 | 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
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
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
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
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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 111 | \ No newline at end of file | ... | ... |