Retorfit2在项目中的使用
这是我的Github地址:https://github.com/brokes6
我的博客:https://brokes6.github.io/
本篇已Java为主要语言
下面的代码为了方便,我将已我之前写的高仿B站的网络请求来进行讲解
源码地址 欢迎大家来star
-
添加依赖
implementation 'com.squareup.retrofit2:retrofit:2.6.0' implementation 'com.squareup.retrofit2:converter-gson:2.4.0' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
版本可能与官网版本存在不同,以官网为主
-
一般来说,使用了Retorfit2来进行网络请求,都会创建一个类用来进行retorfit初始化和一个接口文档来进行请求,下面我将创建一个“ApiEngine”类
public class ApiEngine { private volatile static ApiEngine apiEngine; private Retrofit retrofit; private ApiEngine() { //添加网络拦截器 NetWorkInterceptor netWorkInterceptor = new NetWorkInterceptor(); //解析返回结果的Interceptor ResponseInterceptor responseInterceptor = new ResponseInterceptor(); ClearableCookieJar cookieJar = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(MyApplication.getContext())); //拦截器 OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(20, TimeUnit.SECONDS) .readTimeout(20, TimeUnit.SECONDS) .writeTimeout(20, TimeUnit.SECONDS) .addNetworkInterceptor(netWorkInterceptor) .addInterceptor(responseInterceptor) .addInterceptor(new AddCookiesInterceptor()) //下面这里是添加了自己定义的每次请求都会添加上Cookies .addInterceptor(new ReceivedCookiesInterceptor()) .cookieJar(cookieJar) .build(); Gson gson = new Gson(); //开启retrofit retrofit = new Retrofit.Builder() //指定主url .baseUrl(ApiService.BASE_URL) //指定拦截器 .client(client) //指定使用Gson解析 .addConverterFactory(GsonConverterFactory.create(gson)) //设置支持Observable .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); } //获取实例 public static ApiEngine getInstance() { if (apiEngine == null) { synchronized (ApiEngine.class) { if (apiEngine == null) { apiEngine = new ApiEngine(); } } } return apiEngine; } public ApiService getApiService() { return retrofit.create(ApiService.class); } }
并且这里设置成了单例模式,方便各个地方的获取
-
初始化完成了,接下来就是创建各个接口。下面我将创建一个"ApiService"来作为接口文档
public interface ApiService { String BASE_URL = "xxxx"; //这里是你服务器的地址和接口 @GET("videoservice/video/{id}") Observable<VideoDetailsBean> getVideoDetails(@Path("id") int id, @Query("userId") int uid); @POST("videoservice/video/coin") Observable<CoinBean> coin_Operated(@Body dto coinBean, @Query("uid") int id); @POST() Observable<ThumbsUpBean> thumbsUp(@Url String url, @Body dto dto); @POST("userservice/login") Observable<UserBean> Login(@Body inputDto inputDto); @POST("userservice/user") Observable<RegisterBean> Register(@Body inputDto inputDto); @POST("videoservice/video/collection") Observable<CollectionBean> CollectionVideo(@Body dto dto, @Query("uid") int uid); @GET("userservice/logout") Observable<LogoutBean> Logout(); @GET("commentservice/danmu/{vid}/{second}") Observable<DanmuBean> getDanMu(@Path("second") int second, @Path("vid") int vid); @POST("commentservice/danmu") Observable<SeadDanmuBean> seadDanMu(@Body danmu danmu); @GET("userservice/dynamic/unread") Observable<DynamicNumBean> getDynamicNum(@Query("uid") int uid); @GET Observable<VersionBean> getVersion(@Url String url); @POST("commentservice/comment") Observable<CommentBean> addComment(@Body dto dto, @Query("uid") int uid); @POST("commentservice/comment") Observable<CommentBean> addDynamicComment(@Body dto dto, @Query("uid") int uid); @GET("userservice/user/details/{uid}") Observable<UserBean> findUserDetails(@Path("uid") int uid); @GET("videoservice/banner/list") Observable<BannerBean> findBanner(); }
上面的网络请求路径是与服务器地址分开的,该文档只是负责不同的接口调用,接下来就介绍一下这里面的注释都是那些意思。拦截器的代码我就不放出来了,如果想要可去源码上获取
注解 说明 @GET get请求 @POST post请求 @Headers 用于添加固定请求头,可以同时添加多个。通过该注解添加的请求头不会相互覆盖,而是共同存在 @Body 多用于post请求发送非表单数据,比如想要以post方式传递json格式数据 @Part 用于表单字段,Part和PartMap与Multipart注解结合使用,适合文件上传的情况 @Path 用于url中的占位符 @Query 用于Get中指定参数 @Url 指定请求路径 -
接下来为了防止Activity过于繁杂,为了解耦,所以将以MVP模式来进行网络请求
MVP模式进行网络请求
MVP模式我就不做多介绍了,想要了解的返回看专门讲解的文档
结构介绍:
- contract 整体的接口
- model 负责进行调用接口来获取数据
- presenter view和model交互之间的桥梁
- view 负责将获取的数据进行展示
接下来我已B站首页获取数据进行展示(源码在上方连接中)
-
先创建contract
public interface RecommendContract { interface View extends BaseView { void onGetRecommendVideoSuccess(RecommendVideoBean videoBean); void onGetRecommendVideoFail(String e); void onGetRefreshRecommendVideoSuccess(RecommendVideoBean videoBean); void onGetRefreshRecommendVideoFail(String e); void onGetBannerSuccess(BannerBean bannerBean); void onGetBannerFail(String e); } interface Model extends BaseModel { Observable<RecommendVideoBean> getRandomRecommendation(); Observable<RecommendVideoBean> getRefreshRecommendVideo(); Observable<BannerBean> findBanner(); } abstract class Presenter extends BasePresenter<View, Model> { public abstract void getRandomRecommendation(); public abstract void getRefreshRecommendVideo(); public abstract void findBanner(); } }
上面总共定义了4个方法,分别是:
- 获取首页随机推荐
- 刷新首页
- 获取轮播图
其中的View是给Activity/Fragment提供的接口,Model是给Model提供的接口,Presenter也就是给presenter提供的接口
-
按照顺序,接下来创建Model
public class RecommendModel implements RecommendContract.Model { @Override public Observable<RecommendVideoBean> getRandomRecommendation() { return ApiEngine.getInstance().getApiService().randomRecommendation(); } @Override public Observable<RecommendVideoBean> getRefreshRecommendVideo() { return ApiEngine.getInstance().getApiService().randomRecommendation(); } @Override public Observable<BannerBean> findBanner() { return ApiEngine.getInstance().getApiService().findBanner(); } }
对应contract中的3个接口,每个接口对会去调用相应的接口并返回获取到的数据
-
最后创建Model与View之间的桥梁–presenter
public class RecommendPresenter extends RecommendContract.Presenter { public void attachView(RecommendContract.View view) { this.mView = view; this.mModel = new RecommendModel(); } public void detachView() { this.mView = null; } //这里是将Retrofit2与Rxjava一起使用 //Retrofit2网络请求本身会自动的将网络请求放在子线程中运行,结果会在主线程中返回 @Override public void getRandomRecommendation() { mModel.getRandomRecommendation().subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<RecommendVideoBean>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(RecommendVideoBean videoBean) { mView.onGetRecommendVideoSuccess(videoBean); } @Override public void onError(Throwable e) { mView.onGetRecommendVideoFail(e.getMessage()); } @Override public void onComplete() { } }); } @Override public void getRefreshRecommendVideo() { mModel.getRefreshRecommendVideo().subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<RecommendVideoBean>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(RecommendVideoBean videoBean) { mView.onGetRefreshRecommendVideoSuccess(videoBean); } @Override public void onError(Throwable e) { mView.onGetRefreshRecommendVideoFail(e.getMessage()); } @Override public void onComplete() { } }); } @Override public void findBanner() { mModel.findBanner().subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<BannerBean>() { @Override public void onSubscribe(@NonNull Disposable d) { } @Override public void onNext(@NonNull BannerBean bannerBean) { mView.onGetBannerSuccess(bannerBean); } @Override public void onError(@NonNull Throwable e) { mView.onGetBannerFail(e.getMessage()); } @Override public void onComplete() { } }); } }
上面的代码,都是通过调用model的接口将数据返回给对应View接口,这样View中就只需要调用方法,就可在对应的接口中获取数据
-
在Activity/Fragment中使用
public class RecommendedFragment extends BaseFragment implements RecommendContract.View { RecommendPresenter mPresenter; @Override protected View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){ ... //进行绑定 mPresenter.attachView(this); } @Override protected void initData() { //调用接口来获取数据 mPresenter.findBanner(); } @Override public void onGetRecommendVideoSuccess(RecommendVideoBean videoBean) { //将获取到的数据放入适配器 videoBean.addData(mBeanData); adapter.loadMore(videoBean.getData()); } @Override public void onGetRecommendVideoFail(String e) { } @Override public void onGetRefreshRecommendVideoSuccess(RecommendVideoBean videoBean) { //刷新数据 for (RecommendVideoBean.BeanData datum : videoBean.getData()) { adapter.add(0, datum); } binding.ReRecy.scrollToPosition(0); } @Override public void onGetRefreshRecommendVideoFail(String e) { //通知用户发送错误 XToastUtils.error(R.string.errorOccurred + e); } @Override public void onGetBannerSuccess(BannerBean bannerBean) { mBeanData = new RecommendVideoBean.BeanData(); mBeanData.setBanner(true); mBeanData.setBannerUrl(bannerBean.getData()); mPresenter.getRandomRecommendation(); } @Override public void onGetBannerFail(String e) { } @Override public void onDestroy() { //进行销毁 mPresenter.detachView(); super.onDestroy(); } }
以上就是Retrofit2网络请求的全过程,下次会进一步的分析