├── .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 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 36 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 27 | 42 | 43 | 44 | 45 | 46 | 47 | 49 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 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>() {}.getType()); 40 | } 41 | 42 | /** 43 | * 将json 格式化输出 44 | * @param str str 45 | * @return str 46 | */ 47 | public static String GsonToString(String str){ 48 | try { 49 | return GSON.toJson(PARSER.parse(str)); 50 | } catch (JsonSyntaxException e){ 51 | e.printStackTrace(); 52 | return str; 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/xing/retrofitconverter/api/RetrofitClient.java: -------------------------------------------------------------------------------- 1 | package com.xing.retrofitconverter.api; 2 | 3 | import com.xing.retrofitconverter.api.http.MyConverterFactory; 4 | 5 | import java.util.concurrent.TimeUnit; 6 | 7 | import okhttp3.OkHttpClient; 8 | import retrofit2.Retrofit; 9 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; 10 | import retrofit2.converter.gson.GsonConverterFactory; 11 | 12 | /** 13 | * Creation Time: 2018/10/26 13:01. 14 | * Author: King. 15 | * Description: Retrofit请求封装 16 | */ 17 | public class RetrofitClient { 18 | 19 | private static RetrofitClient mInstance; 20 | 21 | private Retrofit mRetrofit; 22 | 23 | private RetrofitClient() { 24 | } 25 | 26 | public static RetrofitClient getInstance() { 27 | if (mInstance == null) { 28 | synchronized (RetrofitClient.class) { 29 | if (mInstance == null) mInstance = new RetrofitClient(); 30 | } 31 | } 32 | return mInstance; 33 | } 34 | 35 | /** 36 | * 初始化必要对象与参数 37 | */ 38 | public void init() { 39 | OkHttpClient.Builder builder = new OkHttpClient.Builder() 40 | //链接超时 41 | .connectTimeout(90, TimeUnit.SECONDS) 42 | //读取超时 43 | .readTimeout(90, TimeUnit.SECONDS) 44 | //失败自动重连 45 | .retryOnConnectionFailure(true); 46 | //初始化Retrofit并添加配置 47 | mRetrofit = new Retrofit.Builder() 48 | .client(builder.build()) 49 | .baseUrl(ApiService.BASE_URL) 50 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) 51 | // .addConverterFactory(GsonConverterFactory.create()) 52 | //这里是自定义的GsonConverterFactory 53 | .addConverterFactory(MyConverterFactory.create()) 54 | .build(); 55 | } 56 | 57 | public T getApi(Class clz) { 58 | return mRetrofit.create(clz); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/xing/retrofitconverter/api/http/MyConverterFactory.java: -------------------------------------------------------------------------------- 1 | package com.xing.retrofitconverter.api.http; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.TypeAdapter; 5 | import com.google.gson.reflect.TypeToken; 6 | import com.xing.retrofitconverter.api.GsonUtils; 7 | 8 | import java.lang.annotation.Annotation; 9 | import java.lang.reflect.Type; 10 | 11 | import okhttp3.RequestBody; 12 | import okhttp3.ResponseBody; 13 | import retrofit2.Converter; 14 | import retrofit2.Retrofit; 15 | 16 | /** 17 | * Creation Time: 2018/10/26 12:58. 18 | * Author: King. 19 | * Description: 自定义的GsonConverterFactory 20 | */ 21 | public class MyConverterFactory extends Converter.Factory { 22 | 23 | /** 24 | * Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and 25 | * decoding from JSON (when no charset is specified by a header) will use UTF-8. 26 | */ 27 | public static MyConverterFactory create() { 28 | return create(GsonUtils.getGSON()); 29 | } 30 | 31 | /** 32 | * Create an instance using {@code gson} for conversion. Encoding to JSON and 33 | * decoding from JSON (when no charset is specified by a header) will use UTF-8. 34 | */ 35 | @SuppressWarnings("ConstantConditions") // Guarding public API nullability. 36 | public static MyConverterFactory create(Gson gson) { 37 | if (gson == null) { 38 | throw new NullPointerException("gson == null"); 39 | } 40 | return new MyConverterFactory(gson); 41 | } 42 | 43 | private final Gson gson; 44 | 45 | private MyConverterFactory(Gson gson) { 46 | this.gson = gson; 47 | } 48 | 49 | @Override 50 | public Converter requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) { 51 | TypeAdapter adapter = gson.getAdapter(TypeToken.get(type)); 52 | return new RequestBodyConverter<>(gson, adapter); 53 | } 54 | 55 | @Override 56 | public Converter responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { 57 | return new ResponseBodyConverter<>(gson, TypeToken.get(type)); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/xing/retrofitconverter/api/http/RequestBodyConverter.java: -------------------------------------------------------------------------------- 1 | package com.xing.retrofitconverter.api.http; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import com.google.gson.Gson; 6 | import com.google.gson.TypeAdapter; 7 | import com.google.gson.stream.JsonWriter; 8 | 9 | import java.io.IOException; 10 | import java.io.OutputStreamWriter; 11 | import java.io.Writer; 12 | import java.nio.charset.Charset; 13 | 14 | import okhttp3.MediaType; 15 | import okhttp3.RequestBody; 16 | import okio.Buffer; 17 | import retrofit2.Converter; 18 | 19 | /** 20 | * Creation Time: 2018/10/26 12:57. 21 | * Author: King. 22 | * Description: 23 | */ 24 | public class RequestBodyConverter implements Converter { 25 | 26 | private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8"); 27 | private static final Charset UTF_8 = Charset.forName("UTF-8"); 28 | 29 | private final Gson gson; 30 | private final TypeAdapter adapter; 31 | 32 | RequestBodyConverter(Gson gson, TypeAdapter adapter) { 33 | this.gson = gson; 34 | this.adapter = adapter; 35 | } 36 | 37 | @Override public RequestBody convert(@NonNull T value) throws IOException { 38 | Buffer buffer = new Buffer(); 39 | Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8); 40 | JsonWriter jsonWriter = gson.newJsonWriter(writer); 41 | adapter.write(jsonWriter, value); 42 | jsonWriter.close(); 43 | return RequestBody.create(MEDIA_TYPE, buffer.readByteString()); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/xing/retrofitconverter/api/http/ResponseBodyConverter.java: -------------------------------------------------------------------------------- 1 | package com.xing.retrofitconverter.api.http; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.annotation.Nullable; 5 | 6 | import com.google.gson.Gson; 7 | import com.google.gson.TypeAdapter; 8 | import com.google.gson.reflect.TypeToken; 9 | import com.xing.retrofitconverter.api.ApiException; 10 | import com.xing.retrofitconverter.api.BaseResponse; 11 | import com.xing.retrofitconverter.api.GsonUtils; 12 | 13 | import java.io.IOException; 14 | import java.lang.reflect.GenericArrayType; 15 | import java.lang.reflect.ParameterizedType; 16 | import java.lang.reflect.Type; 17 | import java.lang.reflect.TypeVariable; 18 | import java.lang.reflect.WildcardType; 19 | import java.util.Arrays; 20 | 21 | import okhttp3.ResponseBody; 22 | import retrofit2.Converter; 23 | 24 | /** 25 | * Creation Time: 2018/10/26 12:56. 26 | * Author: King. 27 | * Description: 28 | */ 29 | public class ResponseBodyConverter implements Converter { 30 | 31 | private final TypeAdapter> adapter; 32 | 33 | ResponseBodyConverter(Gson gson, TypeToken typeToken) { 34 | ParameterizedTypeImpl parameterizedType = new ParameterizedTypeImpl(null, BaseResponse.class, typeToken.getType()); 35 | //noinspection unchecked 36 | adapter = (TypeAdapter>) gson.getAdapter(TypeToken.get(parameterizedType)); 37 | } 38 | 39 | @Override 40 | public T convert(@NonNull ResponseBody value) throws IOException { 41 | String json = value.string(); 42 | //第一次解析 43 | BaseResponse obj = GsonUtils.GsonToBean(json, BaseResponse.class); 44 | if (!obj.isSuccess()) { 45 | //如果是服务端返回的错误码,则抛出自定义异常 46 | throw new ApiException(obj.getErrorCode(), obj.getError()); 47 | } 48 | //第二次解析 49 | BaseResponse result = adapter.fromJson(json); 50 | value.close(); 51 | return result.getData(); 52 | } 53 | 54 | private static final class ParameterizedTypeImpl implements ParameterizedType { 55 | private final Type ownerType; 56 | private final Type rawType; 57 | private final Type[] typeArguments; 58 | 59 | ParameterizedTypeImpl(@Nullable Type ownerType, Type rawType, Type... typeArguments) { 60 | // Require an owner type if the raw type needs it. 61 | if (rawType instanceof Class 62 | && (ownerType == null) != (((Class) rawType).getEnclosingClass() == null)) { 63 | throw new IllegalArgumentException(); 64 | } 65 | 66 | for (Type typeArgument : typeArguments) { 67 | checkNotNull(typeArgument, "typeArgument == null"); 68 | checkNotPrimitive(typeArgument); 69 | } 70 | 71 | this.ownerType = ownerType; 72 | this.rawType = rawType; 73 | this.typeArguments = typeArguments.clone(); 74 | } 75 | 76 | @Override 77 | public Type[] getActualTypeArguments() { 78 | return typeArguments.clone(); 79 | } 80 | 81 | @Override 82 | public Type getRawType() { 83 | return rawType; 84 | } 85 | 86 | @Override 87 | public Type getOwnerType() { 88 | return ownerType; 89 | } 90 | 91 | @Override 92 | public boolean equals(Object other) { 93 | return other instanceof ParameterizedType && typeEquals(this, (ParameterizedType) other); 94 | } 95 | 96 | @Override 97 | public int hashCode() { 98 | return Arrays.hashCode(typeArguments) 99 | ^ rawType.hashCode() 100 | ^ (ownerType != null ? ownerType.hashCode() : 0); 101 | } 102 | 103 | @Override 104 | public String toString() { 105 | if (typeArguments.length == 0) return typeToString(rawType); 106 | StringBuilder result = new StringBuilder(30 * (typeArguments.length + 1)); 107 | result.append(typeToString(rawType)); 108 | result.append("<").append(typeToString(typeArguments[0])); 109 | for (int i = 1; i < typeArguments.length; i++) { 110 | result.append(", ").append(typeToString(typeArguments[i])); 111 | } 112 | return result.append(">").toString(); 113 | } 114 | } 115 | 116 | static void checkNotPrimitive(Type type) { 117 | if (type instanceof Class && ((Class) type).isPrimitive()) { 118 | throw new IllegalArgumentException(); 119 | } 120 | } 121 | 122 | static T checkNotNull(@Nullable T object, String message) { 123 | if (object == null) { 124 | throw new NullPointerException(message); 125 | } 126 | return object; 127 | } 128 | 129 | static String typeToString(Type type) { 130 | return type instanceof Class ? ((Class) type).getName() : type.toString(); 131 | } 132 | 133 | /** 134 | * Returns true if {@code a} and {@code b} are equal. 135 | */ 136 | static boolean typeEquals(Type a, Type b) { 137 | if (a == b) { 138 | return true; // Also handles (a == null && b == null). 139 | 140 | } else if (a instanceof Class) { 141 | return a.equals(b); // Class already specifies equals(). 142 | 143 | } else if (a instanceof ParameterizedType) { 144 | if (!(b instanceof ParameterizedType)) return false; 145 | ParameterizedType pa = (ParameterizedType) a; 146 | ParameterizedType pb = (ParameterizedType) b; 147 | Object ownerA = pa.getOwnerType(); 148 | Object ownerB = pb.getOwnerType(); 149 | return (ownerA == ownerB || (ownerA != null && ownerA.equals(ownerB))) 150 | && pa.getRawType().equals(pb.getRawType()) 151 | && Arrays.equals(pa.getActualTypeArguments(), pb.getActualTypeArguments()); 152 | 153 | } else if (a instanceof GenericArrayType) { 154 | if (!(b instanceof GenericArrayType)) return false; 155 | GenericArrayType ga = (GenericArrayType) a; 156 | GenericArrayType gb = (GenericArrayType) b; 157 | return typeEquals(ga.getGenericComponentType(), gb.getGenericComponentType()); 158 | 159 | } else if (a instanceof WildcardType) { 160 | if (!(b instanceof WildcardType)) return false; 161 | WildcardType wa = (WildcardType) a; 162 | WildcardType wb = (WildcardType) b; 163 | return Arrays.equals(wa.getUpperBounds(), wb.getUpperBounds()) 164 | && Arrays.equals(wa.getLowerBounds(), wb.getLowerBounds()); 165 | 166 | } else if (a instanceof TypeVariable) { 167 | if (!(b instanceof TypeVariable)) return false; 168 | TypeVariable va = (TypeVariable) a; 169 | TypeVariable vb = (TypeVariable) b; 170 | return va.getGenericDeclaration() == vb.getGenericDeclaration() 171 | && va.getName().equals(vb.getName()); 172 | 173 | } else { 174 | return false; // This isn't a type we support! 175 | } 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 11 | 16 | 21 | 26 | 31 | 36 | 41 | 46 | 51 | 56 | 61 | 66 | 71 | 76 | 81 | 86 | 91 | 96 | 101 | 106 | 111 | 116 | 121 | 126 | 131 | 136 | 141 | 146 | 151 | 156 | 161 | 166 | 171 | 172 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 17 | 18 | 26 | 27 | 42 | 43 | 58 | 59 | 68 | 69 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magic0908/RetrofitConverterSimple/df2aab577a32770bf3f4ade3cdbb355ceb72b905/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magic0908/RetrofitConverterSimple/df2aab577a32770bf3f4ade3cdbb355ceb72b905/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magic0908/RetrofitConverterSimple/df2aab577a32770bf3f4ade3cdbb355ceb72b905/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magic0908/RetrofitConverterSimple/df2aab577a32770bf3f4ade3cdbb355ceb72b905/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magic0908/RetrofitConverterSimple/df2aab577a32770bf3f4ade3cdbb355ceb72b905/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magic0908/RetrofitConverterSimple/df2aab577a32770bf3f4ade3cdbb355ceb72b905/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magic0908/RetrofitConverterSimple/df2aab577a32770bf3f4ade3cdbb355ceb72b905/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magic0908/RetrofitConverterSimple/df2aab577a32770bf3f4ade3cdbb355ceb72b905/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magic0908/RetrofitConverterSimple/df2aab577a32770bf3f4ade3cdbb355ceb72b905/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magic0908/RetrofitConverterSimple/df2aab577a32770bf3f4ade3cdbb355ceb72b905/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | RetrofitConverterSimple 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/com/xing/retrofitconverter/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.xing.retrofitconverter; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /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 | google() 6 | jcenter() 7 | 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:3.3.1' 11 | 12 | // NOTE: Do not place your application dependencies here; they belong 13 | // in the individual module build.gradle files 14 | } 15 | } 16 | 17 | allprojects { 18 | repositories { 19 | google() 20 | jcenter() 21 | maven { url "https://jitpack.io" } 22 | } 23 | } 24 | 25 | task clean(type: Delete) { 26 | delete rootProject.buildDir 27 | } 28 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | 15 | 16 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magic0908/RetrofitConverterSimple/df2aab577a32770bf3f4ade3cdbb355ceb72b905/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Feb 13 13:23:37 CST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------