First, basic packaging

1. Introduction of libraries

//RxJava dependencies
implementation 'the IO. Reactivex. Rxjava3: rxandroid: 3.0.0'
//RxAndroid dependency package
implementation 'the IO. Reactivex. Rxjava3: rxjava: 3.0.0'
//retrofit
implementation 'com. Squareup. Retrofit2: retrofit: 2.9.0'
implementation 'com. Squareup. Retrofit2: converter - gson: 2.9.0'
implementation 'com. Squareup. Retrofit2: converter - scalars: 2.9.0'
implementation  'com. Squareup. Retrofit2: adapter - rxjava3:2.9.0'
//okhttp
implementation 'com. Squareup. Okhttp3: okhttp: 4.9.3'
implementation 'com. Squareup. Okhttp3: logging - interceptor: 4.9.3'
//gson
implementation 'com. Google. Code. Gson: gson: 2.9.0'
//Logger
implementation 'com. Orhanobut: logger: 2.2.0'
Copy the code

2. Basic packaging

There are a lot of resources on the web that I won’t go into detail about. Data calls are now generally in ViewModel modules and then encapsulated in LiveData. This article focuses on Retrofit. This interface is from WanAndroid, thanks to Hongyang God!

Management class ApiManager. Java


public class ApiManager {

    public final String BASE_URL= "https://wanandroid.com/";

    private static ApiManager apiManager;
    private Retrofit retrofit;
    private OkHttpClient client;
    private ApiServer apiServer;

    public static ApiManager getInstance() {
        if (apiManager == null) {
            synchronized (Object.class) {
                if (apiManager == null) {
                    apiManager = newApiManager(); }}}return apiManager;
    }

    public ApiManager() {
        client = new OkHttpClient.Builder()
                // Add a log interceptor
                .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)) / / okhttp default
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .build();

        retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addConverterFactory(ScalarsConverterFactory.create())
                / / support RxJava
                .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
                .client(client)
                .build();

        apiServer = retrofit.create(ApiServer.class);
    }

    public ApiServer getApiService() {
        returnapiServer; }}Copy the code

Returns a parse of the data baseresponse.java

public class BaseResponse<T> {
    private int errorCode;
    private String errorMsg;
    private T data;
}
Copy the code

Baseobserver.java returns the processing of the data

public abstract class BaseObserver<T> extends DisposableObserver<BaseResponse<T>> {

    private boolean isShowDialog;   // Whether Dialog needs to be displayed
    /** * Failed to parse data */
    public static final int PARSE_ERROR = 1001;
    /** * Network problem */
    public static final int BAD_NETWORK = 1002;
    /** * connection error */
    public static final int CONNECT_ERROR = 1003;
    /** * Connection timed out */
    public static final int CONNECT_TIMEOUT = 1004;

    / * * *@param IsShowDialog Whether to display Dialog */
    public BaseObserver(boolean isShowDialog) {
        this.isShowDialog = isShowDialog;
    }

    @Override
    protected void onStart() {
        showLoading();
    }

    @Override
    public void onNext(BaseResponse<T> response) {
        // How to return according to schema customization
        if (response.getErrorCode() == 0) {
            onSuccess(response.getData());
        } else {
            int errorCode = response.getErrorCode();
            String msg = response.getErrorMsg();
            onFail(errorCode, msg, response);
        }
    }

    @Override
    public void onError(Throwable e) {
        dismissDialog();
        if (e instanceof HttpException) {
            / / HTTP error
            onException(BAD_NETWORK);
        } else if (e instanceof ConnectException
                || e instanceof UnknownHostException) {
            // Connection error
            onException(CONNECT_ERROR);
        } else if (e instanceof InterruptedIOException) {
            // Connection timed out
            onException(CONNECT_TIMEOUT);
        } else if (e instanceof JsonParseException
                || e instanceof JSONException
                || e instanceof ParseException) {
            // Parsing error
            onException(PARSE_ERROR);
        } else {
            if(e ! =null) {
                onError(e.toString());
            } else {
                onError("Unknown error");
            }
        }
    }

    private void onException(int unknownError) {
        switch (unknownError) {
            case CONNECT_ERROR:
                onError("Connection error");
                break;

            case CONNECT_TIMEOUT:
                onError("Connection timed out");
                break;

            case BAD_NETWORK:
                onError("Network problems");
                break;

            case PARSE_ERROR:
                onError("Failed to parse data");
                break;

            default:
                break;
        }
    }

    @Override
    public void onComplete() {
        dismissDialog();
    }

    public abstract void onSuccess(T o);

    public abstract void onFail(int errorCode, String errorMsg, BaseResponse<T> response);

    public abstract void onError(String msg);

    /** * display Dialog
    public void showLoading() {
        / / TODO slightly
    }

    /** ** hide Dialog */
    public void dismissDialog() {
        / / TODO slightly}}Copy the code

Interface class ApiServer. Java

public interface ApiServer {

    /** * get the list of articles *@return* /
    @GET("article/list/1/json")
    Observable<BaseResponse<ArticleListResp>> getArticleList();


    /** * get hot word *@return* /
    @GET("hotkey/json")
    Observable<BaseResponse<Object>> getHotKey();

}
Copy the code

Call directly from the Activity, where the LiveData and ViewModel parts are omitted, and encapsulation is easy.

// Get the list of articles
getArticleList()


private void getArticleList() {
    ApiManager.getInstance().getApiService()
            .getArticleList()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new BaseObserver<ArticleListResp>(true) {
                @Override
                public void onSuccess(ArticleListResp resp) {

                }

                @Override
                public void onFail(int errorCode, String errorMsg, BaseResponse<ArticleListResp> response) {

                }

                @Override
                public void onError(String msg){}}); }Copy the code

The following output is displayed:

2022-03-13 14:46:40.210 25122-25154/com.abc.rxjava3 I/okhttp.OkHttpClient: --> GET https://wanandroid.com/article/list/1/json
2022-03-13 14:46:40.210 25122-25154/com.abc.rxjava3 I/okhttp.OkHttpClient: --> END GET
2022-03-13 14:46:40.554 25122-25154/com.abc.rxjava3 I/okhttp.OkHttpClient: <-- 200 OK https://wanandroid.com/article/list/1/json (343ms)
2022-03-13 14:46:40.554 25122-25154/com.abc.rxjava3 I/okhttp.OkHttpClient: Server: Apache-Coyote/1.1
2022-03-13 14:46:40.554 25122-25154/com.abc.rxjava3 I/okhttp.OkHttpClient: Cache-Control: private
2022-03-13 14:46:40.554 25122-25154/com.abc.rxjava3 I/okhttp.OkHttpClient: Expires: Thu, 01 Jan 1970 08:00:00 CST
2022-03-13 14:46:40.554 25122-25154/com.abc.rxjava3 I/okhttp.OkHttpClient: Set-Cookie: JSESSIONID=009E1C654D8D5CD7C889DAFA23A2FB36; Path=/; Secure; HttpOnly
2022-03-13 14:46:40.554 25122-25154/com.abc.rxjava3 I/okhttp.OkHttpClient: Content-Type: application/json;charset=UTF-8
2022-03-13 14:46:40.554 25122-25154/com.abc.rxjava3 I/okhttp.OkHttpClient: Transfer-Encoding: chunked
2022-03-13 14:46:40.554 25122-25154/com.abc.rxjava3 I/okhttp.OkHttpClient: Date: Sun, 13 Mar 2022 06:46:39 GMT
2022-03-13 14:46:40.590 25122-25154/com.abc.rxjava3 I/okhttp.OkHttpClient: {"data":{"curPage":2,"datas":[{"apkLink":"","audit":1,"author":"","canEdit":false,"chapterId":502,"chapterName":"自助","collect":false,"courseId":13,"desc":"","descMd":"","envelopePic":"","fresh":false,"host":"","id":21691,"link":"https://juejin.cn/post/7072613093502615588","niceDate":"2022-03-08 21:40","niceShareDate":"2022-03-08 21:40","origin":"","prefix":"","projectLink":"","publishTime":1646746858000,"realSuperChapterId":493,"selfVisible":0,"shareDate":1646746834000,"shareUser":"鸿洋","superChapterId":494,"superChapterName":"广场Tab","tags":[],"title":"Android设备里的那些事儿|硬核科普","type":0,"userId":2,"visible":1,"zan":0},{"apkLink":"","audit":1,"author":"","canEdit":false,"chapterId":502,"chapterName":"自助","collect":false,"courseId":13,"desc":"","descMd":"","envelopePic":"","fresh":false,"host":"","id":21690,"link":"https://mp.weixin.qq.com/s/e1p9QdnCv-fFXgzO4XI74g","niceDate":"2022-03-08 21:40","niceShareDate":"2022-03-08 20:28","origin":"","prefix":"","projectLink":"","publishTime":1646746857000,"realSuperChapterId":493,"selfVisible":0,"shareDate":1646742494000,"shareUser":"趣阅编程","superChapterId":494,"superChapterName":"广场Tab","tags":[],"title":"Android 性能优化 - 通过 ASM 实现大图监控","type":0,"userId":13273,"visible":1,"zan":0},{"apkLink":"","audit":1,"author":"","canEdit":false,"chapterId":502,"chapterName":"自助","collect":false,"courseId":13,"desc":"","descMd":"","envelopePic":"","fresh":false,"host":"","id":21692,"link":"https://juejin.cn/post/7072541180667363358","niceDate":"2022-03-08 21:40","niceShareDate":"2022-03-08 21:40","origin":"","prefix":"","projectLink":"","publishTime":1646746853000,"realSuperChapterId":493,"selfVisible":0,"shareDate":1646746843000,"shareUser":"鸿洋","superChapterId":494,"superChapterName":"广场Tab","tags":[],"title":"CreationExtras 来了,创建 ViewModel 的新方式","type":0,"userId":2,"visible":1,"zan":0},{"apkLink":"","audit":1,"author":"","canEdit":false,"chapterId":502,"chapterName":"自助","collect":false,"courseId":13,"desc":"","descMd":"","envelopePic":"","fresh":false,"host":"","id":21688,"link":"https://juejin.cn/post/7072263857015619621","niceDate":"2022-03-08 09:12","niceShareDate":"2022-03-08 09:12","origin":"","prefix":"","projectLink":"","publishTime":1646701954000,"realSuperChapterId":493,"selfVisible":0,"shareDate":1646701954000,"shareUser":"易保山","superChapterId":494,"superChapterName":"广场Tab","tags":[],"title":"从Android源码角度谈设计模式(三):行为型模式","type":0,"userId":47679,"visible":1,"zan":0},{"apkLink":"","audit":1,"author":"","canEdit":false,"chapterId":502,"chapterName":"自助","collect":false,"courseId":13,"desc":"","descMd":"","envelopePic":"","fresh":false,"host":"","id":21687,"link":"https://juejin.cn/post/7051139976095858725","niceDate":"2022-03-08 09:12","niceShareDate":"2022-03-08 09:12","origin":"","prefix":"","projectLink":"","publishTime":1646701924000,"realSuperChapterId":493,"selfVisible":0,"shareDate":1646701924000,"shareUser":"易保山","superChapterId":494,"superChapterName":"广场Tab","tags":[],"title":"从Android源码角度谈设计模式(二):结构型模式","type":0,"userId":47679,"visible":1,"zan":0},{"apkLink":"","audit":1,"author":"","canEdit":false,"chapterId":502,"chapterName":"自助","collect":false,"courseId":13,"desc":"","descMd":"","envelopePic":"","fresh":false,"host":"","id":21686,"link":"https://juejin.cn/post/7043951828144226341","niceDate":"2022-03-08 09:11","niceShareDate":"2022-03-08 09:11","origin":"","prefix":"","projectLink":"","publishTime":1646701884000,"realSuperChapterId":493,"selfVisible":0,"shareDate":1646701884000,"shareUser":"易保山","superChapterId":494,"superChapterName":"广场Tab","tags":[],"title":"从Android源码角度谈设计模式(一):创建型模式","type":0,"userId":47679,"visible":1,"zan":0},{"apkLink":"","audit":1,"author":"鸿洋","canEdit":false,"chapterId":408,"chapterName":"鸿洋","collect":false,"courseId":13,"desc":"",
2022-03-13 14:46:40.590 25122-25154/com.abc.rxjava3 I/okhttp.OkHttpClient: "","publishTime":1646668800000,"realSuperChapterId":407,"selfVisible":0,"shareDate":1646748567000,"shareUser":"","superChapterId":408,"superChapterName":"公众号","tags":[{"name":"公众号","url":"/wxarticle/list/408/1"}],"title":"写了个适配检查工具,一键发现适配问题!","type":0,"userId":-1,"visible":1,"zan":0},{"apkLink":"","audit":1,"author":"Android群英传","canEdit":false,"chapterId":413,"chapterName":"Android群英传","collect":false,"courseId":13,"desc":"","descMd":"","envelopePic":"","fresh":false,"host":"","id":21694,"link":"https://mp.weixin.qq.com/s/z1mV_NLtnKjFuvoIAA2SRA","niceDate":"2022-03-08 00:00","niceShareDate":"2022-03-08 22:09","origin":"","prefix":"","projectLink":"","publishTime":1646668800000,"realSuperChapterId":407,"selfVisible":0,"shareDate":1646748580000,"shareUser":"","superChapterId":408,"superChapterName":"公众号","tags":[{"name":"公众号","url":"/wxarticle/list/413/1"}],"title":"Flutter布局指南之谁动了我的Key","type":0,"userId":-1,"visible":1,"zan":0},{"apkLink":"","audit":1,"author":"郭霖","canEdit":false,"chapterId":409,"chapterName":"郭霖","collect":false,"courseId":13,"desc":"","descMd":"","envelopePic":"","fresh":false,"host":"","id":21695,"link":"https://mp.weixin.qq.com/s/qGUGuCR4sXDifVnegmKrew","niceDate":"2022-03-08 00:00","niceShareDate":"2022-03-08 22:09","origin":"","prefix":"","projectLink":"","publishTime":1646668800000,"realSuperChapterId":407,"selfVisible":0,"shareDate":1646748592000,"shareUser":"","superChapterId":408,"superChapterName":"公众号","tags":[{"name":"公众号","url":"/wxarticle/list/409/1"}],"title":"Compose 的 State 状态到底是个啥?","type":0,"userId":-1,"visible":1,"zan":0},{"apkLink":"","audit":1,"author":"Afauria","canEdit":false,"chapterId":539,"chapterName":"未分类","collect":false,"courseId":13,"desc":"基于GitHub开源项目https://github.com/fengwensheng/getx_wanandroid开发。主要用于学习GetX框架、FlutterUI等","descMd":"","envelopePic":"https://www.wanandroid.com/blogimgs/eebdcecf-15e4-4895-a75a-725121807f75.png","fresh":false,"host":"","id":21683,"link":"https://www.wanandroid.com/blog/show/3150","niceDate":"2022-03-07 21:35","niceShareDate":"2022-03-07 21:35","origin":"","prefix":"","projectLink":"https://github.com/Afauria/Flutter-WanAndroid","publishTime":1646660138000,"realSuperChapterId":293,"selfVisible":0,"shareDate":1646660138000,"shareUser":"","superChapterId":294,"superChapterName":"开源项目主Tab","tags":[{"name":"项目","url":"/project/list/1?cid=539"}],"title":"GetX-WanAndroid","type":0,"userId":-1,"visible":1,"zan":0},{"apkLink":"","audit":1,"author":"","canEdit":false,"chapterId":502,"chapterName":"自助","collect":false,"courseId":13,"desc":"","descMd":"","envelopePic":"","fresh":false,"host":"","id":21674,"link":"https://juejin.cn/post/7071964490459250724","niceDate":"2022-03-07 21:25","niceShareDate":"2022-03-06 23:18","origin":"","prefix":"","projectLink":"","publishTime":1646659522000,"realSuperChapterId":493,"selfVisible":0,"shareDate":1646579920000,"shareUser":"深红骑士","superChapterId":494,"superChapterName":"广场Tab","tags":[],"title":"引用还是传值&mdash;&mdash;被打脸后才发现多年的理解是错的","type":0,"userId":29303,"visible":1,"zan":0},{"apkLink":"","audit":1,"author":"","canEdit":false,"chapterId":502,"chapterName":"自助","collect":false,"courseId":13,"desc":"","descMd":"","envelopePic":"","fresh":false,"host":"","id":21675,"link":"https://juejin.cn/post/7069013946929250311","niceDate":"2022-03-07 21:25","niceShareDate":"2022-03-06 23:23","origin":"","prefix":"","projectLink":"","publishTime":1646659520000,"realSuperChapterId":493,"selfVisible":0,"shareDate":1646580231000,"shareUser":"goweii","superChapterId":494,"superChapterName":"广场Tab","tags":[],"title":"Binder机制和AIDL的理解","type":0,"userId":20382,"visible":1,"zan":0},{"apkLink":"","audit":1,"author":"","canEdit":false,"chapterId":502,"chapterName":"自助","collect":false,"courseId":13,"desc":"","descMd
2022-03-13 14:46:40.590 25122-25154/com.abc.rxjava3 I/okhttp.OkHttpClient: e":1646659511000,"realSuperChapterId":493,"selfVisible":0,"shareDate":1646627793000,"shareUser":"古诚欺","superChapterId":494,"superChapterName":"广场Tab","tags":[],"title":"Mvi架构模式开发","type":0,"userId":127711,"visible":1,"zan":0},{"apkLink":"","audit":1,"author":"","canEdit":false,"chapterId":502,"chapterName":"自助","collect":false,"courseId":13,"desc":"","descMd":"","envelopePic":"","fresh":false,"host":"","id":21680,"link":"https://juejin.cn/post/7072020104212381732","niceDate":"2022-03-07 19:51","niceShareDate":"2022-03-07 19:51","origin":"","prefix":"","projectLink":"","publishTime":1646653919000,"realSuperChapterId":493,"selfVisible":0,"shareDate":1646653919000,"shareUser":"彭旭锐","superChapterId":494,"superChapterName":"广场Tab","tags":[],"title":"Android UI 架构演进:从 MVC 到 MVP、MVVM、MVI","type":0,"userId":30587,"visible":1,"zan":0},{"apkLink":"","audit":1,"author":"","canEdit":false,"chapterId":502,"chapterName":"自助","collect":false,"courseId":13,"desc":"","descMd":"","envelopePic":"","fresh":false,"host":"","id":21679,"link":"https://blog.csdn.net/zxm528/article/details/122351407?spm=1001.2014.3001.5501","niceDate":"2022-03-07 18:04","niceShareDate":"2022-03-07 18:04","origin":"","prefix":"","projectLink":"","publishTime":1646647441000,"realSuperChapterId":493,"selfVisible":0,"shareDate":1646647441000,"shareUser":"zxm528","superChapterId":494,"superChapterName":"广场Tab","tags":[],"title":"Flutter从0到1开发一个app:知天气","type":0,"userId":3487,"visible":1,"zan":0},{"apkLink":"","audit":1,"author":"","canEdit":false,"chapterId":502,"chapterName":"自助","collect":false,"courseId":13,"desc":"","descMd":"","envelopePic":"","fresh":false,"host":"","id":21676,"link":"https://mp.weixin.qq.com/s?__biz=MzU5NjkxMjE5Mg==&amp;mid=2247484594&amp;idx=1&amp;sn=bd31cddb9e6854e1afe7a7e024d6303f&amp;chksm=fe5a359dc92dbc8b751f75be4fe90c891658b3528fc2ee531fefb2a74bf4c88625883279b3b9&amp;token=994800008&amp;lang=zh_CN#rd","niceDate":"2022-03-07 08:31","niceShareDate":"2022-03-07 08:31","origin":"","prefix":"","projectLink":"","publishTime":1646613101000,"realSuperChapterId":493,"selfVisible":0,"shareDate":1646613101000,"shareUser":"音视频开发之旅","superChapterId":494,"superChapterName":"广场Tab","tags":[],"title":"学习实践CMake","type":0,"userId":107131,"visible":1,"zan":0},{"apkLink":"","audit":1,"author":"鸿洋","canEdit":false,"chapterId":408,"chapterName":"鸿洋","collect":false,"courseId":13,"desc":"","descMd":"","envelopePic":"","fresh":false,"host":"","id":21682,"link":"https://mp.weixin.qq.com/s/GFDSPHUuUxUKuAogR0XZ4Q","niceDate":"2022-03-07 00:00","niceShareDate":"2022-03-07 21:31","origin":"","prefix":"","projectLink":"","publishTime":1646582400000,"realSuperChapterId":407,"selfVisible":0,"shareDate":1646659894000,"shareUser":"","superChapterId":408,"superChapterName":"公众号","tags":[{"name":"公众号","url":"/wxarticle/list/408/1"}],"title":"让自定义View更加优雅的一个技巧!","type":0,"userId":-1,"visible":1,"zan":0},{"apkLink":"","audit":1,"author":"fmtjava","canEdit":false,"chapterId":539,"chapterName":"未分类","collect":false,"courseId":13,"desc":"基于微信小程序实现的一款精美仿开眼视频小程序(提供Flutter、Kotlin、ReactNative版本 :grin: )","descMd":"","envelopePic":"https://www.wanandroid.com/blogimgs/ebdbc335-0ff9-4e9a-9822-edb8ecccefb0.png","fresh":false,"host":"","id":21672,"link":"https://www.wanandroid.com/blog/show/3148","niceDate":"2022-03-06 22:24","niceShareDate":"2022-03-06 22:24","origin":"","prefix":"","projectLink":"https://github.com/fmtjava/wx_eyepetizer","publishTime":1646576675000,"realSuperChapterId":293,"selfVisible":0,"shareDate":1646576675000,"shareUser":"","superChapterId":294,"superChapterName":"开源项目主Tab","tags":[{"name":"项目","url":"/project/list/1?cid=539"}],"title":"基于微信小程序实现的一款精美仿开眼视频小程序(提供Flutter、Kotlin、ReactNative版本 😁 )","type":0,"userId":-1,"visible":
2022-03-13 14:46:40.590 25122-25154/com.abc.rxjava3 I/okhttp.OkHttpClient: cMd":"","envelopePic":"https://www.wanandroid.com/resources/image/pc/default_project_img.jpg","fresh":false,"host":"","id":21673,"link":"https://www.wanandroid.com/blog/show/3149","niceDate":"2022-03-06 22:21","niceShareDate":"2022-03-06 22:21","origin":"","prefix":"","projectLink":"https://github.com/ZuYun/pageviewj","publishTime":1646576485000,"realSuperChapterId":293,"selfVisible":0,"shareDate":1646576485000,"shareUser":"","superChapterId":294,"superChapterName":"开源项目主Tab","tags":[{"name":"项目","url":"/project/list/1?cid=539"}],"title":"flutter中viewpager的各种页面切换效果","type":0,"userId":-1,"visible":1,"zan":0},{"apkLink":"","audit":1,"author":"iDeMonnnnnn","canEdit":false,"chapterId":539,"chapterName":"未分类","collect":false,"courseId":13,"desc":"Activity Results API自动化注册&amp;极简使用方案。\r\n只调用一个带回调的函数实现startActivityForResult()/onActivityResult()。","descMd":"","envelopePic":"https://www.wanandroid.com/resources/image/pc/default_project_img.jpg","fresh":false,"host":"","id":21671,"link":"https://www.wanandroid.com/blog/show/3147","niceDate":"2022-03-06 22:17","niceShareDate":"2022-03-06 22:17","origin":"","prefix":"","projectLink":"https://github.com/iDeMonnnnnn/DeMon-ARA","publishTime":1646576224000,"realSuperChapterId":293,"selfVisible":0,"shareDate":1646576224000,"shareUser":"","superChapterId":294,"superChapterName":"开源项目主Tab","tags":[{"name":"项目","url":"/project/list/1?cid=539"}],"title":"Activity Results API自动化注册&amp;极简使用方案","type":0,"userId":-1,"visible":1,"zan":0}],"offset":20,"over":false,"pageCount":599,"size":20,"total":11970},"errorCode":0,"errorMsg":""}
2022-03-13 14:46:40.590 25122-25154/com.abc.rxjava3 I/okhttp.OkHttpClient: <-- END HTTP (14586-byte body)
Copy the code

Second, log processing

Hope that the log can locate the problem point, so it is suggested to introduce a more powerful log library Logger–Simple, Pretty and Powerful Logger for Android, now has more than thirteen thousand stars, or more trustworthy.

1. Encapsulate the logging utility class

Basic encapsulation of log libraries

/** * Log class */
public class LogUtil {

    private static final String LOG_TAG = "SHOW_LOG";
    private static final String DEBUG = "debug";

    /** * Initialize the log tool by calling */ at the app entrance
    public static void init() {
        FormatStrategy formatStrategy = PrettyFormatStrategy.newBuilder()
                .showThreadInfo(true)  // (Optional) Whether to show thread info or not. Default true
                .methodCount(0)         // (Optional) How many method line to show. Default 2
                .methodOffset(5)        // (Optional) Hides internal method calls up to offset. Default 5
                .logStrategy(new LogcatLogStrategy()) // (Optional) Changes the log strategy to print out. Default LogCat
                .tag(LOG_TAG)   // (Optional) Global tag for every log. Default PRETTY_LOGGER
                .build();

        Logger.addLogAdapter(new AndroidLogAdapter(formatStrategy) {
            @Override
            public boolean isLoggable(int priority, @Nullable String tag) {
                // Use system buildconfig. DEBUG(default true), not Logger library buildconfig. DEBUG(default false)
                //true: logs are printed false: logs are not printed
                returnBuildConfig.BUILD_TYPE.equals(DEBUG); }}); } publicstatic void d(String message) {
        Logger.d(message);
    }

    public static void i(String message) {
        Logger.i(message);
    }

    / * * * LogHelper getStackTraceAsString (e) print the complete Exception information, the Logger can locate the position of the Exception * e. oString can print the Exception information, You cannot locate Exception *@param e* /
    public static void w(Throwable e) {
         Stringinfo = e ! =null ? LogHelper.getStackTraceAsString(e) : "null";
        Logger.w(info);
    }

    / * * * LogHelper getStackTraceAsString (e) print the complete Exception information, the Logger can locate the position of the Exception * e. oString can print the Exception information, You cannot locate Exception *@param e* /
    public static void e(Throwable e) {
        Stringinfo = e ! =null ? LogHelper.getStackTraceAsString(e) : "null";
        Logger.e(info);
    }

    public static void json(String json){ Logger.json(json); }}Copy the code

LogHelper.java

public class LogHelper {
    /** * convert exception stack *@param throwable
     * @return* /
    public static String getStackTraceAsString(Throwable throwable) {
        StringWriter writer = new StringWriter();
        throwable.printStackTrace(new PrintWriter(writer));
        returnwriter.toString(); }}Copy the code

Print a NullPointerException that locates Exception, not e.tostring ()

2. Print a formatted Log

Logs are messy to print in Android Studio, and if you’re careful, you’ll notice that characters are lost between logs when they’re too long. See log input above:

If logutil.d (message) is called directly in the log method of LoggerHttp, the printed log is scattered because the log method prints the request-response lines and headers of a network request. The desired effect, however, is to combine all information about the same network request and response into one log so that it can be easily viewed during debugging. So you need to do some logic in the log method of LoggerHttp:

public class HttpLogger implements HttpLoggingInterceptor.Logger {
    private StringBuffer mMessage = new StringBuffer();
    @Override
    public void log(@NotNull String message) {

            // The request or response begins
            if (message.startsWith("--> POST")) {
                mMessage.setLength(0);
            }
            // Statements in the form {} or [] are JSON data for the response result and need to be formatted
            if ((message.startsWith("{") && message.endsWith("}"))
                    || (message.startsWith("[") && message.endsWith("]"))) {
                message = JsonUtil.formatJson(JsonUtil.decodeUnicode(message));
            }
            mMessage.append(message.concat("\n"));
            // The response ends, and the entire log is printed
            if (message.startsWith("<-- END HTTP")) {
                LogUtil.d(mMessage.toString());
                / / remove
                mMessage.setLength(0); }}}Copy the code

The looger library’s looger. json(String json) method is not used here to print JSON data because this method call is also printed as a separate log and it is not possible to put all requested information in one log. JsonUtil is a separate packaged tool for formatting JSON strings into a clear hierarchy using formatJson(String JSON).

/** * Format json string **@param JsonStr Json string * to be formatted@return Formatted JSON string */
public static String formatJson(String jsonStr) {
    if (null == jsonStr || "".equals(jsonStr)) return "";
    StringBuilder sb = new StringBuilder();
    char last = '\ 0';
    char current = '\ 0';
    int indent = 0;
    for (int i = 0; i < jsonStr.length(); i++) {
        last = current;
        current = jsonStr.charAt(i);
        // a {[line break is encountered and the next line is indented
        switch (current) {
            case '{':
            case '[':
                sb.append(current);
                sb.append('\n');
                indent++;
                addIndentBlank(sb, indent);
                break;
            }] line break, current line indent
            case '} ':
            case '] ':
                sb.append('\n');
                indent--;
                addIndentBlank(sb, indent);
                sb.append(current);
                break;
            // encountered, newline
            case ', ':
                sb.append(current);
                if(last ! ='\ \') {
                    sb.append('\n');
                    addIndentBlank(sb, indent);
                }
                break;
            default: sb.append(current); }}return sb.toString();
}

/** * add space **@param sb
 * @param indent* /
private static void addIndentBlank(StringBuilder sb, int indent) {
    for (int i = 0; i < indent; i++) {
        sb.append('\t'); }}Copy the code

DecodeUnicode (String JSON) is to convert the Unicode encoding in JSON to the Chinese character encoding (The Chinese characters in the Unicode encoding JSON may be printed out as a String beginning with \ U, so it needs to be processed).

  /** ** HTTP request data returns JSON in which Chinese characters are converted to Unicode characters **@param theString
     * @return The transformed result. */
    public static String decodeUnicode(String theString) {
        char aChar;
        int len = theString.length();
        StringBuffer outBuffer = new StringBuffer(len);
        for (int x = 0; x < len; ) {
            aChar = theString.charAt(x++);
            if (aChar == '\ \') {
                aChar = theString.charAt(x++);
                if (aChar == 'u') {
                    int value = 0;
                    for (int i = 0; i < 4; i++) {
                        aChar = theString.charAt(x++);
                        switch (aChar) {
                            case '0':
                            case '1':
                            case '2':
                            case '3':
                            case '4':
                            case '5':
                            case '6':
                            case '7':
                            case '8':
                            case '9':
                                value = (value << 4) + aChar - '0';
                                break;
                            case 'a':
                            case 'b':
                            case 'c':
                            case 'd':
                            case 'e':
                            case 'f':
                                value = (value << 4) + 10 + aChar - 'a';
                                break;
                            case 'A':
                            case 'B':
                            case 'C':
                            case 'D':
                            case 'E':
                            case 'F':
                                value = (value << 4) + 10 + aChar - 'A';
                                break;
                            default:
                                throw new IllegalArgumentException(
                                        "Malformed \\uxxxx encoding.");
                        }

                    }
                    outBuffer.append((char) value);
                } else {
                    if (aChar == 't')
                        aChar = '\t';
                    else if (aChar == 'r')
                        aChar = '\r';
                    else if (aChar == 'n')
                        aChar = '\n';
                    else if (aChar == 'f')
                        aChar = '\f'; outBuffer.append(aChar); }}else
                outBuffer.append(aChar);
        }
        return outBuffer.toString();
    }
Copy the code

Replace the log interceptor

// Add a log interceptor
/ / addInterceptor (new HttpLoggingInterceptor () setLevel (HttpLoggingInterceptor. Level. BODY)) / / okhttp default
.addInterceptor(new HttpLoggingInterceptor(new HttpLogger()).setLevel(HttpLoggingInterceptor.Level.BODY)) 
Copy the code

Printing effect

2022-03-13 19:10:35.997 30574-30605/com.abc.rxjava3 D/SHOW_LOG: ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─2022-03-13 19:10:35.998 30574-30605/com.abc. Rxjava3 D/SHOW_LOG: Thread: OkHttp HTTPS: /com.abc. Rxjava3 D/SHOW_LOG: OkHttp: /com.abc.//wanandroid.com/...
2022-03-13 19:10:35.998 30574-30605/com.abc.rxjava3 D/SHOW_LOG: ├ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄2022-03-13 19:10:35.998 30574-30605/com.abc.rxjava3 D/SHOW_LOG: │ --> GET HTTPS: /com.abc.rxjava3 D/SHOW_LOG://wanandroid.com/hotkey/json
2022-03-13 19:10:35.998 30574-30605/com.abc.rxjava3 D/SHOW_LOG: │ --> END GET
2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │ < --200 OK https:/ / wanandroid.com/hotkey/json (304 ms) < -- -- -- -- -- -- -- request time
2022-03-13 19:10:35.998 30574-30605/com.abc.rxjava3 D/SHOW_LOG: │ Server: apache-coyote /1.1
2022-03-13 19:10:35.998 30574-30605/com.abc.rxjava3 D/SHOW_LOG: │ Cache-Control: private
2022-03-13 19:10:35.998 30574-30605/com.abc.rxjava3 D/SHOW_LOG: │ Expires: Thu, 01 Jan 1970 08:00:00 CST
2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │Set-Cookie: JSESSIONID=D5E28B310AAF0666F28E6A44FA409894; Path=/; Secure; HttpOnly
2022-03-13 19:10:35.998 30574-30605/com.abc.rxjava3 D/SHOW_LOG: │ content-type: Application /json; charset=UTF-8
2022-03-13 19:10:35.998 30574-30605/com.abc.rxjava3 D/SHOW_LOG: │ Transfer-Encoding: chunked
2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │Date: Sun, 13 Mar 2022 11:10:35 GMT
2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │ {2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"data": [2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │ {2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"id":6.2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"link":"".2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"name":"The interview".2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"order":1.2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"visible":1
2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │},2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │ {2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"id":9.2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"link":"".2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"name":"Studio3".2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"order":1.2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"visible":1
2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │},2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │ {2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"id":5.2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"link":"".2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"name":"Animation".2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"order":2.2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"visible":1
2022-03-13 19:10:35.998 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │},2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │ {2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"id":1.2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"link":"".2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"name":"Custom View".2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"order":3.2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"visible":1
2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │},2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │ {2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"id":2.2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"link":"".2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"name":"Performance optimization speed".2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"order":4.2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"visible":1
2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │},2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │ {2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"id":3.2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"link":"".2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"name":"gradle".2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"order":5.2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"visible":1
2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │},2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │ {2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"id":4.2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"link":"".2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"name":"Camera Camera".2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"order":6.2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"visible":1
2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │},2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │ {2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"id":7.2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"link":"".2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"name":"Code confusion security".2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"order":7.2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"visible":1
2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │},2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │ {2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"id":8.2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"link":"".2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"name":"Reverse reinforcement".2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"order":8.2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"visible":1
2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │}2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │].2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"errorCode":0.2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │"errorMsg":""
2022-03-13 19:10:35.999 30574-30605/ / com. ABC. Rxjava3 D SHOW_LOG: │}2022-03-13 19:10:35.999 30574-30605/com.abc.rxjava3 D/SHOW_LOG: │ <-- END HTTP (599-byte body)
2022-03-13 19:10:35.999 30574-30605/com.abc.rxjava3 D/SHOW_LOG: └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─Copy the code

There is a problem with this output, however. When multiple interfaces are requested at the same time, the printing may overlap, but it is generally more convenient in use.

3. Multi-baseurl processing

1. Method 1: Multiple Retrofit object encapsulation

public class ApiManager {

    public final String BASE_URL= "https://wanandroid.com/";
    public final String BASE_URL_2= "https://www.baidu.com/";

    private static ApiManager apiManager;
    private Retrofit retrofit;
    private Retrofit retrofit2;
    private OkHttpClient client;
    private ApiServer apiServer;
    private ApiServer apiServer2;

    public static ApiManager getInstance() {
        if (apiManager == null) {
            synchronized (Object.class) {
                if (apiManager == null) {
                    apiManager = newApiManager(); }}}return apiManager;
    }

    public ApiManager() {
        client = new OkHttpClient.Builder()
                // Add a log interceptor
                / / addInterceptor (new HttpLoggingInterceptor () setLevel (HttpLoggingInterceptor. Level. BODY)) / / okhttp default
                .addInterceptor(new HttpLoggingInterceptor(new HttpLogger()).setLevel(HttpLoggingInterceptor.Level.BODY))
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .build();

        retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addConverterFactory(ScalarsConverterFactory.create())
                / / support RxJava
                .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
                .client(client)
                .build();

        retrofit2 = new Retrofit.Builder()
                .baseUrl(BASE_URL_2)
                .addConverterFactory(GsonConverterFactory.create())
                .addConverterFactory(ScalarsConverterFactory.create())
                / / support RxJava
                .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
                .client(client)
                .build();

        apiServer = retrofit.create(ApiServer.class);

        apiServer2 = retrofit2.create(ApiServer.class);
    }

    public ApiServer getApiService() {
        return apiServer;
    }

    public ApiServer getApiService2() {
        returnapiServer2; }}Copy the code

use

ApiManager. GetInstance (). GetApiService () or ApiManager. GetInstance (). GetApiService2 ()Copy the code

Method 2: Check the head from the Interceptor

Retrofit2+ RxHeaders = Retrofit2+ RxHeaders = Retrofit2+ RxHeaders = Retrofit2+ RxHeaders = Retrofit2+ RxHeaders = Retrofit2+ RxHeaders This type of interceptor precedes the log interceptor. This method is not recommended. Although it can be implemented, printing logs may cause problems.

3. Method three: Use reflection

Repackage ApiManager


public class ApiManager {

    public static final String[] BASE_URL_SRR = {
            "https://www.baidu.com/"."https://wanandroid.com/"."https://www.juejin.com/"
    };

    private static ApiManager apiManager;
    private Retrofit retrofit;
    private Retrofit retrofitTwo;
    private OkHttpClient client;
    private ApiServer apiServer;

    public static ApiManager getInstance() {
        if (apiManager == null) {
            synchronized (Object.class) {
                if (apiManager == null) {
                    apiManager = newApiManager(); }}}return apiManager;
    }

    public ApiManager() {
        client = new OkHttpClient.Builder()
                // Add a log interceptor
                .addInterceptor(new HttpLoggingInterceptor(new HttpLogger()).setLevel(HttpLoggingInterceptor.Level.BODY))
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .build();

        Retrofit.Builder builder = new Retrofit.Builder()
                .baseUrl(BASE_URL_SRR[0])
                .addConverterFactory(GsonConverterFactory.create())
                .addConverterFactory(ScalarsConverterFactory.create())
                / / support RxJava
                .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
                .client(client);
        / / the default
        retrofit = builder.build();
        // For reflection modify BaseUrl
        retrofitTwo = builder.build();

        apiServer = retrofit.create(ApiServer.class);
    }

    public ApiServer getApiService() {
        return apiServer;
    }

    /** * Reflection modifies BaseUrl, encapsulating as required *@param IsChangeBaseUrl true The value needs to be changed. False The value does not need *@param BaseUrlIndex Array index of baseUrl *@return* /
    public ApiServer getApiService(boolean isChangeBaseUrl, int baseUrlIndex) {
        if (isChangeBaseUrl) {
            if (baseUrlIndex < ApiManager3.BASE_URL_SRR.length) {
                try {
                    Field baseUrl = retrofitTwo.getClass().getDeclaredField("baseUrl");
                    baseUrl.setAccessible(true);
                    HttpUrl newBaseUrl = HttpUrl.parse(ApiManager.BASE_URL_SRR[baseUrlIndex]);
                    baseUrl.set(retrofitTwo, newBaseUrl);
                    return retrofitTwo.create(ApiServer.class);
                } catch(Exception e) { e.printStackTrace(); }}}returnapiServer; }}Copy the code

The principle is to take the Retrofit object’s parameter baseUrl and reset it by reflection.

call

ApiManager.getInstance().getApiService(true.1)  // We need to modify baseUrl with the index 1 in the array
        .getHotKey()
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new BaseObserver<Object> (false) {
            @Override
            public void onSuccess(Object resp) {

            }

            @Override
            public void onFail(int errorCode, String errorMsg, BaseResponse<Object> response) {

            }

            @Override
            public void onError(String msg){}});Copy the code

4. Method 4: Use third-party libraries

This is an older library, but you can still use retrofit Manager. See the documentation for the usage.

Refresh expired tokens

1. Method 1: Through interceptors


public class TokenRefreshInterceptor implements Interceptor {
    @NotNull
    @Override
    public Response intercept(@NotNull Chain chain) throws IOException {
        Request request = chain.request();
        Response response = chain.proceed(request);

        if(response.body() ! =null) {
            BufferedSource buffer = Okio.buffer(response.body().source());
            String jsonString = buffer.readUtf8();

            try {
                JSONObject object = new JSONObject(jsonString);
                int errorCode = object.getInt("errorCode");
                if (errorCode == 202) {
                    // The token needs to be refreshed
                    OkHttpClient client = new OkHttpClient.Builder()
                            // .addInterceptor(new LogInterceptor())
                            // Disable the proxy
                            .proxy(Proxy.NO_PROXY)
                            .connectTimeout(10, TimeUnit.SECONDS)
                            .readTimeout(10, TimeUnit.SECONDS)
                            .build();

                    Retrofit retrofit = new Retrofit.Builder()
                            .baseUrl(ApiManager.BASE_URL)
                            // Add a custom parser
                            / / support RxJava2
                            .addConverterFactory(GsonConverterFactory.create())
                            .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
                            .client(client)
                            .build();

                    ApiServer apiServer = retrofit.create(ApiServer.class);

                    // Synchronize the request
                    Response tokenResponse = apiServer.refreshToken().execute();
                    if(tokenResponse.body() ! =null) {
                        / / save the token
                        TokenCommon.saveToken(tokenResponse.body().get("token"));
                        TokenCommon.saveRefreshToken(tokenResponse.body().get("refreshToken"));

                        / / add a token
                        Request newRequest = request.newBuilder()
                                .addHeader("Authorization"."Bearer " + TokenCommon.getToken())
                                .build();
                        response.close();
                        try {
                            return chain.proceed(newRequest);
                        } catch(IOException e) { e.printStackTrace(); }}}}catch(JSONException e) { e.printStackTrace(); }}returnresponse; }}Copy the code

Method 2: the retryWhen operator of Rxjava

In the future, Rxjava usage scenarios will be detailed, which is omitted here.

Thanks for referring to the following article:

Use Logger to print complete OKHTTP network request and response logs

【Android architecture 】 Retrofit2+RXjava encapsulation based on MVP mode

MVP mode Retrofit2+RXjava package Token refresh (8)

— Personal study notes