3 | *
4 | * This file is part of Meizhi
5 | *
6 | * Meizhi is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * Meizhi is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with Meizhi. If not, see .
18 | */
19 |
20 | package com.github.weiss.example.view;
21 |
22 | import android.content.Context;
23 | import android.util.AttributeSet;
24 | import android.widget.ImageView;
25 |
26 | public class RatioImageView extends ImageView {
27 |
28 | private int originalWidth;
29 | private int originalHeight;
30 |
31 |
32 | public RatioImageView(Context context) {
33 | super(context);
34 | }
35 |
36 |
37 | public RatioImageView(Context context, AttributeSet attrs) {
38 | super(context, attrs);
39 | }
40 |
41 |
42 | public RatioImageView(Context context, AttributeSet attrs, int defStyleAttr) {
43 | super(context, attrs, defStyleAttr);
44 | }
45 |
46 |
47 | public void setOriginalSize(int originalWidth, int originalHeight) {
48 | this.originalWidth = originalWidth;
49 | this.originalHeight = originalHeight;
50 | }
51 |
52 |
53 | @Override
54 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
55 | if (originalWidth > 0 && originalHeight > 0) {
56 | float ratio = (float) originalWidth / (float) originalHeight;
57 |
58 | int width = MeasureSpec.getSize(widthMeasureSpec);
59 | int height = MeasureSpec.getSize(heightMeasureSpec);
60 | // TODO: 现在只支持固定宽度
61 | if (width > 0) {
62 | height = (int) ((float) width / ratio);
63 | }
64 |
65 | setMeasuredDimension(width, height);
66 | } else {
67 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/weiss/example/view/behavior/helper/MathUtils.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.example.view.behavior.helper;
2 |
3 | /**
4 | * Copy from Android design library
5 | * Created by chensuilun on 16/7/24.
6 | */
7 | class MathUtils {
8 |
9 | static int constrain(int amount, int low, int high) {
10 | return amount < low ? low : (amount > high ? high : amount);
11 | }
12 |
13 | static float constrain(float amount, float low, float high) {
14 | return amount < low ? low : (amount > high ? high : amount);
15 | }
16 |
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/weiss/example/view/behavior/helper/ViewOffsetBehavior.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.example.view.behavior.helper;
2 |
3 | import android.content.Context;
4 | import androidx.coordinatorlayout.widget.CoordinatorLayout;
5 | import android.util.AttributeSet;
6 | import android.view.View;
7 |
8 | /**
9 | * Copy from Android design library
10 | *
11 | * Behavior will automatically sets up a {@link com.google.android.material.appbar.ViewOffsetHelper} on a {@link View}.
12 | */
13 | public class ViewOffsetBehavior extends CoordinatorLayout.Behavior {
14 |
15 | private ViewOffsetHelper mViewOffsetHelper;
16 |
17 | private int mTempTopBottomOffset = 0;
18 | private int mTempLeftRightOffset = 0;
19 |
20 | public ViewOffsetBehavior() {
21 | }
22 |
23 | public ViewOffsetBehavior(Context context, AttributeSet attrs) {
24 | super(context, attrs);
25 | }
26 |
27 | @Override
28 | public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
29 | // First let lay the child out
30 | layoutChild(parent, child, layoutDirection);
31 |
32 | if (mViewOffsetHelper == null) {
33 | mViewOffsetHelper = new ViewOffsetHelper(child);
34 | }
35 | mViewOffsetHelper.onViewLayout();
36 |
37 | if (mTempTopBottomOffset != 0) {
38 | mViewOffsetHelper.setTopAndBottomOffset(mTempTopBottomOffset);
39 | mTempTopBottomOffset = 0;
40 | }
41 | if (mTempLeftRightOffset != 0) {
42 | mViewOffsetHelper.setLeftAndRightOffset(mTempLeftRightOffset);
43 | mTempLeftRightOffset = 0;
44 | }
45 |
46 | return true;
47 | }
48 |
49 | protected void layoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
50 | // Let the parent lay it out by default
51 | parent.onLayoutChild(child, layoutDirection);
52 | }
53 |
54 | public boolean setTopAndBottomOffset(int offset) {
55 | if (mViewOffsetHelper != null) {
56 | return mViewOffsetHelper.setTopAndBottomOffset(offset);
57 | } else {
58 | mTempTopBottomOffset = offset;
59 | }
60 | return false;
61 | }
62 |
63 | public boolean setLeftAndRightOffset(int offset) {
64 | if (mViewOffsetHelper != null) {
65 | return mViewOffsetHelper.setLeftAndRightOffset(offset);
66 | } else {
67 | mTempLeftRightOffset = offset;
68 | }
69 | return false;
70 | }
71 |
72 | public int getTopAndBottomOffset() {
73 | return mViewOffsetHelper != null ? mViewOffsetHelper.getTopAndBottomOffset() : 0;
74 | }
75 |
76 | public int getLeftAndRightOffset() {
77 | return mViewOffsetHelper != null ? mViewOffsetHelper.getLeftAndRightOffset() : 0;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/weiss/example/view/behavior/helper/ViewOffsetHelper.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.example.view.behavior.helper;
2 |
3 |
4 | import android.os.Build;
5 | import androidx.core.view.ViewCompat;
6 | import android.view.View;
7 | import android.view.ViewParent;
8 |
9 | /**
10 | * Copy from Android design library
11 | *
12 | * Utility helper for moving a {@link View} around using
13 | * {@link View#offsetLeftAndRight(int)} and
14 | * {@link View#offsetTopAndBottom(int)}.
15 | *
16 | * Also the setting of absolute offsets (similar to translationX/Y), rather than additive
17 | * offsets.
18 | */
19 | public class ViewOffsetHelper {
20 |
21 | private final View mView;
22 |
23 | private int mLayoutTop;
24 | private int mLayoutLeft;
25 | private int mOffsetTop;
26 | private int mOffsetLeft;
27 |
28 | public ViewOffsetHelper(View view) {
29 | mView = view;
30 | }
31 |
32 | public void onViewLayout() {
33 | // Now grab the intended top
34 | mLayoutTop = mView.getTop();
35 | mLayoutLeft = mView.getLeft();
36 |
37 | // And offset it as needed
38 | updateOffsets();
39 | }
40 |
41 | private void updateOffsets() {
42 | ViewCompat.offsetTopAndBottom(mView, mOffsetTop - (mView.getTop() - mLayoutTop));
43 | ViewCompat.offsetLeftAndRight(mView, mOffsetLeft - (mView.getLeft() - mLayoutLeft));
44 |
45 | // Manually invalidate the view and parent to make sure we get drawn pre-M
46 | if (Build.VERSION.SDK_INT < 23) {
47 | tickleInvalidationFlag(mView);
48 | final ViewParent vp = mView.getParent();
49 | if (vp instanceof View) {
50 | tickleInvalidationFlag((View) vp);
51 | }
52 | }
53 | }
54 |
55 | private static void tickleInvalidationFlag(View view) {
56 | final float y = ViewCompat.getTranslationY(view);
57 | ViewCompat.setTranslationY(view, y + 1);
58 | ViewCompat.setTranslationY(view, y);
59 | }
60 |
61 | /**
62 | * Set the top and bottom offset for this {@link ViewOffsetHelper}'s view.
63 | *
64 | * @param offset the offset in px.
65 | * @return true if the offset has changed
66 | */
67 | public boolean setTopAndBottomOffset(int offset) {
68 | if (mOffsetTop != offset) {
69 | mOffsetTop = offset;
70 | updateOffsets();
71 | return true;
72 | }
73 | return false;
74 | }
75 |
76 | /**
77 | * Set the left and right offset for this {@link ViewOffsetHelper}'s view.
78 | *
79 | * @param offset the offset in px.
80 | * @return true if the offset has changed
81 | */
82 | public boolean setLeftAndRightOffset(int offset) {
83 | if (mOffsetLeft != offset) {
84 | mOffsetLeft = offset;
85 | updateOffsets();
86 | return true;
87 | }
88 | return false;
89 | }
90 |
91 | public int getTopAndBottomOffset() {
92 | return mOffsetTop;
93 | }
94 |
95 | public int getLeftAndRightOffset() {
96 | return mOffsetLeft;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/weiss/example/view/behavior/uc/UcNewsContentBehavior.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.example.view.behavior.uc;
2 |
3 | import android.content.Context;
4 | import androidx.coordinatorlayout.widget.CoordinatorLayout;
5 | import android.util.AttributeSet;
6 | import android.util.Log;
7 | import android.view.View;
8 |
9 | import com.github.weiss.example.App;
10 | import com.github.weiss.example.BuildConfig;
11 | import com.github.weiss.example.R;
12 | import com.github.weiss.example.view.behavior.helper.HeaderScrollingViewBehavior;
13 |
14 | import java.util.List;
15 |
16 |
17 | /**
18 | * 可滚动的新闻列表Behavior
19 | *
20 | * Created by chensuilun on 16/7/24.
21 | */
22 | public class UcNewsContentBehavior extends HeaderScrollingViewBehavior {
23 | private static final String TAG = "UcNewsContentBehavior";
24 |
25 | public UcNewsContentBehavior() {
26 | }
27 |
28 | public UcNewsContentBehavior(Context context, AttributeSet attrs) {
29 | super(context, attrs);
30 | }
31 |
32 | @Override
33 | public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
34 | return isDependOn(dependency);
35 | }
36 |
37 | @Override
38 | public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
39 | if (BuildConfig.DEBUG) {
40 | Log.d(TAG, "onDependentViewChanged");
41 | }
42 | offsetChildAsNeeded(parent, child, dependency);
43 | return false;
44 | }
45 |
46 | private void offsetChildAsNeeded(CoordinatorLayout parent, View child, View dependency) {
47 | child.setTranslationY((int) (-dependency.getTranslationY() / (getHeaderOffsetRange() * 1.0f) * getScrollRange(dependency)));
48 |
49 | }
50 |
51 |
52 | @Override
53 | protected View findFirstDependency(List views) {
54 | for (int i = 0, z = views.size(); i < z; i++) {
55 | View view = views.get(i);
56 | if (isDependOn(view))
57 | return view;
58 | }
59 | return null;
60 | }
61 |
62 | @Override
63 | protected int getScrollRange(View v) {
64 | if (isDependOn(v)) {
65 | return Math.max(0, v.getMeasuredHeight() - getFinalHeight());
66 | } else {
67 | return super.getScrollRange(v);
68 | }
69 | }
70 |
71 | private int getHeaderOffsetRange() {
72 | return App.getAppContext().getResources().getDimensionPixelOffset(R.dimen.uc_news_header_pager_offset);
73 | }
74 |
75 | private int getFinalHeight() {
76 | return App.getAppContext().getResources().getDimensionPixelOffset(R.dimen.uc_news_tabs_height) + App.getAppContext().getResources().getDimensionPixelOffset(R.dimen.uc_news_header_title_height);
77 | }
78 |
79 |
80 | private boolean isDependOn(View dependency) {
81 | return dependency != null && dependency.getId() == R.id.id_uc_news_header_pager;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/weiss/example/view/behavior/uc/UcNewsTabBehavior.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.example.view.behavior.uc;
2 |
3 | import android.content.Context;
4 | import androidx.coordinatorlayout.widget.CoordinatorLayout;
5 | import android.util.AttributeSet;
6 | import android.util.Log;
7 | import android.view.View;
8 |
9 | import com.github.weiss.example.App;
10 | import com.github.weiss.example.BuildConfig;
11 | import com.github.weiss.example.R;
12 | import com.github.weiss.example.view.behavior.helper.HeaderScrollingViewBehavior;
13 |
14 | import java.util.List;
15 |
16 |
17 | /**
18 | * 新闻tab behavior
19 | *
20 | * Created by chensuilun on 16/7/25.
21 | */
22 | public class UcNewsTabBehavior extends HeaderScrollingViewBehavior {
23 | private static final String TAG = "UcNewsTabBehavior";
24 |
25 | public UcNewsTabBehavior() {
26 | }
27 |
28 | public UcNewsTabBehavior(Context context, AttributeSet attrs) {
29 | super(context, attrs);
30 | }
31 |
32 |
33 | @Override
34 | protected void layoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
35 | super.layoutChild(parent, child, layoutDirection);
36 | if (BuildConfig.DEBUG) {
37 | Log.d(TAG, "layoutChild:top" + child.getTop() + ",height" + child.getHeight());
38 | }
39 | }
40 |
41 | @Override
42 | public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
43 | return isDependOn(dependency);
44 | }
45 |
46 |
47 | @Override
48 | public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
49 | if (BuildConfig.DEBUG) {
50 | Log.d(TAG, "onDependentViewChanged: dependency.getTranslationY():" + dependency.getTranslationY());
51 | }
52 | offsetChildAsNeeded(parent, child, dependency);
53 | return false;
54 | }
55 |
56 | private void offsetChildAsNeeded(CoordinatorLayout parent, View child, View dependency) {
57 | float offsetRange = dependency.getTop() + getFinalHeight() - child.getTop();
58 | int headerOffsetRange = getHeaderOffsetRange();
59 | if (dependency.getTranslationY() == headerOffsetRange) {
60 | child.setTranslationY(offsetRange);
61 | } else if (dependency.getTranslationY() == 0) {
62 | child.setTranslationY(0);
63 | } else {
64 | child.setTranslationY((int) (dependency.getTranslationY() / (getHeaderOffsetRange() * 1.0f) * offsetRange));
65 | }
66 | }
67 |
68 |
69 | @Override
70 | protected View findFirstDependency(List views) {
71 | for (int i = 0, z = views.size(); i < z; i++) {
72 | View view = views.get(i);
73 | if (isDependOn(view))
74 | return view;
75 | }
76 | return null;
77 | }
78 |
79 | private int getHeaderOffsetRange() {
80 | return App.getAppContext().getResources().getDimensionPixelOffset(R.dimen.uc_news_header_pager_offset);
81 | }
82 |
83 | private int getFinalHeight() {
84 | return App.getAppContext().getResources().getDimensionPixelOffset(R.dimen.uc_news_header_title_height);
85 | }
86 |
87 |
88 | private boolean isDependOn(View dependency) {
89 | return dependency != null && dependency.getId() == R.id.id_uc_news_header_pager;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/weiss/example/view/behavior/uc/UcNewsTitleBehavior.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.example.view.behavior.uc;
2 |
3 | import android.content.Context;
4 | import androidx.coordinatorlayout.widget.CoordinatorLayout;
5 | import android.util.AttributeSet;
6 | import android.util.Log;
7 | import android.view.View;
8 |
9 | import com.github.weiss.example.App;
10 | import com.github.weiss.example.BuildConfig;
11 | import com.github.weiss.example.R;
12 |
13 | /**
14 | * 新闻标题
15 | *
16 | * Created by chensuilun on 16/7/25.
17 | */
18 | public class UcNewsTitleBehavior extends CoordinatorLayout.Behavior {
19 | private static final String TAG = "UcNewsTitleBehavior";
20 |
21 | public UcNewsTitleBehavior() {
22 | }
23 |
24 | public UcNewsTitleBehavior(Context context, AttributeSet attrs) {
25 | super(context, attrs);
26 | }
27 |
28 |
29 | @Override
30 | public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
31 | // FIXME: 16/7/27 不知道为啥在XML设置-45dip,解析出来的topMargin少了1个px,所以这里用代码设置一遍
32 | ((CoordinatorLayout.LayoutParams) child.getLayoutParams()).topMargin = -getTitleHeight();
33 | parent.onLayoutChild(child, layoutDirection);
34 | if (BuildConfig.DEBUG) {
35 | Log.d(TAG, "layoutChild:top" + child.getTop() + ",height" + child.getHeight());
36 | }
37 | return true;
38 | }
39 |
40 | @Override
41 | public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
42 | return isDependOn(dependency);
43 | }
44 |
45 |
46 | @Override
47 | public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
48 | offsetChildAsNeeded(parent, child, dependency);
49 | return false;
50 | }
51 |
52 | private void offsetChildAsNeeded(CoordinatorLayout parent, View child, View dependency) {
53 | int headerOffsetRange = getHeaderOffsetRange();
54 | int titleOffsetRange = getTitleHeight();
55 | if (BuildConfig.DEBUG) {
56 | Log.d(TAG, "offsetChildAsNeeded:" + dependency.getTranslationY());
57 | }
58 | if (dependency.getTranslationY() == headerOffsetRange) {
59 | child.setTranslationY(titleOffsetRange);
60 | } else if (dependency.getTranslationY() == 0) {
61 | child.setTranslationY(0);
62 | } else {
63 | child.setTranslationY((int) (dependency.getTranslationY() / (headerOffsetRange * 1.0f) * titleOffsetRange));
64 | }
65 |
66 | }
67 |
68 | private int getHeaderOffsetRange() {
69 | return App.getAppContext().getResources().getDimensionPixelOffset(R.dimen.uc_news_header_pager_offset);
70 | }
71 |
72 | private int getTitleHeight() {
73 | return App.getAppContext().getResources().getDimensionPixelOffset(R.dimen.uc_news_header_title_height);
74 | }
75 |
76 |
77 | private boolean isDependOn(View dependency) {
78 | return dependency != null && dependency.getId() == R.id.id_uc_news_header_pager;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/weiss/example/view/webview/CommonWebChromeClient.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.example.view.webview;
2 |
3 | import androidx.appcompat.app.ActionBar;
4 | import android.view.View;
5 | import android.webkit.JsPromptResult;
6 | import android.webkit.JsResult;
7 | import android.webkit.WebChromeClient;
8 | import android.webkit.WebView;
9 | import android.widget.ProgressBar;
10 |
11 | public class CommonWebChromeClient extends WebChromeClient {
12 |
13 | private ProgressBar mBar;
14 |
15 | private View mLoadingView;
16 |
17 | private ActionBar mActionBar;
18 |
19 | public CommonWebChromeClient(ProgressBar bar, View loadingView) {
20 |
21 | this(bar, loadingView, null);
22 | }
23 |
24 | public CommonWebChromeClient(ProgressBar bar, View loadingView, ActionBar actionBar) {
25 |
26 | mBar = bar;
27 | mLoadingView = loadingView;
28 | mActionBar = actionBar;
29 | }
30 |
31 | @Override
32 | public void onReceivedTitle(WebView view, String title) {
33 |
34 | if (mActionBar != null) {
35 | mActionBar.setTitle(title);
36 | }
37 | }
38 |
39 | @Override
40 | public void onProgressChanged(WebView view, int newProgress) {
41 |
42 | if (mBar != null) {
43 | mBar.setProgress(newProgress);
44 | if (newProgress >= 100) {
45 | mBar.setVisibility(View.GONE);
46 | mLoadingView.setVisibility(View.GONE);
47 | }
48 | }
49 | }
50 |
51 | @Override
52 | public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
53 |
54 | return super.onJsAlert(view, url, message, result);
55 | }
56 |
57 | @Override
58 | public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
59 |
60 | return super.onJsConfirm(view, url, message, result);
61 | }
62 |
63 | @Override
64 | public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
65 |
66 | return super.onJsPrompt(view, url, message, defaultValue, result);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/weiss/example/view/webview/CommonWebView.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.example.view.webview;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.os.Build;
6 | import android.util.AttributeSet;
7 | import android.webkit.WebSettings;
8 | import android.webkit.WebView;
9 |
10 |
11 | /**
12 | * 通用的WebView
13 | */
14 | public class CommonWebView extends WebView {
15 |
16 | public static final String ENCODING_UTF_8 = "UTF-8";
17 |
18 | public static final String MIME_TYPE = "text/html";
19 |
20 | public CommonWebView(Context context) {
21 |
22 | super(context);
23 | init();
24 | }
25 |
26 | public CommonWebView(Context context, AttributeSet attrs) {
27 |
28 | super(context, attrs);
29 | init();
30 | }
31 |
32 | public CommonWebView(Context context, AttributeSet attrs, int defStyleAttr) {
33 |
34 | super(context, attrs, defStyleAttr);
35 | init();
36 | }
37 |
38 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
39 | public CommonWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
40 |
41 | super(context, attrs, defStyleAttr, defStyleRes);
42 | init();
43 | }
44 |
45 | private void init() {
46 |
47 | if (isInEditMode()) {
48 | return;
49 | }
50 | WebSettings settings = getSettings();
51 | settings.setJavaScriptEnabled(true);
52 | settings.setBuiltInZoomControls(false);
53 | //设置缓存模式
54 | settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
55 | //开启DOM storage API功能
56 | settings.setDomStorageEnabled(true);
57 | //开启database storage 功能
58 | settings.setDatabaseEnabled(true);
59 |
60 | String cacheDir = getContext().getFilesDir().getAbsolutePath() + "web_cache";
61 | settings.setAppCachePath(cacheDir);
62 | settings.setAppCacheEnabled(true);
63 |
64 | settings.setLoadsImagesAutomatically(true);
65 | settings.setDefaultTextEncodingName(ENCODING_UTF_8);
66 | settings.setBlockNetworkImage(false);
67 | settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
68 | settings.setUseWideViewPort(true);
69 | settings.setLoadWithOverviewMode(true);
70 | setHorizontalScrollBarEnabled(false);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/weiss/example/view/webview/CommonWebViewClient.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.example.view.webview;
2 |
3 | import android.graphics.Bitmap;
4 | import androidx.appcompat.app.ActionBar;
5 | import androidx.appcompat.app.AppCompatActivity;
6 | import android.webkit.WebResourceRequest;
7 | import android.webkit.WebResourceResponse;
8 | import android.webkit.WebView;
9 |
10 | import com.github.weiss.example.ui.WebActivity;
11 |
12 |
13 | public class CommonWebViewClient extends android.webkit.WebViewClient {
14 |
15 |
16 | private AppCompatActivity mActivity;
17 |
18 | public CommonWebViewClient(AppCompatActivity activity) {
19 |
20 | mActivity = activity;
21 | }
22 |
23 | @Override
24 | public void onLoadResource(WebView view, String url) {
25 |
26 | super.onLoadResource(view, url);
27 | }
28 |
29 | @Override
30 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
31 |
32 |
33 | if (url != null && url.startsWith("orpheus")) {
34 | return true;
35 | }
36 | if (url != null && url.startsWith("http")) {
37 | WebActivity.start(mActivity, url);
38 | return true;
39 | }
40 | return true;
41 | }
42 |
43 | @Override
44 | public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
45 |
46 | return super.shouldInterceptRequest(view, url);
47 | }
48 |
49 | @Override
50 | public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
51 |
52 | return super.shouldInterceptRequest(view, request);
53 | }
54 |
55 | @Override
56 | public void onPageStarted(WebView view, String url, Bitmap favicon) {
57 |
58 | super.onPageStarted(view, url, favicon);
59 | }
60 |
61 | @Override
62 | public void onPageFinished(WebView view, String url) {
63 |
64 | super.onPageFinished(view, url);
65 | ActionBar actionBar = mActivity.getSupportActionBar();
66 | if (actionBar != null) {
67 | actionBar.setTitle(view.getTitle());
68 | }
69 | }
70 |
71 | @Override
72 | public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
73 |
74 | super.onReceivedError(view, errorCode, description, failingUrl);
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/weiss/example/view/webview/LoveVideoView.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.example.view.webview;
2 |
3 | import android.content.Context;
4 | import android.media.MediaPlayer;
5 | import android.util.AttributeSet;
6 | import android.util.Base64;
7 | import android.webkit.WebChromeClient;
8 | import android.webkit.WebSettings;
9 | import android.webkit.WebView;
10 | import android.webkit.WebViewClient;
11 |
12 | import java.io.InputStream;
13 |
14 |
15 | public class LoveVideoView extends WebView {
16 |
17 | private final Context mContext;
18 |
19 |
20 | public LoveVideoView(Context context) {
21 |
22 | this(context, null);
23 | }
24 |
25 |
26 | public LoveVideoView(Context context, AttributeSet attrs) {
27 |
28 | this(context, attrs, 0);
29 | }
30 |
31 |
32 | public LoveVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
33 |
34 | super(context, attrs, defStyleAttr);
35 | mContext = context;
36 | init();
37 | }
38 |
39 |
40 | void init() {
41 |
42 | setWebViewClient(new LoveClient());
43 | setWebChromeClient(new Chrome());
44 | WebSettings webSettings = getSettings();
45 | webSettings.setJavaScriptEnabled(true);
46 | webSettings.setAllowFileAccess(true);
47 | webSettings.setDatabaseEnabled(true);
48 | webSettings.setDomStorageEnabled(true);
49 | webSettings.setSaveFormData(false);
50 | webSettings.setAppCacheEnabled(true);
51 | webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
52 | webSettings.setLoadWithOverviewMode(false);
53 | webSettings.setUseWideViewPort(true);
54 | }
55 |
56 |
57 | private class LoveClient extends WebViewClient {
58 |
59 | @Override
60 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
61 |
62 | view.loadUrl(url);
63 | return true;
64 | }
65 |
66 |
67 | @Override
68 | public void onPageFinished(WebView view, String url) {
69 |
70 | super.onPageFinished(view, url);
71 | // 这些视频需要hack CSS才能达到全屏播放的效果
72 | if (url.contains("www.vmovier.com")) {
73 | injectCSS("vmovier.css");
74 | } else if (url.contains("video.weibo.com")) {
75 | injectCSS("weibo.css");
76 | } else if (url.contains("m.miaopai.com")) {
77 | injectCSS("miaopai.css");
78 | }
79 | }
80 | }
81 |
82 |
83 | private void injectCSS(String filename) {
84 |
85 | try {
86 | InputStream inputStream = mContext.getAssets().open(filename);
87 | byte[] buffer = new byte[inputStream.available()];
88 | inputStream.read(buffer);
89 | inputStream.close();
90 | String encoded = Base64.encodeToString(buffer, Base64.NO_WRAP);
91 | loadUrl("javascript:(function() {" +
92 | "var parent = document.getElementsByTagName('head').item(0);" +
93 | "var style = document.createElement('style');" +
94 | "style.type = 'text/css';" +
95 | // Tell the browser to BASE64-decode the string into your script !!!
96 | "style.innerHTML = window.atob('" + encoded + "');" +
97 | "parent.appendChild(style)" +
98 | "})()");
99 | } catch (Exception e) {
100 | e.printStackTrace();
101 | }
102 | }
103 |
104 |
105 | private class Chrome extends WebChromeClient
106 | implements MediaPlayer.OnCompletionListener {
107 |
108 | @Override
109 | public void onCompletion(MediaPlayer player) {
110 |
111 | if (player != null) {
112 | if (player.isPlaying()) player.stop();
113 | player.reset();
114 | player.release();
115 | player = null;
116 | }
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/black_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xm1nam0/RxCore/595f08ee480e17d7b4ec93bed3e5e8929434c8e2/app/src/main/res/drawable/ic_copy.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xm1nam0/RxCore/595f08ee480e17d7b4ec93bed3e5e8929434c8e2/app/src/main/res/drawable/ic_share.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
21 |
22 |
23 |
24 |
29 |
30 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_picture.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_web.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
17 |
18 |
19 |
22 |
23 |
24 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_main.xml:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_gank.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
19 |
20 |
21 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/navigation_content.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
18 |
46 |
47 |
48 |
55 |
56 |
61 |
62 |
69 |
70 |
71 |
72 |
73 |
83 |
84 |
90 |
98 |
99 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/recyclerview_base.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
18 |
19 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_load_more.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
18 |
19 |
27 |
28 |
29 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_toolbar.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_web.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xm1nam0/RxCore/595f08ee480e17d7b4ec93bed3e5e8929434c8e2/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xm1nam0/RxCore/595f08ee480e17d7b4ec93bed3e5e8929434c8e2/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xm1nam0/RxCore/595f08ee480e17d7b4ec93bed3e5e8929434c8e2/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xm1nam0/RxCore/595f08ee480e17d7b4ec93bed3e5e8929434c8e2/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xm1nam0/RxCore/595f08ee480e17d7b4ec93bed3e5e8929434c8e2/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xm1nam0/RxCore/595f08ee480e17d7b4ec93bed3e5e8929434c8e2/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xm1nam0/RxCore/595f08ee480e17d7b4ec93bed3e5e8929434c8e2/app/src/main/res/mipmap-xxhdpi/bg.jpg
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xm1nam0/RxCore/595f08ee480e17d7b4ec93bed3e5e8929434c8e2/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xm1nam0/RxCore/595f08ee480e17d7b4ec93bed3e5e8929434c8e2/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xm1nam0/RxCore/595f08ee480e17d7b4ec93bed3e5e8929434c8e2/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xm1nam0/RxCore/595f08ee480e17d7b4ec93bed3e5e8929434c8e2/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
8 | #dd000000
9 | #FFF5F5F5
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 16dp
3 | 8dp
4 |
5 |
6 |
7 | 45dip
8 | -45dip
9 | -90dip
10 | 45dip
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | RxCore
3 | Settings
4 | DOIT
5 | 是否保存图片?
6 | 正在加载更多...
7 | 搜索
8 |
9 | com.view.behavior.uc.UcNewsContentBehavior
10 | com.view.behavior.uc.UcNewsHeaderPagerBehavior
11 | com.view.behavior.uc.UcNewsTitleBehavior
12 | com.view.behavior.uc.UcNewsTabBehavior
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
14 |
17 |
18 |
19 |
20 |
21 |
24 |
25 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | mavenCentral()
7 | maven {
8 | url 'https://maven.google.com/'
9 | name 'Google'
10 | }
11 | google()
12 | }
13 |
14 | dependencies {
15 | classpath 'com.android.tools.build:gradle:3.5.2'
16 | classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
17 | classpath 'com.jakewharton:butterknife-gradle-plugin:10.2.0'
18 |
19 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
20 | // classpath 'me.tatarka:gradle-retrolambda:3.5.0'
21 | // NOTE: Do not place your application dependencies here; they belong
22 | // in the individual module build.gradle files
23 | }
24 | }
25 |
26 |
27 | allprojects {
28 | repositories {
29 | jcenter()
30 | mavenCentral()
31 | maven { url "https://jitpack.io" }
32 | maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
33 | maven {
34 | url 'https://maven.google.com/'
35 | name 'Google'
36 | }
37 | }
38 | }
39 |
40 | allprojects {
41 | tasks.withType(Javadoc) {
42 | options.addStringOption('Xdoclint:none', '-quiet')
43 | options.addStringOption('encoding', 'UTF-8')
44 | }
45 | }
46 |
47 |
48 | task clean(type: Delete) {
49 | delete rootProject.buildDir
50 | }
51 |
52 | ext {
53 | androidVersionCode = 7
54 | androidVersionName = '1.6.0'
55 |
56 | androidCompileSdkVersion = 28
57 | androidBuildToolsVersion = '26.1.0'
58 | androidSupportSdkVersion = '28.0.0'
59 | androidMinSdkVersion = 17
60 | androidTargetSdkVersion = 28
61 |
62 | junitVersion = '4.12'
63 |
64 | butterknifeVersion = '10.2.0'
65 | rxAndroidVersion = '2.1.1'
66 | rxjava2Version = '2.2.13'
67 | retrofit2Version = '2.6.2'
68 | gsonVersion = '2.8.5'
69 | supportXVersion = '1.0.0'
70 | commonVersion = 'x1.1.0'
71 | }
--------------------------------------------------------------------------------
/core/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/core/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 | group = 'com.github.0xm1nam0'
4 | //apply plugin: 'me.tatarka.retrolambda'
5 |
6 | // Java8 not fully supported in library projects yet, https://code.google.com/p/android/issues/detail?id=211386
7 | // this is a temporary workaround to get at least lambdas compiling
8 | /*gradle.projectsEvaluated {
9 | tasks.withType(JavaCompile) {
10 | options.compilerArgs << "-Xbootclasspath/a:" + System.properties.get("java.home") + "/lib/rt.jar"
11 | }
12 | }*/
13 |
14 | android {
15 |
16 | def globalConfiguration = rootProject.extensions.getByName("ext")
17 |
18 | compileSdkVersion globalConfiguration["androidCompileSdkVersion"]
19 |
20 | defaultConfig {
21 | minSdkVersion globalConfiguration["androidMinSdkVersion"]
22 | targetSdkVersion globalConfiguration["androidTargetSdkVersion"]
23 | versionCode globalConfiguration["androidVersionCode"]
24 | versionName globalConfiguration["androidVersionName"]
25 |
26 | }
27 | buildTypes {
28 | release {
29 | minifyEnabled false
30 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
31 | }
32 | }
33 |
34 | compileOptions {
35 | sourceCompatibility JavaVersion.VERSION_1_8
36 | targetCompatibility JavaVersion.VERSION_1_8
37 | }
38 |
39 | lintOptions {
40 | abortOnError false
41 | }
42 | }
43 |
44 | dependencies {
45 | api fileTree(dir: 'libs', include: ['*.jar'])
46 |
47 | implementation "androidx.appcompat:appcompat:$rootProject.ext.supportXVersion"
48 | implementation "com.google.android.material:material:$rootProject.ext.supportXVersion"
49 | implementation "androidx.recyclerview:recyclerview:$rootProject.ext.supportXVersion"
50 | implementation "androidx.legacy:legacy-support-v4:$rootProject.ext.supportXVersion"
51 |
52 | annotationProcessor "com.jakewharton:butterknife-compiler:$rootProject.ext.butterknifeVersion"
53 | implementation "com.jakewharton:butterknife:$rootProject.ext.butterknifeVersion"
54 | implementation 'com.github.bumptech.glide:glide:4.10.0'
55 |
56 | implementation "io.reactivex.rxjava2:rxjava:$rootProject.ext.rxjava2Version"
57 | implementation "com.squareup.retrofit2:retrofit:$rootProject.ext.retrofit2Version"
58 | implementation "com.squareup.retrofit2:adapter-rxjava2:$rootProject.ext.retrofit2Version"
59 | implementation "com.squareup.retrofit2:converter-gson:$rootProject.ext.retrofit2Version"
60 | // api 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
61 | implementation 'com.squareup.okhttp3:logging-interceptor:3.6.0'
62 | implementation "io.reactivex.rxjava2:rxandroid:$rootProject.ext.rxAndroidVersion"
63 | implementation 'in.srain.cube:ultra-ptr:1.0.11'
64 | implementation 'com.drakeet.multitype:multitype:4.1.1'
65 | debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5'
66 | releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
67 | implementation "com.google.code.gson:gson:$rootProject.ext.gsonVersion"
68 | implementation "com.flyco.systembar:FlycoSystemBar_Lib:1.0.0@aar"
69 | implementation "com.github.0xm1nam0:Common:$rootProject.ext.commonVersion"
70 | // debugApi 'com.github.BolexLiu.AutoEx:AutoEx-Lib:v1.0.8'
71 | // releaseApi 'com.github.BolexLiu.AutoEx:AutoEx-Lib-No-Op:v1.0.8'
72 | }
73 |
74 |
75 | //apply from: 'publish.gradle'
--------------------------------------------------------------------------------
/core/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in F:\SDK\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/core/publish.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'maven-publish'
2 | apply plugin: 'com.jfrog.bintray'
3 |
4 |
5 | // 定义参数
6 | def gitUrl = 'https://github.com/0xm1nam0/RxCore.git' // Git仓库的url
7 | def groupIdDefined = "com.github.weiss"
8 | def artifactIdDefined = "rxcore"
9 | def versionDefined = "1.3.3"
10 |
11 | // bintray平台信息配置
12 | Properties properties = new Properties()
13 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
14 | bintray {
15 | user = properties.getProperty("bintray.user") // local.properties里设置
16 | key = properties.getProperty("bintray.apikey") // local.properties里设置
17 | publications = ['Production']
18 | // configurations = ['archives']
19 | override = true
20 | pkg {
21 | repo = 'maven' // 必填。bintray平台仓库名,必须已经创建过。
22 | description = "RxJava2+Retrofit2 Core"
23 | name = "RxCore" // 必填。仓库里包package的名称,没有的话会自动创建。
24 | licenses = ["Apache-2.0"] // 首次创建package则必须,否则选填。
25 | vcsUrl = gitUrl // 首次创建package则必须,否则选填。
26 | publish = true
27 | publicDownloadNumbers = true
28 | // dryRun = true
29 | version {
30 | name = "$versionDefined"
31 | }
32 | }
33 | }
34 |
35 | publishing {
36 | publications {
37 | Production(MavenPublication) {
38 | artifact("$buildDir/outputs/aar/core-release.aar")
39 | artifact sourcesJar
40 | artifact javadocJar
41 | groupId "$groupIdDefined"
42 | artifactId "$artifactIdDefined"
43 | version "$versionDefined"
44 |
45 | pom.withXml {
46 | def dependenciesNode = asNode().appendNode('dependencies')
47 |
48 | // Iterate over the implementation dependencies (we don't want the test ones), adding a node for each
49 | configurations.implementation.allDependencies.each {
50 | // Ensure dependencies such as fileTree are not included in the pom.
51 | if (it.name != 'unspecified') {
52 | def dependencyNode = dependenciesNode.appendNode('dependency')
53 | dependencyNode.appendNode('groupId', it.group)
54 | dependencyNode.appendNode('artifactId', it.name)
55 | dependencyNode.appendNode('version', it.version)
56 | }
57 | }
58 | }
59 | }
60 | }
61 | }
62 |
63 | // 生成sourceJar和javaDocJar构件
64 | task sourcesJar(type: Jar) {
65 | from android.sourceSets.main.java.srcDirs
66 | classifier = 'sources'
67 | }
68 |
69 | task javadoc(type: Javadoc) {
70 | source = android.sourceSets.main.java.srcDirs
71 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
72 | // destinationDir = file("../javadoc/")
73 | failOnError false
74 | }
75 |
76 | task javadocJar(type: Jar, dependsOn: javadoc) {
77 | classifier = 'javadoc'
78 | from javadoc.destinationDir
79 | }
80 | artifacts {
81 | archives javadocJar
82 | archives sourcesJar
83 | }
84 |
85 | // 执行 ./gradlew clean bintrayUpload
86 |
--------------------------------------------------------------------------------
/core/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
15 |
16 |
21 |
22 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/UserManager.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core;
2 |
3 | import android.text.TextUtils;
4 |
5 | import com.google.gson.Gson;
6 | import com.minamo.utils.LoggerUtils;
7 | import com.minamo.utils.SPUtils;
8 |
9 | /**
10 | * author weiss
11 | * email kleinminamo@gmail.com
12 | * created 2018/1/4.
13 | */
14 |
15 | public class UserManager {
16 | private static final String TAG = "UserManager";
17 | public static String FILE = "user_info";
18 | public static String KEY = "user_message";
19 | public static String KEY_TOKEN = "user_token";
20 | public static String IS_LOGIN = "user_is_login";
21 | private T mModel;
22 |
23 | public UserManager(Class tClass) {
24 | String user_message = SPUtils.getString(FILE, KEY);
25 | if(!TextUtils.isEmpty(user_message)) {
26 | this.mModel = (new Gson()).fromJson(user_message, tClass);
27 | }
28 |
29 | }
30 |
31 | public boolean isLogin() {
32 | return SPUtils.getBoolean(FILE, IS_LOGIN);
33 | }
34 |
35 | public T getUserModel() {
36 | return this.mModel;
37 | }
38 |
39 | public void login(T t) {
40 | if(t == null) {
41 | LoggerUtils.e("UserManager", "Login Model is Null");
42 | } else if(SPUtils.getBoolean(FILE, IS_LOGIN)) {
43 | LoggerUtils.e("UserManager", "Can't Login Again");
44 | } else {
45 | this.mModel = t;
46 | String user_message = (new Gson()).toJson(t);
47 | SPUtils.put(FILE, KEY, user_message);
48 | SPUtils.put(FILE, IS_LOGIN, true);
49 | }
50 | }
51 |
52 | public void logout() {
53 | SPUtils.put(FILE, IS_LOGIN, false);
54 | }
55 |
56 | public String getToken() {
57 | return SPUtils.getString(FILE, KEY_TOKEN);
58 | }
59 |
60 | public void setToken(String token) {
61 | SPUtils.put(FILE, KEY_TOKEN, token);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/api/NobodyConverterFactory.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.api;
2 |
3 | import com.github.weiss.core.entity.NoBodyEntity;
4 |
5 | import java.io.IOException;
6 | import java.lang.annotation.Annotation;
7 | import java.lang.reflect.Type;
8 |
9 | import okhttp3.RequestBody;
10 | import okhttp3.ResponseBody;
11 | import retrofit2.Converter;
12 | import retrofit2.Retrofit;
13 |
14 | /**
15 | * 代替gson converter转换无响应体的response
16 | */
17 | public class NobodyConverterFactory extends Converter.Factory {
18 |
19 | public static final NobodyConverterFactory create() {
20 | return new NobodyConverterFactory();
21 | }
22 |
23 | private NobodyConverterFactory() {
24 | }
25 |
26 | //将响应对象responseBody转成目标类型对象(也就是Call里给定的类型)
27 | @Override
28 | public Converter responseBodyConverter(Type type, Annotation[] annotations,
29 | Retrofit retrofit) {
30 | //判断当前的类型是否是我们需要处理的类型
31 | if (NoBodyEntity.class.equals(type)) {
32 | //是则创建一个Converter返回转换数据
33 | return new Converter() {
34 | @Override
35 | public NoBodyEntity convert(ResponseBody value) throws IOException {
36 | //这里直接返回null是因为我们不需要使用到响应体,本来也没有响应体.
37 | //返回的对象会存到response.body()里.
38 | return null;
39 | }
40 | };
41 | }
42 | return null;
43 | }
44 |
45 | //其它两个方法我们不需要使用到.所以不需要重写.
46 | @Override
47 | public Converter, RequestBody> requestBodyConverter(Type type,
48 | Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
49 | return null;
50 | }
51 |
52 | @Override
53 | public Converter, String> stringConverter(Type type, Annotation[] annotations,
54 | Retrofit retrofit) {
55 | return null;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/api/NullableResult.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.api;
2 |
3 | import androidx.annotation.Nullable;
4 |
5 | import java.util.NoSuchElementException;
6 |
7 | public class NullableResult {
8 |
9 | private final T nullableResult; // 返回结果
10 | public NullableResult(@Nullable T nullableResult) {
11 | this.nullableResult = nullableResult;
12 | }
13 |
14 | public boolean isEmpty() {
15 | return this.nullableResult == null;
16 | }
17 |
18 | // 获取不能为null的返回结果,如果为null,直接抛异常,这个异常最终可以在走向RxJava的onError()
19 | public T get() {
20 | if (nullableResult == null) {
21 | throw new NoSuchElementException("No value present");
22 | }
23 | return nullableResult;
24 | }
25 |
26 | // 获取可以为null的返回结果
27 | public T getNullable() {
28 | return nullableResult;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/api/ProgressRequestBody.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.api;
2 |
3 | import android.os.Handler;
4 | import android.os.Looper;
5 |
6 | import java.io.File;
7 | import java.io.FileInputStream;
8 | import java.io.IOException;
9 |
10 | import okhttp3.MediaType;
11 | import okhttp3.RequestBody;
12 | import okio.BufferedSink;
13 |
14 | // Content-Type(Mime-Type) 对照表 http://tool.oschina.net/commons/
15 | public class ProgressRequestBody extends RequestBody {
16 | private File mFile;
17 | private String mPath;
18 | private String mMediaType;
19 | private UploadCallbacks mListener;
20 |
21 | private int mEachBufferSize = 1024;
22 |
23 | public interface UploadCallbacks {
24 | void onProgressUpdate(int percentage);
25 |
26 | void onError();
27 |
28 | void onFinish();
29 | }
30 |
31 | public ProgressRequestBody(final File file, String mediaType, final UploadCallbacks listener) {
32 | mFile = file;
33 | mMediaType = mediaType;
34 | mListener = listener;
35 | }
36 |
37 | public ProgressRequestBody(final File file, String mediaType, int eachBufferSize, final UploadCallbacks listener) {
38 | mFile = file;
39 | mMediaType = mediaType;
40 | mEachBufferSize = eachBufferSize;
41 | mListener = listener;
42 | }
43 |
44 | @Override
45 | public MediaType contentType() {
46 | // i want to upload only images
47 | return MediaType.parse(mMediaType);
48 | }
49 |
50 | @Override
51 | public void writeTo(BufferedSink sink) throws IOException {
52 | long fileLength = mFile.length();
53 | byte[] buffer = new byte[mEachBufferSize];
54 | FileInputStream in = new FileInputStream(mFile);
55 | long uploaded = 0;
56 |
57 | try {
58 | int read;
59 | Handler handler = new Handler(Looper.getMainLooper());
60 | while ((read = in.read(buffer)) != -1) {
61 | // update progress on UI thread
62 | handler.post(new ProgressUpdater(uploaded, fileLength));
63 | uploaded += read;
64 | sink.write(buffer, 0, read);
65 |
66 | }
67 | } finally {
68 | in.close();
69 | }
70 | }
71 |
72 | private class ProgressUpdater implements Runnable {
73 | private long mUploaded;
74 | private long mTotal;
75 |
76 | public ProgressUpdater(long uploaded, long total) {
77 | mUploaded = uploaded;
78 | mTotal = total;
79 | }
80 |
81 | @Override
82 | public void run() {
83 | mListener.onProgressUpdate((int) (100 * mUploaded / mTotal));
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/api/RetryIntercepter.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.api;
2 |
3 |
4 | import com.minamo.utils.LoggerUtils;
5 |
6 | import java.io.IOException;
7 |
8 | import okhttp3.Interceptor;
9 | import okhttp3.Request;
10 | import okhttp3.Response;
11 |
12 | public class RetryIntercepter implements Interceptor {
13 |
14 | public int maxRetry;//最大重试次数
15 | private int retryNum = 0;//假如设置为3次重试的话,则最大可能请求4次(默认1次+3次重试)
16 |
17 | public RetryIntercepter(int maxRetry) {
18 | this.maxRetry = maxRetry;
19 | }
20 |
21 | @Override
22 | public Response intercept(Chain chain) throws IOException {
23 | Request request = chain.request();
24 | LoggerUtils.d("retryNum=" + retryNum);
25 | Response response = chain.proceed(request);
26 | while (!response.isSuccessful() && retryNum < maxRetry) {
27 | retryNum++;
28 | LoggerUtils.d("retryNum=" + retryNum);
29 | response = chain.proceed(request);
30 | }
31 | return response;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/api/cookie/CookieJarImpl.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.api.cookie;
2 |
3 |
4 | import com.github.weiss.core.api.cookie.store.CookieStore;
5 |
6 | import java.util.List;
7 |
8 | import okhttp3.Cookie;
9 | import okhttp3.CookieJar;
10 | import okhttp3.HttpUrl;
11 |
12 | /**
13 | * Created by goldze on 2017/5/13.
14 | */
15 | public class CookieJarImpl implements CookieJar {
16 |
17 | private CookieStore cookieStore;
18 |
19 | public CookieJarImpl(CookieStore cookieStore) {
20 | if (cookieStore == null) {
21 | throw new IllegalArgumentException("cookieStore can not be null!");
22 | }
23 | this.cookieStore = cookieStore;
24 | }
25 |
26 | @Override
27 | public synchronized void saveFromResponse(HttpUrl url, List cookies) {
28 | cookieStore.saveCookie(url, cookies);
29 | }
30 |
31 | @Override
32 | public synchronized List loadForRequest(HttpUrl url) {
33 | return cookieStore.loadCookie(url);
34 | }
35 |
36 | public CookieStore getCookieStore() {
37 | return cookieStore;
38 | }
39 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/api/cookie/store/CookieStore.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.api.cookie.store;
2 |
3 | import java.util.List;
4 |
5 | import okhttp3.Cookie;
6 | import okhttp3.HttpUrl;
7 |
8 | /**
9 | * Created by goldze on 2017/5/13.
10 | */
11 | public interface CookieStore {
12 |
13 | /** 保存url对应所有cookie */
14 | void saveCookie(HttpUrl url, List cookie);
15 |
16 | /** 保存url对应所有cookie */
17 | void saveCookie(HttpUrl url, Cookie cookie);
18 |
19 | /** 加载url所有的cookie */
20 | List loadCookie(HttpUrl url);
21 |
22 | /** 获取当前所有保存的cookie */
23 | List getAllCookie();
24 |
25 | /** 获取当前url对应的所有的cookie */
26 | List getCookie(HttpUrl url);
27 |
28 | /** 根据url和cookie移除对应的cookie */
29 | boolean removeCookie(HttpUrl url, Cookie cookie);
30 |
31 | /** 根据url移除所有的cookie */
32 | boolean removeCookie(HttpUrl url);
33 |
34 | /** 移除所有的cookie */
35 | boolean removeAllCookie();
36 | }
37 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/api/cookie/store/MemoryCookieStore.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.api.cookie.store;
2 |
3 | import java.util.ArrayList;
4 | import java.util.HashMap;
5 | import java.util.List;
6 | import java.util.Set;
7 |
8 | import okhttp3.Cookie;
9 | import okhttp3.HttpUrl;
10 |
11 | /**
12 | * Created by goldze on 2017/5/13.
13 | */
14 | public class MemoryCookieStore implements CookieStore {
15 |
16 | private final HashMap> memoryCookies = new HashMap<>();
17 |
18 | @Override
19 | public synchronized void saveCookie(HttpUrl url, List cookies) {
20 | List oldCookies = memoryCookies.get(url.host());
21 | List needRemove = new ArrayList<>();
22 | for (Cookie newCookie : cookies) {
23 | for (Cookie oldCookie : oldCookies) {
24 | if (newCookie.name().equals(oldCookie.name())) {
25 | needRemove.add(oldCookie);
26 | }
27 | }
28 | }
29 | oldCookies.removeAll(needRemove);
30 | oldCookies.addAll(cookies);
31 | }
32 |
33 | @Override
34 | public synchronized void saveCookie(HttpUrl url, Cookie cookie) {
35 | List cookies = memoryCookies.get(url.host());
36 | List needRemove = new ArrayList<>();
37 | for (Cookie item : cookies) {
38 | if (cookie.name().equals(item.name())) {
39 | needRemove.add(item);
40 | }
41 | }
42 | cookies.removeAll(needRemove);
43 | cookies.add(cookie);
44 | }
45 |
46 | @Override
47 | public synchronized List loadCookie(HttpUrl url) {
48 | List cookies = memoryCookies.get(url.host());
49 | if (cookies == null) {
50 | cookies = new ArrayList<>();
51 | memoryCookies.put(url.host(), cookies);
52 | }
53 | return cookies;
54 | }
55 |
56 | @Override
57 | public synchronized List getAllCookie() {
58 | List cookies = new ArrayList<>();
59 | Set httpUrls = memoryCookies.keySet();
60 | for (String url : httpUrls) {
61 | cookies.addAll(memoryCookies.get(url));
62 | }
63 | return cookies;
64 | }
65 |
66 | @Override
67 | public List getCookie(HttpUrl url) {
68 | List cookies = new ArrayList<>();
69 | List urlCookies = memoryCookies.get(url.host());
70 | if (urlCookies != null) cookies.addAll(urlCookies);
71 | return cookies;
72 | }
73 |
74 | @Override
75 | public synchronized boolean removeCookie(HttpUrl url, Cookie cookie) {
76 | List cookies = memoryCookies.get(url.host());
77 | return (cookie != null) && cookies.remove(cookie);
78 | }
79 |
80 | @Override
81 | public synchronized boolean removeCookie(HttpUrl url) {
82 | return memoryCookies.remove(url.host()) != null;
83 | }
84 |
85 | @Override
86 | public synchronized boolean removeAllCookie() {
87 | memoryCookies.clear();
88 | return true;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/api/cookie/store/SerializableHttpCookie.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.api.cookie.store;
2 |
3 | import java.io.IOException;
4 | import java.io.ObjectInputStream;
5 | import java.io.ObjectOutputStream;
6 | import java.io.Serializable;
7 |
8 | import okhttp3.Cookie;
9 |
10 | public class SerializableHttpCookie implements Serializable {
11 | private static final long serialVersionUID = 6374381323722046732L;
12 |
13 | private transient final Cookie cookie;
14 | private transient Cookie clientCookie;
15 |
16 | public SerializableHttpCookie(Cookie cookie) {
17 | this.cookie = cookie;
18 | }
19 |
20 | public Cookie getCookie() {
21 | Cookie bestCookie = cookie;
22 | if (clientCookie != null) {
23 | bestCookie = clientCookie;
24 | }
25 | return bestCookie;
26 | }
27 |
28 | private void writeObject(ObjectOutputStream out) throws IOException {
29 | out.writeObject(cookie.name());
30 | out.writeObject(cookie.value());
31 | out.writeLong(cookie.expiresAt());
32 | out.writeObject(cookie.domain());
33 | out.writeObject(cookie.path());
34 | out.writeBoolean(cookie.secure());
35 | out.writeBoolean(cookie.httpOnly());
36 | out.writeBoolean(cookie.hostOnly());
37 | out.writeBoolean(cookie.persistent());
38 | }
39 |
40 | private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
41 | String name = (String) in.readObject();
42 | String value = (String) in.readObject();
43 | long expiresAt = in.readLong();
44 | String domain = (String) in.readObject();
45 | String path = (String) in.readObject();
46 | boolean secure = in.readBoolean();
47 | boolean httpOnly = in.readBoolean();
48 | boolean hostOnly = in.readBoolean();
49 | boolean persistent = in.readBoolean();
50 | Cookie.Builder builder = new Cookie.Builder();
51 | builder = builder.name(name);
52 | builder = builder.value(value);
53 | builder = builder.expiresAt(expiresAt);
54 | builder = hostOnly ? builder.hostOnlyDomain(domain) : builder.domain(domain);
55 | builder = builder.path(path);
56 | builder = secure ? builder.secure() : builder;
57 | builder = httpOnly ? builder.httpOnly() : builder;
58 | clientCookie = builder.build();
59 | }
60 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/api/download/DownLoadStateBean.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.api.download;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import java.io.Serializable;
7 |
8 | /**
9 | * Created by goldze on 2017/5/11.
10 | */
11 |
12 | public class DownLoadStateBean implements Serializable, Parcelable {
13 | long total; // 文件总大小
14 | long bytesLoaded; //已加载文件的大小
15 | String tag; // 多任务下载时的一个标记
16 |
17 | public DownLoadStateBean(long total, long bytesLoaded) {
18 | this.total = total;
19 | this.bytesLoaded = bytesLoaded;
20 | }
21 |
22 | public DownLoadStateBean(long total, long bytesLoaded, String tag) {
23 | this.total = total;
24 | this.bytesLoaded = bytesLoaded;
25 | this.tag = tag;
26 | }
27 |
28 | public long getTotal() {
29 | return total;
30 | }
31 |
32 | public void setTotal(long total) {
33 | this.total = total;
34 | }
35 |
36 | public long getBytesLoaded() {
37 | return bytesLoaded;
38 | }
39 |
40 | public void setBytesLoaded(long bytesLoaded) {
41 | this.bytesLoaded = bytesLoaded;
42 | }
43 |
44 | public String getTag() {
45 | return tag;
46 | }
47 |
48 | public void setTag(String tag) {
49 | this.tag = tag;
50 | }
51 |
52 | @Override
53 | public int describeContents() {
54 | return 0;
55 | }
56 |
57 | @Override
58 | public void writeToParcel(Parcel dest, int flags) {
59 | dest.writeLong(this.total);
60 | dest.writeLong(this.bytesLoaded);
61 | dest.writeString(this.tag);
62 | }
63 |
64 | protected DownLoadStateBean(Parcel in) {
65 | this.total = in.readLong();
66 | this.bytesLoaded = in.readLong();
67 | this.tag = in.readString();
68 | }
69 |
70 | public static final Creator CREATOR = new Creator() {
71 | @Override
72 | public DownLoadStateBean createFromParcel(Parcel source) {
73 | return new DownLoadStateBean(source);
74 | }
75 |
76 | @Override
77 | public DownLoadStateBean[] newArray(int size) {
78 | return new DownLoadStateBean[size];
79 | }
80 | };
81 | }
82 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/api/download/DownLoadSubscriber.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.api.download;
2 |
3 | import io.reactivex.observers.DisposableObserver;
4 |
5 | /**
6 | * Created by goldze on 2017/5/11.
7 | */
8 |
9 | public class DownLoadSubscriber extends DisposableObserver {
10 | private ProgressCallBack fileCallBack;
11 |
12 | public DownLoadSubscriber(ProgressCallBack fileCallBack) {
13 | this.fileCallBack = fileCallBack;
14 | }
15 |
16 | @Override
17 | public void onStart() {
18 | super.onStart();
19 | if (fileCallBack != null)
20 | fileCallBack.onStart();
21 | }
22 |
23 | @Override
24 | public void onComplete() {
25 | if (fileCallBack != null)
26 | fileCallBack.onCompleted();
27 | }
28 |
29 | @Override
30 | public void onError(Throwable e) {
31 | if (fileCallBack != null)
32 | fileCallBack.onError(e);
33 | }
34 |
35 | @Override
36 | public void onNext(T t) {
37 | if (fileCallBack != null)
38 | fileCallBack.onSuccess(t);
39 | }
40 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/api/download/ProgressCallBack.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.api.download;
2 |
3 | import android.util.Log;
4 |
5 | import com.github.weiss.core.bus.RxBus;
6 | import com.github.weiss.core.bus.RxSubscriptions;
7 |
8 | import java.io.File;
9 | import java.io.FileNotFoundException;
10 | import java.io.FileOutputStream;
11 | import java.io.IOException;
12 | import java.io.InputStream;
13 |
14 | import io.reactivex.android.schedulers.AndroidSchedulers;
15 | import io.reactivex.disposables.Disposable;
16 | import io.reactivex.functions.Consumer;
17 | import okhttp3.ResponseBody;
18 |
19 | /**
20 | * Created by goldze on 2017/9/26 0026.
21 | */
22 |
23 | public abstract class ProgressCallBack {
24 |
25 | private String destFileDir; // 本地文件存放路径
26 | private String destFileName; // 文件名
27 | private Disposable mSubscription;
28 |
29 | public ProgressCallBack(String destFileDir, String destFileName) {
30 | this.destFileDir = destFileDir;
31 | this.destFileName = destFileName;
32 | subscribeLoadProgress();
33 | }
34 |
35 | public abstract void onSuccess(T t);
36 |
37 | public abstract void progress(long progress, long total);
38 |
39 | public void onStart() {
40 | }
41 |
42 | public void onCompleted() {
43 | }
44 |
45 | public abstract void onError(Throwable e);
46 |
47 | public void saveFile(ResponseBody body) {
48 | InputStream is = null;
49 | byte[] buf = new byte[2048];
50 | int len;
51 | FileOutputStream fos = null;
52 | try {
53 | is = body.byteStream();
54 | File dir = new File(destFileDir);
55 | if (!dir.exists()) {
56 | dir.mkdirs();
57 | }
58 | File file = new File(dir, destFileName);
59 | fos = new FileOutputStream(file);
60 | while ((len = is.read(buf)) != -1) {
61 | fos.write(buf, 0, len);
62 | }
63 | fos.flush();
64 | unsubscribe();
65 | //onCompleted();
66 | } catch (FileNotFoundException e) {
67 | e.printStackTrace();
68 | } catch (IOException e) {
69 | e.printStackTrace();
70 | } finally {
71 | try {
72 | if (is != null) is.close();
73 | if (fos != null) fos.close();
74 | } catch (IOException e) {
75 | Log.e("saveFile", e.getMessage());
76 | }
77 | }
78 | }
79 |
80 | /**
81 | * 订阅加载的进度条
82 | */
83 | public void subscribeLoadProgress() {
84 | mSubscription = RxBus.getDefault().toObservable(DownLoadStateBean.class)
85 | .observeOn(AndroidSchedulers.mainThread()) //回调到主线程更新UI
86 | .subscribe(new Consumer() {
87 | @Override
88 | public void accept(final DownLoadStateBean progressLoadBean) throws Exception {
89 | progress(progressLoadBean.getBytesLoaded(), progressLoadBean.getTotal());
90 | }
91 | });
92 | //将订阅者加入管理站
93 | RxSubscriptions.add(mSubscription);
94 | }
95 |
96 | /**
97 | * 取消订阅,防止内存泄漏
98 | */
99 | public void unsubscribe() {
100 | RxSubscriptions.remove(mSubscription);
101 | }
102 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/api/download/ProgressResponseBody.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.api.download;
2 |
3 | import com.github.weiss.core.bus.RxBus;
4 |
5 | import java.io.IOException;
6 | import okhttp3.MediaType;
7 | import okhttp3.ResponseBody;
8 | import okio.Buffer;
9 | import okio.BufferedSource;
10 | import okio.ForwardingSource;
11 | import okio.Okio;
12 | import okio.Source;
13 |
14 | /**
15 | * Created by goldze on 2017/5/11.
16 | */
17 |
18 | public class ProgressResponseBody extends ResponseBody {
19 | private ResponseBody responseBody;
20 |
21 | private BufferedSource bufferedSource;
22 | private String tag;
23 |
24 | public ProgressResponseBody(ResponseBody responseBody) {
25 | this.responseBody = responseBody;
26 | }
27 |
28 | public ProgressResponseBody(ResponseBody responseBody, String tag) {
29 | this.responseBody = responseBody;
30 | this.tag = tag;
31 | }
32 |
33 | @Override
34 | public MediaType contentType() {
35 | return responseBody.contentType();
36 | }
37 |
38 | @Override
39 | public long contentLength() {
40 | return responseBody.contentLength();
41 | }
42 |
43 | @Override
44 | public BufferedSource source() {
45 | if (bufferedSource == null) {
46 | bufferedSource = Okio.buffer(source(responseBody.source()));
47 | }
48 | return bufferedSource;
49 | }
50 |
51 | private Source source(Source source) {
52 | return new ForwardingSource(source) {
53 | long bytesReaded = 0;
54 |
55 | @Override
56 | public long read(Buffer sink, long byteCount) throws IOException {
57 | long bytesRead = super.read(sink, byteCount);
58 | bytesReaded += bytesRead == -1 ? 0 : bytesRead;
59 | //使用RxBus的方式,实时发送当前已读取(上传/下载)的字节数据
60 | RxBus.getDefault().post(new DownLoadStateBean(contentLength(), bytesReaded, tag));
61 | return bytesRead;
62 | }
63 | };
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/api/interceptor/BaseInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.api.interceptor;
2 |
3 | import java.io.IOException;
4 | import java.util.Map;
5 | import java.util.Set;
6 |
7 | import okhttp3.Interceptor;
8 | import okhttp3.Request;
9 | import okhttp3.Response;
10 |
11 | /**
12 | * Created by goldze on 2017/5/10.
13 | */
14 | public class BaseInterceptor implements Interceptor {
15 | private Map headers;
16 |
17 | public BaseInterceptor(Map headers) {
18 | this.headers = headers;
19 | }
20 |
21 | @Override
22 | public Response intercept(Chain chain) throws IOException {
23 | Request.Builder builder = chain.request()
24 | .newBuilder();
25 | if (headers != null && headers.size() > 0) {
26 | Set keys = headers.keySet();
27 | for (String headerKey : keys) {
28 | builder.addHeader(headerKey, headers.get(headerKey)).build();
29 | }
30 | }
31 | //请求信息
32 | return chain.proceed(builder.build());
33 | }
34 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/api/interceptor/CacheInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.api.interceptor;
2 |
3 | import android.content.Context;
4 |
5 |
6 | import com.blankj.utilcode.util.NetworkUtils;
7 |
8 | import java.io.IOException;
9 |
10 | import okhttp3.CacheControl;
11 | import okhttp3.Interceptor;
12 | import okhttp3.Request;
13 | import okhttp3.Response;
14 |
15 | /**
16 | * Created by goldze on 2017/5/10.
17 | * 无网络状态下智能读取缓存的拦截器
18 | */
19 | public class CacheInterceptor implements Interceptor {
20 |
21 | private Context context;
22 |
23 | public CacheInterceptor(Context context) {
24 | this.context = context;
25 | }
26 |
27 | @Override
28 | public Response intercept(Chain chain) throws IOException {
29 | Request request = chain.request();
30 | if (NetworkUtils.isConnected()) {
31 | Response response = chain.proceed(request);
32 | // read from cache for 60 s
33 | int maxAge = 60;
34 | return response.newBuilder()
35 | .removeHeader("Pragma")
36 | .removeHeader("Cache-Control")
37 | .header("Cache-Control", "public, max-age=" + maxAge)
38 | .build();
39 | } else {
40 | //读取缓存信息
41 | request = request.newBuilder()
42 | .cacheControl(CacheControl.FORCE_CACHE)
43 | .build();
44 | Response response = chain.proceed(request);
45 | //set cache times is 3 days
46 | int maxStale = 60 * 60 * 24 * 3;
47 | return response.newBuilder()
48 | .removeHeader("Pragma")
49 | .removeHeader("Cache-Control")
50 | .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
51 | .build();
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/api/interceptor/ProgressInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.api.interceptor;
2 |
3 | import com.github.weiss.core.api.download.ProgressResponseBody;
4 |
5 | import java.io.IOException;
6 |
7 | import okhttp3.Interceptor;
8 | import okhttp3.Response;
9 |
10 | /**
11 | * Created by goldze on 2017/5/10.
12 | */
13 |
14 | public class ProgressInterceptor implements Interceptor {
15 |
16 | @Override
17 | public Response intercept(Chain chain) throws IOException {
18 | Response originalResponse = chain.proceed(chain.request());
19 | return originalResponse.newBuilder()
20 | .body(new ProgressResponseBody(originalResponse.body()))
21 | .build();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/api/interceptor/logging/I.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.api.interceptor.logging;
2 |
3 |
4 | import java.util.logging.Level;
5 |
6 | import okhttp3.internal.platform.Platform;
7 |
8 | /**
9 | * @author ihsan on 10/02/2017.
10 | */
11 | class I {
12 |
13 | protected I() {
14 | throw new UnsupportedOperationException();
15 | }
16 |
17 | static void log(int type, String tag, String msg) {
18 | java.util.logging.Logger logger = java.util.logging.Logger.getLogger(tag);
19 | switch (type) {
20 | case Platform.INFO:
21 | logger.log(Level.INFO, msg);
22 | break;
23 | default:
24 | logger.log(Level.WARNING, msg);
25 | break;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/api/interceptor/logging/Level.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.api.interceptor.logging;
2 |
3 | /**
4 | * @author ihsan on 21/02/2017.
5 | */
6 |
7 | public enum Level {
8 | /**
9 | * No logs.
10 | */
11 | NONE,
12 | /**
13 | * Example:
14 | *
{@code
15 | * - URL
16 | * - Method
17 | * - Headers
18 | * - Body
19 | * }
20 | */
21 | BASIC,
22 | /**
23 | * Example:
24 | *
{@code
25 | * - URL
26 | * - Method
27 | * - Headers
28 | * }
29 | */
30 | HEADERS,
31 | /**
32 | * Example:
33 | *
{@code
34 | * - URL
35 | * - Method
36 | * - Body
37 | * }
38 | */
39 | BODY
40 | }
41 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/api/interceptor/logging/Logger.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.api.interceptor.logging;
2 |
3 | import okhttp3.internal.platform.Platform;
4 |
5 | /**
6 | * @author ihsan on 11/07/2017.
7 | */
8 | @SuppressWarnings({"WeakerAccess", "unused"})
9 | public interface Logger {
10 | void log(int level, String tag, String msg);
11 |
12 | Logger DEFAULT = new Logger() {
13 | @Override
14 | public void log(int level, String tag, String message) {
15 | Platform.get().log(level, message, null);
16 | }
17 | };
18 | }
19 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/base/BackHandledFragment.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.base;
2 |
3 | import androidx.viewpager.widget.ViewPager;
4 |
5 | import com.github.weiss.core.utils.helper.BackHandlerHelper;
6 | import com.github.weiss.core.utils.helper.FragmentBackHandler;
7 |
8 | public abstract class BackHandledFragment extends BaseRxFragment implements FragmentBackHandler {
9 |
10 | public BackHandledFragment() {
11 | }
12 |
13 | @Override
14 | public final boolean onBackPressed() {
15 | return interceptBackPressed()
16 | || (getBackHandleViewPager() == null
17 | ? BackHandlerHelper.handleBackPress(this)
18 | : BackHandlerHelper.handleBackPress(getBackHandleViewPager()));
19 | }
20 |
21 | public boolean interceptBackPressed() {
22 | return false;
23 | }
24 |
25 | /**
26 | * 2.1 版本已经不在需要单独对ViewPager处理
27 | *
28 | * @deprecated
29 | */
30 | @Deprecated
31 | public ViewPager getBackHandleViewPager() {
32 | return null;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/base/BaseApp.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.base;
2 |
3 | import android.app.Activity;
4 | import android.app.Application;
5 | import android.content.Context;
6 | import android.content.res.Resources;
7 | import android.os.Bundle;
8 |
9 | import com.blankj.utilcode.util.CrashUtils;
10 | import com.blankj.utilcode.util.Utils;
11 | import com.minamo.utils.SPUtils;
12 |
13 | /**
14 | * Created by Weiss on 2017/1/10.
15 | */
16 |
17 | public class BaseApp extends Application {
18 |
19 | private static BaseApp app;
20 |
21 | public static Context getAppContext() {
22 | return app;
23 | }
24 |
25 | public static Resources getAppResources() {
26 | return app.getResources();
27 | }
28 |
29 | @Override
30 | public void onCreate() {
31 | super.onCreate();
32 | app = this;
33 | SPUtils.init(this);
34 | Utils.init(this);
35 | CrashUtils.init();
36 | // AutoEx.apply();
37 | // LogUtils2.getBuilder().setTag("MyTag").setLog2FileSwitch(true).create();
38 |
39 | //注册监听每个activity的生命周期,便于堆栈式管理
40 | registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
41 |
42 | @Override
43 | public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
44 | AppManager.getAppManager().addActivity(activity);
45 | }
46 |
47 | @Override
48 | public void onActivityStarted(Activity activity) {
49 | }
50 |
51 | @Override
52 | public void onActivityResumed(Activity activity) {
53 | }
54 |
55 | @Override
56 | public void onActivityPaused(Activity activity) {
57 | }
58 |
59 | @Override
60 | public void onActivityStopped(Activity activity) {
61 | }
62 |
63 | @Override
64 | public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
65 | }
66 |
67 | @Override
68 | public void onActivityDestroyed(Activity activity) {
69 | AppManager.getAppManager().removeActivity(activity);
70 | }
71 | });
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/base/BaseCoreActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.base;
2 |
3 | import android.app.ProgressDialog;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import androidx.appcompat.app.AppCompatActivity;
7 | import android.view.View;
8 | import android.view.Window;
9 | import android.view.WindowManager;
10 |
11 |
12 | import com.blankj.utilcode.util.ToastUtils;
13 |
14 | import butterknife.ButterKnife;
15 |
16 | /**
17 | * Created by Weiss on 2017/1/10.
18 | */
19 |
20 | public abstract class BaseCoreActivity extends AppCompatActivity implements View.OnClickListener {
21 | protected ProgressDialog progressDialog;
22 |
23 | @Override
24 | protected void onCreate(Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | // if(savedInstanceState!=null){
27 | // String name=savedInstanceState.getString("recover");
28 | // }
29 | //隐藏标题栏以及状态栏
30 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
31 | WindowManager.LayoutParams.FLAG_FULLSCREEN);
32 | // *标题是属于View的,所以窗口所有的修饰部分被隐藏后标题依然有效,需要去掉标题*
33 | requestWindowFeature(Window.FEATURE_NO_TITLE);
34 | if (getLayoutId() > 0) {
35 | setContentView(this.getLayoutId());
36 | }
37 | // SystemBarHelper.immersiveStatusBar(this);
38 | ButterKnife.bind(this);
39 | this.preInit(this.getIntent());
40 | progressDialog = new ProgressDialog(this);
41 | progressDialog.setCancelable(false);
42 | progressDialog.setCanceledOnTouchOutside(false);
43 | initView();
44 | initData();
45 | /* if(!handleLogin()) {
46 | }*/
47 | }
48 |
49 | //是否登录
50 | protected boolean needLogin() {
51 | return false;
52 | }
53 |
54 | public void showToast(String msg) {
55 | ToastUtils.showShort(msg);
56 | }
57 |
58 | public void showProgress(String msg) {
59 | if(isFinishing()) return;
60 | progressDialog.setMessage(msg);
61 | progressDialog.show();
62 | }
63 |
64 | public void dismissProgress() {
65 | if (progressDialog != null && progressDialog.isShowing()) {
66 | progressDialog.dismiss();
67 | }
68 | }
69 |
70 | @Override
71 | public void onBackPressed() {
72 | if (progressDialog.isShowing()) {
73 | progressDialog.dismiss();
74 | } else {
75 | super.onBackPressed();
76 | }
77 |
78 | }
79 |
80 | protected abstract int getLayoutId();
81 |
82 | protected abstract void initView();
83 |
84 | protected void preInit(Intent intent) {
85 |
86 | }
87 |
88 | protected void initData() {
89 |
90 | }
91 |
92 | @Override
93 | public void onClick(View v) {
94 |
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/base/BaseFragment.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.base;
2 |
3 | import android.os.Bundle;
4 | import androidx.annotation.IdRes;
5 | import androidx.annotation.Nullable;
6 | import androidx.fragment.app.Fragment;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 | import butterknife.ButterKnife;
12 |
13 | /**
14 | * Created by Weiss on 2017/1/10.
15 | */
16 |
17 | public abstract class BaseFragment extends Fragment implements View.OnClickListener {
18 | public View rootView;
19 | public LayoutInflater inflater;
20 |
21 | @Nullable
22 | @Override
23 | public final View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
24 | super.onCreateView(inflater, container, savedInstanceState);
25 | this.inflater = inflater;
26 | if (rootView == null) {
27 | rootView = inflater.inflate(this.getLayoutId(), container, false);
28 | ButterKnife.bind(this, rootView);
29 | parseArguments(getArguments());
30 | initView();
31 | initData();
32 | }
33 | ViewGroup parent = (ViewGroup) rootView.getParent();
34 | if (parent != null) {
35 | parent.removeView(rootView);
36 | }
37 | return rootView;
38 | }
39 |
40 | public View findViewById(@IdRes int id) {
41 | return rootView.findViewById(id);
42 | }
43 |
44 | @Override
45 | public void onClick(View v) {
46 |
47 | }
48 |
49 | protected void parseArguments(Bundle bundle) {
50 |
51 | }
52 |
53 | protected void initData() {
54 |
55 | }
56 |
57 | protected abstract int getLayoutId();
58 |
59 | protected abstract void initView();
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/base/BaseLazyFragment.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.base;
2 |
3 |
4 | /**
5 | * Fragment 延迟加载
6 | */
7 | public abstract class BaseLazyFragment extends BaseRxFragment {
8 |
9 | /**
10 | * Fragment当前状态是否可见
11 | */
12 | protected boolean isVisible;
13 |
14 | @Override
15 | public void setUserVisibleHint(boolean isVisibleToUser) {
16 | super.setUserVisibleHint(isVisibleToUser);
17 |
18 | if (getUserVisibleHint()) {
19 | isVisible = true;
20 | onVisible();
21 | } else {
22 | isVisible = false;
23 | onInvisible();
24 | }
25 | }
26 |
27 | /**
28 | * 可见
29 | */
30 | protected void onVisible() {
31 | lazyLoad();
32 | }
33 |
34 | /**
35 | * 不可见
36 | */
37 | protected void onInvisible() {
38 |
39 | }
40 |
41 | /**
42 | * 延迟加载 子类必须重写此方法
43 | */
44 | protected abstract void lazyLoad();
45 | }
46 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/base/BaseRxActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.base;
2 |
3 | import android.os.Bundle;
4 |
5 | import com.blankj.utilcode.util.ToastUtils;
6 | import com.github.weiss.core.api.NullableResult;
7 | import com.github.weiss.core.entity.BaseHttpResult;
8 |
9 | import io.reactivex.Observable;
10 | import io.reactivex.ObservableSource;
11 | import io.reactivex.ObservableTransformer;
12 | import io.reactivex.disposables.CompositeDisposable;
13 | import io.reactivex.disposables.Disposable;
14 | import io.reactivex.functions.Function;
15 |
16 | /**
17 | * 管理RxJava生命周期,避免内存泄漏
18 | * RxJava处理服务器返回
19 | *
20 | * Created by Weiss on 2016/12/23.
21 | */
22 |
23 | public abstract class BaseRxActivity extends BaseCoreActivity {
24 |
25 | protected CompositeDisposable disposables2Stop;// 管理Stop取消订阅者者
26 | protected CompositeDisposable disposables2Destroy;// 管理Destroy取消订阅者者
27 |
28 | protected abstract int getLayoutId();
29 |
30 | protected abstract void initView();
31 |
32 | protected abstract boolean needHandleResult(BaseHttpResult result);
33 |
34 | /**
35 | * Rx优雅处理服务器返回
36 | *
37 | * @param
38 | * @return
39 | */
40 | public ObservableTransformer, NullableResult> handleResult() {
41 | return upstream -> upstream
42 | .flatMap((Function, ObservableSource>>) result -> {
43 | if (result.isSuccess()) {
44 | return createData(result.nullable());
45 | } else if (result.isShowToast()) {
46 | ToastUtils.showShort(result.getMsg());
47 | } else if (!needHandleResult(result)) {
48 | return Observable.error(new Exception(result.getMsg()));
49 | }else {
50 | return Observable.error(new Exception(result.getMsg()));
51 | }
52 | return Observable.empty();
53 | }
54 | );
55 | }
56 |
57 | protected Observable> createData(final NullableResult t) {
58 | return Observable.create(subscriber -> {
59 | try {
60 | subscriber.onNext(t);
61 | subscriber.onComplete();
62 | } catch (Exception e) {
63 | subscriber.onError(e);
64 | }
65 | });
66 | }
67 |
68 | public boolean addRxStop(Disposable disposable) {
69 | if (disposables2Stop == null) {
70 | throw new IllegalStateException(
71 | "addUtilStop should be called between onStart and onStop");
72 | }
73 | disposables2Stop.add(disposable);
74 | return true;
75 | }
76 |
77 | public boolean addRxDestroy(Disposable disposable) {
78 | if (disposables2Destroy == null) {
79 | throw new IllegalStateException(
80 | "addUtilDestroy should be called between onCreate and onDestroy");
81 | }
82 | disposables2Destroy.add(disposable);
83 | return true;
84 | }
85 |
86 | public void remove(Disposable disposable) {
87 | if (disposables2Stop == null && disposables2Destroy == null) {
88 | throw new IllegalStateException("remove should not be called after onDestroy");
89 | }
90 | if (disposables2Stop != null) {
91 | disposables2Stop.remove(disposable);
92 | }
93 | if (disposables2Destroy != null) {
94 | disposables2Destroy.remove(disposable);
95 | }
96 | }
97 |
98 | protected void onCreate(Bundle savedInstanceState) {
99 | if (disposables2Destroy != null) {
100 | throw new IllegalStateException("onCreate called multiple times");
101 | }
102 | disposables2Destroy = new CompositeDisposable();
103 | super.onCreate(savedInstanceState);
104 | }
105 |
106 | protected void onStart() {
107 | if (disposables2Stop != null) {
108 | throw new IllegalStateException("onStart called multiple times");
109 | }
110 | disposables2Stop = new CompositeDisposable();
111 | super.onStart();
112 | }
113 |
114 | protected void onStop() {
115 | super.onStop();
116 | if (disposables2Stop == null) {
117 | throw new IllegalStateException("onStop called multiple times or onStart not called");
118 | }
119 | disposables2Stop.dispose();
120 | disposables2Stop = null;
121 | }
122 |
123 | protected void onDestroy() {
124 | super.onDestroy();
125 | if (disposables2Destroy == null) {
126 | throw new IllegalStateException(
127 | "onDestroy called multiple times or onCreate not called");
128 | }
129 | disposables2Destroy.dispose();
130 | disposables2Destroy = null;
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/base/BaseRxFragment.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.base;
2 |
3 | import android.os.Bundle;
4 |
5 | import com.github.weiss.core.api.NullableResult;
6 | import com.github.weiss.core.entity.BaseHttpResult;
7 |
8 | import io.reactivex.Observable;
9 | import io.reactivex.ObservableTransformer;
10 | import io.reactivex.disposables.CompositeDisposable;
11 | import io.reactivex.disposables.Disposable;
12 |
13 | /**
14 | * 管理RxJava生命周期,避免内存泄漏
15 | *
16 | * Created by Weiss on 2016/12/23.
17 | */
18 |
19 | public abstract class BaseRxFragment extends BaseFragment {
20 |
21 | private CompositeDisposable disposables2Stop;// 管理Stop取消订阅者者
22 | private CompositeDisposable disposables2Destroy;// 管理Destroy取消订阅者者
23 |
24 | protected abstract int getLayoutId();
25 |
26 | protected abstract void initView();
27 |
28 | /**
29 | * Rx优雅处理服务器返回
30 | *
31 | * @param
32 | * @return
33 | */
34 | public ObservableTransformer, NullableResult> handleResult() {
35 | BaseRxActivity baseActivity = (BaseRxActivity) getActivity();
36 | if (baseActivity != null) {
37 | return baseActivity.handleResult();
38 | } else {
39 | return handleError();
40 | }
41 | }
42 |
43 | public ObservableTransformer, NullableResult> handleError() {
44 | return upstream -> {
45 | return upstream.flatMap(result -> {
46 | return Observable.error(new Exception("getActivity() is null"));
47 | }
48 |
49 | );
50 | };
51 | }
52 |
53 | public boolean addRxStop(Disposable disposable) {
54 | if (disposables2Stop == null) {
55 | throw new IllegalStateException(
56 | "addUtilStop should be called between onStart and onStop");
57 | }
58 | disposables2Stop.add(disposable);
59 | return true;
60 | }
61 |
62 | public boolean addRxDestroy(Disposable disposable) {
63 | if (disposables2Destroy == null) {
64 | throw new IllegalStateException(
65 | "addUtilDestroy should be called between onCreate and onDestroy");
66 | }
67 | disposables2Destroy.add(disposable);
68 | return true;
69 | }
70 |
71 | public void remove(Disposable disposable) {
72 | if (disposables2Stop == null && disposables2Destroy == null) {
73 | throw new IllegalStateException("remove should not be called after onDestroy");
74 | }
75 | if (disposables2Stop != null) {
76 | disposables2Stop.remove(disposable);
77 | }
78 | if (disposables2Destroy != null) {
79 | disposables2Destroy.remove(disposable);
80 | }
81 | }
82 |
83 | public void onCreate(Bundle savedInstanceState) {
84 | super.onCreate(savedInstanceState);
85 | if (disposables2Destroy != null) {
86 | throw new IllegalStateException("onCreate called multiple times");
87 | }
88 | disposables2Destroy = new CompositeDisposable();
89 | }
90 |
91 | public void onStart() {
92 | super.onStart();
93 | if (disposables2Stop != null) {
94 | throw new IllegalStateException("onStart called multiple times");
95 | }
96 | disposables2Stop = new CompositeDisposable();
97 | }
98 |
99 | public void onStop() {
100 | super.onStop();
101 | if (disposables2Stop == null) {
102 | throw new IllegalStateException("onStop called multiple times or onStart not called");
103 | }
104 | disposables2Stop.dispose();
105 | disposables2Stop = null;
106 | }
107 |
108 | public void onDestroy() {
109 | super.onDestroy();
110 | if (disposables2Destroy == null) {
111 | throw new IllegalStateException(
112 | "onDestroy called multiple times or onCreate not called");
113 | }
114 | disposables2Destroy.dispose();
115 | disposables2Destroy = null;
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/core/src/main/java/com/github/weiss/core/bus/RxBus.java:
--------------------------------------------------------------------------------
1 | package com.github.weiss.core.bus;
2 |
3 |
4 | import java.util.Map;
5 | import java.util.concurrent.ConcurrentHashMap;
6 |
7 | import io.reactivex.Observable;
8 | import io.reactivex.ObservableEmitter;
9 | import io.reactivex.ObservableOnSubscribe;
10 | import io.reactivex.subjects.PublishSubject;
11 | import io.reactivex.subjects.Subject;
12 |
13 |
14 | /**
15 | * 只会把在订阅发生的时间点之后来自原始Observable的数据发射给观察者
16 | */
17 | public class RxBus {
18 | private static volatile RxBus mDefaultInstance;
19 | private final Subject