├── .gitignore
├── .idea
├── codeStyles
│ └── Project.xml
├── gradle.xml
├── inspectionProfiles
│ └── Project_Default.xml
├── misc.xml
├── runConfigurations.xml
└── vcs.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── xing
│ │ └── retrofitconverter
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── xing
│ │ │ └── retrofitconverter
│ │ │ ├── ArticleAdapter.java
│ │ │ ├── ArticleBean.java
│ │ │ ├── ArticleDetailBean.java
│ │ │ ├── MainActivity.java
│ │ │ └── api
│ │ │ ├── ApiException.java
│ │ │ ├── ApiService.java
│ │ │ ├── ApiServiceImpl.java
│ │ │ ├── BaseResourceObserver.java
│ │ │ ├── BaseResponse.java
│ │ │ ├── GsonUtils.java
│ │ │ ├── RetrofitClient.java
│ │ │ └── http
│ │ │ ├── MyConverterFactory.java
│ │ │ ├── RequestBodyConverter.java
│ │ │ └── ResponseBodyConverter.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ └── item_main.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── xing
│ └── retrofitconverter
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RetrofitConverterSimple
2 | RetrofitConverterSimple
3 |
4 | Android使用Rxjava、Retrofit处理json解析异常
5 | 详情 https://blog.csdn.net/magic0908/article/details/87195805
6 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 28
5 | defaultConfig {
6 | applicationId "com.xing.retrofitconverter"
7 | minSdkVersion 19
8 | targetSdkVersion 28
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | implementation fileTree(include: ['*.jar'], dir: 'libs')
23 | //support
24 | implementation 'com.android.support.constraint:constraint-layout:1.1.3'
25 | implementation 'com.android.support:appcompat-v7:28.0.0'
26 | implementation 'com.android.support:design:28.0.0'
27 | implementation 'com.android.support:recyclerview-v7:28.0.0'
28 | //retrofit2
29 | implementation 'com.squareup.retrofit2:retrofit:2.5.0'
30 | implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
31 | implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
32 | //glide
33 | implementation 'com.github.bumptech.glide:glide:4.8.0'
34 | //rxjava2
35 | implementation 'io.reactivex.rxjava2:rxjava:2.2.2'
36 | implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
37 | //Adapter
38 | implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.42'
39 | testImplementation 'junit:junit:4.12'
40 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
41 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/xing/retrofitconverter/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.xing.retrofitconverter;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.xing.retrofitconverter", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xing/retrofitconverter/ArticleAdapter.java:
--------------------------------------------------------------------------------
1 | package com.xing.retrofitconverter;
2 |
3 | import android.support.annotation.Nullable;
4 | import android.widget.ImageView;
5 |
6 | import com.bumptech.glide.Glide;
7 | import com.bumptech.glide.request.RequestOptions;
8 | import com.chad.library.adapter.base.BaseQuickAdapter;
9 | import com.chad.library.adapter.base.BaseViewHolder;
10 |
11 | import java.util.List;
12 |
13 | /**
14 | * Creation Time: 2019/2/13 14:26.
15 | * Author: King.
16 | * Description: ArticleAdapter
17 | */
18 | public class ArticleAdapter extends BaseQuickAdapter {
19 |
20 | public ArticleAdapter(@Nullable List data) {
21 | super(R.layout.item_main, data);
22 | }
23 |
24 | @Override
25 | protected void convert(BaseViewHolder helper, ArticleDetailBean item) {
26 | ImageView ivPic = helper.getView(R.id.iv_pic);
27 | Glide.with(ivPic.getContext())
28 | .load(item.getEnvelopePic())
29 | .apply(new RequestOptions().centerCrop())
30 | .into(ivPic);
31 | helper.setText(R.id.tv_title,item.getTitle())
32 | .setText(R.id.tv_desc,item.getDesc())
33 | .setText(R.id.tv_time,item.getNiceDate())
34 | .setText(R.id.tv_author,item.getAuthor());
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xing/retrofitconverter/ArticleBean.java:
--------------------------------------------------------------------------------
1 | package com.xing.retrofitconverter;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * Creation Time: 2019/2/13 13:53.
7 | * Author: King.
8 | * Description:
9 | */
10 | public class ArticleBean {
11 |
12 | private int curPage;
13 | private int offset;
14 | private boolean over;
15 | private int pageCount;
16 | private int size;
17 | private int total;
18 | private List datas;
19 |
20 | public int getCurPage() {
21 | return curPage;
22 | }
23 |
24 | public void setCurPage(int curPage) {
25 | this.curPage = curPage;
26 | }
27 |
28 | public int getOffset() {
29 | return offset;
30 | }
31 |
32 | public void setOffset(int offset) {
33 | this.offset = offset;
34 | }
35 |
36 | public boolean isOver() {
37 | return over;
38 | }
39 |
40 | public void setOver(boolean over) {
41 | this.over = over;
42 | }
43 |
44 | public int getPageCount() {
45 | return pageCount;
46 | }
47 |
48 | public void setPageCount(int pageCount) {
49 | this.pageCount = pageCount;
50 | }
51 |
52 | public int getSize() {
53 | return size;
54 | }
55 |
56 | public void setSize(int size) {
57 | this.size = size;
58 | }
59 |
60 | public int getTotal() {
61 | return total;
62 | }
63 |
64 | public void setTotal(int total) {
65 | this.total = total;
66 | }
67 |
68 | public List getDatas() {
69 | return datas;
70 | }
71 |
72 | public void setDatas(List datas) {
73 | this.datas = datas;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xing/retrofitconverter/ArticleDetailBean.java:
--------------------------------------------------------------------------------
1 | package com.xing.retrofitconverter;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * Creation Time: 2019/2/13 13:54.
7 | * Author: King.
8 | * Description:
9 | */
10 | public class ArticleDetailBean {
11 |
12 | /**
13 | * apkLink :
14 | * author : moyokoo
15 | * chapterId : 382
16 | * chapterName : 音视频&相机
17 | * collect : false
18 | * courseId : 13
19 | * desc : 新版youtube视频拖放效果
20 | * envelopePic : http://wanandroid.com/blogimgs/9d8487a5-e5f8-4762-b3f8-ae3f0337cc95.png
21 | * fresh : false
22 | * id : 7922
23 | * link : http://www.wanandroid.com/blog/show/2495
24 | * niceDate : 2019-01-31
25 | * origin :
26 | * projectLink : https://github.com/moyokoo/YoutubeVideoSample
27 | * publishTime : 1548931933000
28 | * superChapterId : 294
29 | * superChapterName : 开源项目主Tab
30 | * tags : [{"name":"项目","url":"/project/list/1?cid=382"}]
31 | * title : 新版youtube视频拖放效果
32 | * type : 0
33 | * userId : -1
34 | * visible : 1
35 | * zan : 0
36 | */
37 |
38 | private String apkLink;
39 | private String author;
40 | private int chapterId;
41 | private String chapterName;
42 | private boolean collect;
43 | private int courseId;
44 | private String desc;
45 | private String envelopePic;
46 | private boolean fresh;
47 | private int id;
48 | private String link;
49 | private String niceDate;
50 | private String origin;
51 | private String projectLink;
52 | private long publishTime;
53 | private int superChapterId;
54 | private String superChapterName;
55 | private String title;
56 | private int type;
57 | private int userId;
58 | private int visible;
59 | private int zan;
60 | private List tags;
61 |
62 | public String getApkLink() {
63 | return apkLink;
64 | }
65 |
66 | public void setApkLink(String apkLink) {
67 | this.apkLink = apkLink;
68 | }
69 |
70 | public String getAuthor() {
71 | return author;
72 | }
73 |
74 | public void setAuthor(String author) {
75 | this.author = author;
76 | }
77 |
78 | public int getChapterId() {
79 | return chapterId;
80 | }
81 |
82 | public void setChapterId(int chapterId) {
83 | this.chapterId = chapterId;
84 | }
85 |
86 | public String getChapterName() {
87 | return chapterName;
88 | }
89 |
90 | public void setChapterName(String chapterName) {
91 | this.chapterName = chapterName;
92 | }
93 |
94 | public boolean isCollect() {
95 | return collect;
96 | }
97 |
98 | public void setCollect(boolean collect) {
99 | this.collect = collect;
100 | }
101 |
102 | public int getCourseId() {
103 | return courseId;
104 | }
105 |
106 | public void setCourseId(int courseId) {
107 | this.courseId = courseId;
108 | }
109 |
110 | public String getDesc() {
111 | return desc;
112 | }
113 |
114 | public void setDesc(String desc) {
115 | this.desc = desc;
116 | }
117 |
118 | public String getEnvelopePic() {
119 | return envelopePic;
120 | }
121 |
122 | public void setEnvelopePic(String envelopePic) {
123 | this.envelopePic = envelopePic;
124 | }
125 |
126 | public boolean isFresh() {
127 | return fresh;
128 | }
129 |
130 | public void setFresh(boolean fresh) {
131 | this.fresh = fresh;
132 | }
133 |
134 | public int getId() {
135 | return id;
136 | }
137 |
138 | public void setId(int id) {
139 | this.id = id;
140 | }
141 |
142 | public String getLink() {
143 | return link;
144 | }
145 |
146 | public void setLink(String link) {
147 | this.link = link;
148 | }
149 |
150 | public String getNiceDate() {
151 | return niceDate;
152 | }
153 |
154 | public void setNiceDate(String niceDate) {
155 | this.niceDate = niceDate;
156 | }
157 |
158 | public String getOrigin() {
159 | return origin;
160 | }
161 |
162 | public void setOrigin(String origin) {
163 | this.origin = origin;
164 | }
165 |
166 | public String getProjectLink() {
167 | return projectLink;
168 | }
169 |
170 | public void setProjectLink(String projectLink) {
171 | this.projectLink = projectLink;
172 | }
173 |
174 | public long getPublishTime() {
175 | return publishTime;
176 | }
177 |
178 | public void setPublishTime(long publishTime) {
179 | this.publishTime = publishTime;
180 | }
181 |
182 | public int getSuperChapterId() {
183 | return superChapterId;
184 | }
185 |
186 | public void setSuperChapterId(int superChapterId) {
187 | this.superChapterId = superChapterId;
188 | }
189 |
190 | public String getSuperChapterName() {
191 | return superChapterName;
192 | }
193 |
194 | public void setSuperChapterName(String superChapterName) {
195 | this.superChapterName = superChapterName;
196 | }
197 |
198 | public String getTitle() {
199 | return title;
200 | }
201 |
202 | public void setTitle(String title) {
203 | this.title = title;
204 | }
205 |
206 | public int getType() {
207 | return type;
208 | }
209 |
210 | public void setType(int type) {
211 | this.type = type;
212 | }
213 |
214 | public int getUserId() {
215 | return userId;
216 | }
217 |
218 | public void setUserId(int userId) {
219 | this.userId = userId;
220 | }
221 |
222 | public int getVisible() {
223 | return visible;
224 | }
225 |
226 | public void setVisible(int visible) {
227 | this.visible = visible;
228 | }
229 |
230 | public int getZan() {
231 | return zan;
232 | }
233 |
234 | public void setZan(int zan) {
235 | this.zan = zan;
236 | }
237 |
238 | public List getTags() {
239 | return tags;
240 | }
241 |
242 | public void setTags(List tags) {
243 | this.tags = tags;
244 | }
245 |
246 | public static class TagsBean {
247 | /**
248 | * name : 项目
249 | * url : /project/list/1?cid=382
250 | */
251 |
252 | private String name;
253 | private String url;
254 |
255 | public String getName() {
256 | return name;
257 | }
258 |
259 | public void setName(String name) {
260 | this.name = name;
261 | }
262 |
263 | public String getUrl() {
264 | return url;
265 | }
266 |
267 | public void setUrl(String url) {
268 | this.url = url;
269 | }
270 | }
271 | }
272 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xing/retrofitconverter/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.xing.retrofitconverter;
2 |
3 | import android.content.Intent;
4 | import android.graphics.Rect;
5 | import android.net.Uri;
6 | import android.os.Bundle;
7 | import android.support.annotation.NonNull;
8 | import android.support.v4.widget.SwipeRefreshLayout;
9 | import android.support.v7.app.AppCompatActivity;
10 | import android.support.v7.widget.LinearLayoutManager;
11 | import android.support.v7.widget.RecyclerView;
12 | import android.view.View;
13 |
14 | import com.chad.library.adapter.base.BaseQuickAdapter;
15 | import com.xing.retrofitconverter.api.ApiServiceImpl;
16 | import com.xing.retrofitconverter.api.BaseResourceObserver;
17 | import com.xing.retrofitconverter.api.RetrofitClient;
18 |
19 | import java.util.List;
20 |
21 | import io.reactivex.android.schedulers.AndroidSchedulers;
22 | import io.reactivex.disposables.CompositeDisposable;
23 | import io.reactivex.disposables.Disposable;
24 | import io.reactivex.schedulers.Schedulers;
25 |
26 | public class MainActivity extends AppCompatActivity
27 | implements SwipeRefreshLayout.OnRefreshListener, BaseQuickAdapter.RequestLoadMoreListener {
28 |
29 | private SwipeRefreshLayout mRefreshLayout;
30 | private RecyclerView mRecyclerView;
31 | private ArticleAdapter mAdapter;
32 | private CompositeDisposable mCompositeDisposable;
33 |
34 | private int pageIndex;
35 |
36 | @Override
37 | protected void onCreate(Bundle savedInstanceState) {
38 | super.onCreate(savedInstanceState);
39 | RetrofitClient.getInstance().init();
40 | setContentView(R.layout.activity_main);
41 | initView();
42 | mAdapter = new ArticleAdapter(null);
43 | mAdapter.setOnLoadMoreListener(this, mRecyclerView);
44 | mAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
45 | @Override
46 | public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
47 | ArticleDetailBean bean = mAdapter.getData().get(position);
48 | Uri uri = Uri.parse(bean.getLink());
49 | Intent intent = new Intent(Intent.ACTION_VIEW, uri);
50 | startActivity(intent);
51 | }
52 | });
53 | mRecyclerView.setAdapter(mAdapter);
54 | mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
55 | mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
56 | @Override
57 | public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
58 | int margin = getResources().getDimensionPixelSize(R.dimen.dp_10);
59 | if (parent.getChildAdapterPosition(view) == 0) {
60 | outRect.top = margin;
61 | outRect.bottom = margin;
62 | } else {
63 | outRect.top = 0;
64 | outRect.bottom = margin;
65 | }
66 | outRect.left = margin;
67 | outRect.right = margin;
68 | }
69 | });
70 | onRefresh();
71 | }
72 |
73 | private void initView() {
74 | mRefreshLayout = findViewById(R.id.srl);
75 | mRecyclerView = findViewById(R.id.rv_list);
76 | mRefreshLayout.setColorSchemeResources(R.color.colorAccent);
77 | mRefreshLayout.setOnRefreshListener(this);
78 | mCompositeDisposable = new CompositeDisposable();
79 | }
80 |
81 | @Override
82 | public void onRefresh() {
83 | pageIndex = 0;
84 | requestData();
85 | mRefreshLayout.setRefreshing(false);
86 | }
87 |
88 | @Override
89 | public void onLoadMoreRequested() {
90 | requestData();
91 | }
92 |
93 | private void requestData() {
94 | Disposable disposable = ApiServiceImpl.getInstance()
95 | .getArticleList(pageIndex)
96 | .subscribeOn(Schedulers.io())
97 | .observeOn(AndroidSchedulers.mainThread())
98 | .subscribeWith(new BaseResourceObserver() {
99 | @Override
100 | public void onNext(ArticleBean articleBean) {
101 | List list = articleBean.getDatas();
102 | if (pageIndex == 0) {
103 | mAdapter.setNewData(list);
104 | } else if (articleBean.getCurPage() >= articleBean.getPageCount()) {
105 | mAdapter.loadMoreEnd();
106 | } else {
107 | mAdapter.addData(list);
108 | mAdapter.loadMoreComplete();
109 | }
110 | pageIndex = articleBean.getCurPage();
111 | }
112 |
113 | //可以重写该方法,处理额外的逻辑
114 | // @Override
115 | // public void onError(Throwable throwable) {
116 | // super.onError(throwable);
117 | // }
118 | });
119 | mCompositeDisposable.add(disposable);
120 | }
121 |
122 | @Override
123 | protected void onDestroy() {
124 | mCompositeDisposable.dispose();
125 | super.onDestroy();
126 | }
127 |
128 | }
129 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xing/retrofitconverter/api/ApiException.java:
--------------------------------------------------------------------------------
1 | package com.xing.retrofitconverter.api;
2 |
3 | /**
4 | * Creation Time: 2018/8/20 10:44.
5 | * Author: King.
6 | * Description: 服务端的异常处理类,根据与服务端约定的code判断
7 | */
8 | public class ApiException extends RuntimeException{
9 |
10 | private int errorCode;
11 |
12 | public ApiException(int errorCode, String msg) {
13 | super(msg);
14 | this.errorCode = errorCode;
15 | }
16 |
17 | public int getErrorCode() {
18 | return errorCode;
19 | }
20 |
21 | public void setErrorCode(int errorCode) {
22 | this.errorCode = errorCode;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xing/retrofitconverter/api/ApiService.java:
--------------------------------------------------------------------------------
1 | package com.xing.retrofitconverter.api;
2 |
3 | import com.xing.retrofitconverter.ArticleBean;
4 |
5 | import io.reactivex.Observable;
6 | import retrofit2.http.GET;
7 | import retrofit2.http.Path;
8 |
9 | /**
10 | * Creation Time: 2019/2/13 13:32.
11 | * Author: King.
12 | * Description: api
13 | */
14 | public interface ApiService {
15 |
16 | String BASE_URL = "http://www.wanandroid.com";
17 |
18 | /**
19 | * 获取首页文章列表
20 | * @param pageIndex pageIndex
21 | * @return Observable
22 | */
23 | @GET("/article/listproject/{pageIndex}/json")
24 | Observable getArticleList(@Path("pageIndex") int pageIndex);
25 |
26 | @GET("/article/listproject/{pageIndex}/json")
27 | Observable> getArticleList1(@Path("pageIndex") int pageIndex);
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xing/retrofitconverter/api/ApiServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.xing.retrofitconverter.api;
2 |
3 | /**
4 | * Creation Time: 2018/8/30 9:56.
5 | * Author: King.
6 | * Description: ApiService接口类实现
7 | */
8 | public class ApiServiceImpl {
9 |
10 | private ApiServiceImpl() {
11 | throw new RuntimeException("you can't init me");
12 | }
13 | public static ApiService getInstance() {
14 | return createApiService.apiService;
15 | }
16 |
17 | /**
18 | * Retrofit生成接口对象.
19 | */
20 | private static class createApiService {
21 | /**
22 | * Retrofit会根据传入的接口类.生成实例对象.
23 | */
24 | private static final ApiService apiService = RetrofitClient.getInstance().getApi(ApiService.class);
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xing/retrofitconverter/api/BaseResourceObserver.java:
--------------------------------------------------------------------------------
1 | package com.xing.retrofitconverter.api;
2 |
3 | import android.net.ParseException;
4 | import android.util.Log;
5 |
6 | import com.google.gson.JsonParseException;
7 |
8 | import org.json.JSONException;
9 |
10 | import java.net.ConnectException;
11 | import java.net.SocketTimeoutException;
12 | import java.net.UnknownHostException;
13 |
14 | import io.reactivex.observers.DisposableObserver;
15 | import retrofit2.HttpException;
16 |
17 | /**
18 | * Creation Time: 2018/9/14 11:19.
19 | * Author: King.
20 | * Description: 泛型T返回的是具体的数据类型,多数时候只需重写onNext方法即可
21 | */
22 | public abstract class BaseResourceObserver extends DisposableObserver {
23 |
24 | /*========================= HttpException 异常 code ==========================*/
25 |
26 | private static final int UNAUTHORIZED = 401;
27 | private static final int FORBIDDEN = 403;
28 | private static final int NOT_FOUND = 404;
29 | private static final int REQUEST_TIMEOUT = 408;
30 | private static final int INTERNAL_SERVER_ERROR = 500;
31 | private static final int BAD_GATEWAY = 502;
32 | private static final int SERVICE_UNAVAILABLE = 503;
33 | private static final int GATEWAY_TIMEOUT = 504;
34 |
35 | @Override
36 | protected void onStart() {
37 | super.onStart();
38 | }
39 |
40 | @Override
41 | public void onError(Throwable throwable) {
42 | //打印日志到控制台
43 | throwable.printStackTrace();
44 | //如果你某个地方不想使用全局错误处理,则重写 onError(Throwable) 并将 super.onError(e); 删掉
45 | //如果你不仅想使用全局错误处理,还想加入自己的逻辑,则重写 onError(Throwable) 并在 super.onError(e); 后面加入自己的逻辑
46 | String msg = requestHandle(throwable);
47 | Log.i("tag",msg);
48 | }
49 |
50 | @Override
51 | public void onComplete() {
52 | }
53 |
54 | /**
55 | * 统一处理Throwable
56 | * @param e e
57 | * @return msg
58 | */
59 | private String requestHandle(Throwable e) {
60 | String msg;
61 | if (e instanceof HttpException) {
62 | HttpException httpException = (HttpException) e;
63 | switch (httpException.code()) {
64 | case UNAUTHORIZED:
65 | case FORBIDDEN:
66 | case NOT_FOUND:
67 | case REQUEST_TIMEOUT:
68 | case GATEWAY_TIMEOUT:
69 | case INTERNAL_SERVER_ERROR:
70 | case BAD_GATEWAY:
71 | case SERVICE_UNAVAILABLE:
72 | default:
73 | msg = "服务器错误";
74 | break;
75 | }
76 | } else if (e instanceof ApiException) {
77 | //后台异常
78 | ApiException apiException = (ApiException) e;
79 | msg = apiException.getMessage();
80 | } else if (e instanceof JsonParseException || e instanceof JSONException || e instanceof ParseException) {
81 | msg = "解析错误";
82 | } else if (e instanceof ConnectException || e instanceof SocketTimeoutException || e instanceof UnknownHostException) {
83 | msg = "连接失败,请检查网络";
84 | } else if (e instanceof NumberFormatException){
85 | msg = "数字格式化异常";
86 | } else {
87 | msg = "请求失败";
88 | }
89 | return msg;
90 | }
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xing/retrofitconverter/api/BaseResponse.java:
--------------------------------------------------------------------------------
1 | package com.xing.retrofitconverter.api;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | /**
7 | * Creation Time: 2019/2/13 13:34.
8 | * Author: King.
9 | * Description: 与服务端约定的基本数据格式类型
10 | * 这里采用 玩Android 开放API 链接 http://www.wanandroid.com/blog/show/2
11 | */
12 | public class BaseResponse implements Parcelable {
13 |
14 | private int errorCode;
15 | private String error;
16 | private T data;
17 |
18 | public int getErrorCode() {
19 | return errorCode;
20 | }
21 |
22 | public void setErrorCode(int errorCode) {
23 | this.errorCode = errorCode;
24 | }
25 |
26 | public String getError() {
27 | return error;
28 | }
29 |
30 | public void setError(String error) {
31 | this.error = error;
32 | }
33 |
34 | public T getData() {
35 | return data;
36 | }
37 |
38 | public void setData(T data) {
39 | this.data = data;
40 | }
41 |
42 | /**
43 | * 判断请求是否成功
44 | * @return bool
45 | */
46 | public boolean isSuccess(){
47 | return getErrorCode() == 0;
48 | }
49 |
50 | @Override
51 | public int describeContents() {
52 | return 0;
53 | }
54 |
55 | @Override
56 | public void writeToParcel(Parcel dest, int flags) {
57 | dest.writeInt(this.errorCode);
58 | dest.writeString(this.error);
59 | }
60 |
61 | public BaseResponse() {
62 | }
63 |
64 | protected BaseResponse(Parcel in) {
65 | this.errorCode = in.readInt();
66 | this.error = in.readString();
67 | }
68 |
69 | public static final Creator CREATOR = new Creator() {
70 | @Override
71 | public BaseResponse createFromParcel(Parcel source) {
72 | return new BaseResponse(source);
73 | }
74 |
75 | @Override
76 | public BaseResponse[] newArray(int size) {
77 | return new BaseResponse[size];
78 | }
79 | };
80 | }
81 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xing/retrofitconverter/api/GsonUtils.java:
--------------------------------------------------------------------------------
1 | package com.xing.retrofitconverter.api;
2 |
3 | import com.google.gson.Gson;
4 | import com.google.gson.GsonBuilder;
5 | import com.google.gson.JsonParser;
6 | import com.google.gson.JsonSyntaxException;
7 | import com.google.gson.reflect.TypeToken;
8 |
9 | import java.util.Map;
10 |
11 | public class GsonUtils {
12 | private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
13 | private static final JsonParser PARSER = new JsonParser();
14 |
15 | public static Gson getGSON() {
16 | return GSON;
17 | }
18 |
19 | /**
20 | * Object 转 json
21 | * @param object object
22 | * @return object
23 | */
24 | public static String GsonString(Object object){
25 | return GSON.toJson(object);
26 | }
27 |
28 | public static T GsonToBean(String gsonString, Class cls) {
29 | return GSON.fromJson(gsonString, cls);
30 | }
31 |
32 | /**
33 | * 转成map的
34 | *
35 | * @param gsonString str
36 | * @return map
37 | */
38 | public static Map GsonToMaps(String gsonString) {
39 | return GSON.fromJson(gsonString, new TypeToken