Retrofit初接触

引言

最近的一个项目里使用到了现在很火的 Retrofit ,刚接触时就是简单的使用。在需要请求接口的地方定义一个方法,方法体里面写 Retrofit 相关代码,所以基本上每一个需要请求接口的地方都要这样做一次。这样做的后果就是后期再回头看这些代码的时候,就觉得类很乱,代码冗余,难于维护。所以我做了一个简单的封装,经一位大神指点过后(这位大神说我这个封装有点MVP的味道,内心还有点小窃喜),现将整理后的代码贴在这儿,分享给大家。如有觉得不足之处,请大家多多指点,在评论区积极留言,以做讨论。我这也是一个抛砖引玉之举,如果哪位大神还有什么好的使用方法,欢迎在此分享给大家,一起学习,一起进步,谢谢!

一般来说我们使用 Retrofit 必不可少的就是定义一个 interface ,里面定义获取 Call 的方法。之前都是随用随建,几乎每个类里面都有一个。现在我把它拿了出来,作为一个公共的 interface ,在里面写各个接口需要的获取 Call 的方法。

public interface Parser {

/**
 * 添加游客身份
 *
 * @param mParams
 * @return
 */
@FormUrlEncoded
@POST("surfers")
Call<SurferEntry> doParserSurferEntry(@FieldMap Map<String, String> mParams);

/**
 * 获取文章列表
 *
 * @param params
 * @return
 */
@GET("articles")
Call<RecommendEntry> doGetArticles(@QueryMap Map<String, String> params);
}

这步做完之后,我们就该去创建 Retrofit 了,用它来请求接口,获取数据。这里我也是把这个操作放在了一个公共类里,这样我们就只需要创建一次就可以了,不需要在每个地方都去创建一次了。

public class EntryDataParser {

private Context mContext;
private Parser mParser;
private Map<String, String> mParams;
private int DATA_TYPE;
private EntryDataListener mListener;

public EntryDataParser(Context mContext, EntryDataListener mListener) {
    this.mContext = mContext;
    this.mListener = mListener;
}

/**
 * 请求接口,接收返回数据
 *
 * @param DATA_TYPE 接口类型
 * @param mParams   接口参数
 */
public void doParser(int DATA_TYPE, Map<String, String> mParams) {
    this.DATA_TYPE = DATA_TYPE;
    this.mParams = mParams;
    Retrofit retrofit = new Retrofit.Builder().baseUrl(ConstantUtil.BASE_URL)
            .addConverterFactory(GsonConverterFactory.create()).build();
    mParser = retrofit.create(Parser.class);
    switch (DATA_TYPE) {
        case ParserEntry.SURFER_TYPE://添加游客身份
            doCreateSurfer();
            break;

        case ParserEntry.ARTICLE_TYPE://获取文章列表
            doGetArticles();
            break;
    }
}

/**
 * 添加游客身份
 */
private void doCreateSurfer() {
    Call<SurferEntry> call = mParser.doCreateSurfer(mParams);
    call.enqueue(new Callback<SurferEntry>() {
        @Override
        public void onResponse(Call<SurferEntry> call, Response<SurferEntry> response) {
            if (response.isSuccessful()) {
                if (response.body().code == 200) {
                    mListener.doEntryData(DATA_TYPE, response.body());
                } else {
                    PrintUtil.toast(mContext, response.body().msg);
                }
            } else {
                PrintUtil.i("添加游客身份失败: response is unsuccessful");
            }
        }

        @Override
        public void onFailure(Call<SurferEntry> call, Throwable t) {
            PrintUtil.i("添加游客身份失败: " + t.getMessage());
        }
    });
}

/**
 * CommonTestActivity.java
 * 获取文章列表
 */
private void doGetArticles() {
    Call<RecommendEntry> call = mParser.doGetArticles(mParams);
    call.enqueue(new Callback<RecommendEntry>() {
        @Override
        public void onResponse(Call<RecommendEntry> call, Response<RecommendEntry> response) {
            if (response.isSuccessful()) {
                if (response.body().code == 200) {
                    mListener.doEntryData(DATA_TYPE, response.body());
                } else {
                    PrintUtil.toast(mContext, response.body().msg);
                }
            } else {
                PrintUtil.i("获取文章列表失败: response is unsuccessful");
            }
        }

        @Override
        public void onFailure(Call<RecommendEntry> call, Throwable t) {
            PrintUtil.i("获取文章列表失败: " + t.getMessage());
        }
    });
}
}

解释一下各个变量:
Context mContext; 就是上下文,不多解释;
Parser mParser; 就是上面定义的公共 interface ,用来获取 Call ;
Map<String, String> mParams; 就是请求接口所需要的参数;
int DATA_TYPE; 这个参数是用来区分你是要做哪个操作的,比如说添加游客身份和获取文章列表,要传入一个用以区分的 tag 。
EntryDataListener mListener; 这个参数是用来回调接口返回的数据通过 Gson 解析后的实体类的,后面会给出定义。

public class ParserEntry {

//添加游客身份
public static final int SURFER_TYPE = 0;

//获取文章列表
public static final int ARTICLE_TYPE = 1;
}

ParserEntry 类,这个类里定义了上面 EntryDataParser 类里 doParser() 方法里面的 switch() 里对应的 DATA_TYPE ,用以区分你要做什么操作。

public class ParserData {

private Context mContext;
private EntryDataParser parser;

public ParserData(Context mContext, EntryDataListener mListener) {
    this.mContext = mContext;
    this.parser = new EntryDataParser(mContext, mListener);
}

/**
 * 添加游客身份
 */
public void doCreateSurfer() {
    Map<String, String> params = new HashMap<>();
    params.put("deviceId", DeviceUtil.doGetIMEI(mContext));
    parser.doParser(ParserEntry.SURFER_TYPE, params);
}

/**
 * 获取文章列表
 */
public void doGetArticles() {
    Map<String, String> params = new HashMap<>();
    params.put("user", "surfer");
    params.put("fromUid", ShareSaveUtil.doGetSurferId(mContext));
    params.put("flag", "index2");
    params.put("page", String.valueOf(1));
    params.put("limit", ConstantUtil.COMMON_LIMIT);
    parser.doParser(ParserEntry.ARTICLE_TYPE, params);
}
}

ParserData 类,用来实现具体接口的请求操作,里面添加需要的参数。

最后,在 Activity 里面调用,实现接口数据的获取,然后填充界面。

public class CommonTestActivity extends Activity implements EntryDataListener {

private TextView show;
private ParserData data;
private SurferEntry surferEntry;
private RecommendEntry recommendEntry;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_common_test);
    init();
    showView();
}

/**
 * 初始化
 */
private void init() {
    show = findViewById(R.id.text_show);
    data = new ParserData(this, this);
    surferEntry = new SurferEntry();
    recommendEntry = new RecommendEntry();
}

/**
 * 显示UI
 */
private void showView() {
    data.doCreateSurfer();//添加游客身份
}

/**
 * 接收回调实体类
 *
 * @param DATA_TYPE 实体类类型
 */
@Override
public void doEntryData(int DATA_TYPE, Object mObject) {
    switch (DATA_TYPE) {
        case ParserEntry.SURFER_TYPE:
            surferEntry = (SurferEntry) mObject;
            data.doGetArticles();//获取文章列表
            break;

        case ParserEntry.ARTICLE_TYPE:
            recommendEntry = (RecommendEntry) mObject;
            show.setText(surferEntry.toString() + "\n\n" + recommendEntry.toString());
            break;
    }
}
}

其中 SurferEntry 和 RecommendEntry 都是接口数据的实体类,大家看情况自行定义。到此,封装使用完毕。

结束语

这个东西做出来之后自己内心还是有点小欣喜的,因为觉得耦合度降低了很多,Activity 层看上去也简洁了很多。但是一开始用了静态方法和静态变量,经大神指点后,知道了这样做会很容易导致内存泄漏。所以改成了现在这样,这应该是我写代码以来做的一件非常非常有成就感觉的事儿了,哈哈哈,自喜一下。
这里分享出来给大家,一是想方便大家使用 Retrofit ,二来也是希望大家看到之后,如果觉得哪儿还可以改进,能在评论区积极留言,多多指点,因为我也期待着进步嘛,嘿嘿。谢谢大家!

    原文作者:花果山来的猴子
    原文地址: https://www.jianshu.com/p/488ddbc562e7
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞