写点什么

Android 教你一步步搭建 MVP+Retrofit+RxJava 网络请求框架

用户头像
Android架构
关注
发布于: 2 小时前

@QueryMap(GET 请求):

当然如果入参比较多,就可以把它们都放在 Map 中,例如:


`@GET("book/search")


Call<Book> getSearchBook(@QueryMap Map<String, String> options);`

@Path(GET 请求):

用于替换 url 中某个字段,例如:


`@GET("group/{id}/users")


Call<Book> groupList(@Path("id") int groupId);`


像这种请求接口,在 group 和 user 之间有个不确定的 id 值需要传入,就可以这种方法。我们把待定的值字段用{}括起来,当然 {}里的名字不一定就是 id,可以任取,但需和@Path后括号里的名字一样。如果在 user 后面还需要传入参数的话,就可以用 Query 拼接上,比如:


`@GET("group/{id}/users")


Call<Book> groupList(@Path("id") int groupId,@Query("sort") String sort);`


当我们调用这个方法时,假设我们 groupId 传入 1,sort 传入“2”,那么它拼接成的 url 就是group/1/users?sort=2,当然最后请求的话还会加上前面的 baseUrl。

@Body(POST 请求):

可以指定一个对象作为 HTTP 请求体,比如:


`@POST("users/new")


Call<User> createUser(@Body User user);`


它会把我们传入的 User 实体类转换为用于传输的 HTTP 请求体,进行网络请求。

@Field(POST 请求):

用于传送表单数据:


`@FormUrlEncoded


@POST("user/edit")


Call<User> up


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


dateUser(@Field("first_name") String first, @Field("last_name") String last);`


注意开头必须多加上@FormUrlEncoded这句注释,不然会报错。表单自然是有多组键值对组成,这里的 first_name 就是键,而具体传入的 first 就是值啦。

@Header/@Headers(POST 请求):

用于添加请求头部:


`@GET("user")


Call<User> getUser(@Header("Authorization") String authorization)`


表示将头部 Authorization 属性设置为你传入的 authorization;当然你还可以用 @Headers 表示,作用是一样的比如:


`@Headers("Cache-Control: max-age=640000")


@GET("user")


Call<User> getUser()`


当然你可以多个设置:


`@Headers({


"Accept: application/vnd.github.v3.full+json",


"User-Agent: Retrofit-Sample-App"


})


@GET("user")


Call<User> getUser()`


好了,这样我们就把上面这个 RetrofitService 接口类解释的差不多了。我觉得,Retrofit 最主要的也就是这个接口类的定义了。好了,有了这个接口类,我们来看一下,到底如何使用这个我们定义的接口来进行网络请求。代码如下:


`Retrofit retrofit = new Retrofit.Builder()


.baseUrl("https://api.douban.com/v2/")


.addConverterFactory(GsonConverterFactory.create(new GsonBuilder().create()))


.build();


RetrofitService service = retrofit.create(RetrofitService.class);


Call<Book> call = service.getSearchBook("金瓶梅", null, 0, 1);


call.enqueue(new Callback<Book>() {


@Override


public void onResponse(Call<Book> call, Response<Book> response) {


text.setText(response.body()+"");


}


@Override


public void onFailure(Call<Book> call, Throwable t) {


}


});`


这里我们可以看到,先新建了一个 Retrofit 对象,然后给它设置一个我们前面说的 baseUrlhttps://api.douban.com/v2/.因为接口返回的数据不是我们需要的实体类,我们需要调用 addConverterFactory 方法进行转换。由于返回的数据为 json 类型,所以在这个方法中传入 Gson 转换工厂GsonConverterFactory.create(new GsonBuilder().create()),这里我们需要在 studio 中添加 Gson 的依赖:


compile 'com.squareup.retrofit2:converter-gson:2.1.0'


然后我们调用 retrofit 的 create 方法并传入上面我们定义的接口的文件名 RetrofitService.class,就可以得到 RetrofitService 的实体对象。有了这个对象,我们就可以调用里面之前定义好的请求方法了。比如:


Call<Book> call = service.getSearchBook("金瓶梅", null, 0, 1);


它会返回一个 Call 实体类,然后就可以调用 Call 的 enqueue 方法进行异步请求,在 enqueue 方法中传入一个回调 CallBack,重写里面的 onResponse 和


onFailure 方法,也就是请求成功和失败的回调方法。当成功时,它会返回 Response,里边封装了请求结果的所有信息,包括报头,返回码,还有主体等。比如调用它的 body()方法就可获得 Book 对象,也就是我们需要的数据。这里我们就把返回的 Book,显示屏幕上。如下图:



好了,到这里我们就基本了解了 Retrofit 的整个工作流程。


3.RxJava


我们这篇文章主要介绍搭建整体网络请求框架,所以关于 RxJava 的基础知识,我这就不再详细介绍了,网上也有很多文章,对 RxJava 还不是很了解的同学,推荐你看一下扔物线的这篇文章给 Android 开发者的 RxJava 详解


下面我们来看一下 RxJava 和 retrofit 的结合使用,为了使 Rxjava 与 retrofit 结合,我们需要在 Retrofit 对象建立的时候添加一句代码addCallAdapterFactory(RxJavaCallAdapterFactory.create()),当然你还需要在 build.gradle 文件中添加如下依赖:


????????compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'


完整的代码如下:


`Retrofit retrofit = new Retrofit.Builder()


.baseUrl("https://api.douban.com/v2/")


.addConverterFactory(GsonConverterFactory.create(new GsonBuilder().create()))


.addCallAdapterFactory(RxJavaCallAdapterFactory.create())//支持 RxJava


.build();`


然后我们还需要修改 RetrofitService 中的代码:


`public interface RetrofitService {


@GET("book/search")


Observable<Book> getSearchBook(@Query("q") String name,


@Query("tag") String tag, @Query("start") int start,


@Query("count") int count);`


可以看到,在原来的 RetrofitService 中我们把 getSearchBook 方法返回的类型 Call 改为了 Observable,也就是被观察者。其他都没变。然后就是创建 RetrofitService 实体类:


RetrofitService service = retrofit.create(RetrofitService.class);


和上面一样,创建完 RetrofitService ,就可以调用里面的方法了:


Observable<Book> observable = service.getSearchBook("金瓶梅", null, 0, 1);


其实这一步,就是创建了一个 rxjava 中 observable,即被观察者,有了被观察者,就需要一个观察者,且订阅它:


`observable.subscribeOn(Schedulers.io())//请求数据的事件发生在 io 线程


.observeOn(AndroidSchedulers.mainThread())//请求完成后在主线程更显 UI


.subscribe(new Observer<Book>() {//订阅


@Override


public void onCompleted() {


//所有事件都完成,可以做些操作。。。


}


@Override


public void onError(Throwable e) {


e.printStackTrace(); //请求过程中发生错误


}


@Override


public void onNext(Book book) {//这里的 book 就是我们请求接口返回的实体类


}


}`


在上面中我们可以看到,事件的消费在 Android 主线程,所以我们还要在 build.gradle 中添加如下依赖:


????????compile 'io.reactivex:rxandroid:1.2.0'


这样我们就引入了 RxAndroid,RxAndroid 其实就是对 RxJava 的扩展。比如上面这个 Android 主线程在 RxJava 中就没有,因此要使用的话就必须得引用 RxAndroid。


4.实践




接下来我们就看看,在一个项目中上面三者是如何配合的。我们打开 Android Studio,新建一个项目取名为 MVPDemo。这个 demo 的功能也很简单,就是点击按钮调用上面的那个测试接口,将请求下来书的信息显示在屏幕上。首先我们来看一下这个工程的目录结构:



我们可以看到,在项目的包名下,我们建了三个主要的文件夹:app、service、ui。当然根据项目的需要你也可以添加更多其他的文件夹,比如一些工具类等。其中 app 文件夹中可以建一个 Application 类,用于设置应用全局的一些属性,这里为了使项目更加简单就没有添加;然后,我们再来看看 ui 文件夹下,这个文件夹下主要放一些关于界面的东西。在里面我们又建了三个文件夹:activity、adapter、fragment,我想看名字你就清楚里面要放什么了。最后我们在重点看看 service 文件夹中的东西。首先我们来看看里面重要的两个类:RetrofitHelper 和 RetrofitService。RetrofitHelper 主要用于 Retrofit 的初始化:


`public class RetrofitHelper {


private Context mCntext;


OkHttpClient client = new OkHttpClient();


GsonConverterFactory factory = GsonConverterFactory.create(new GsonBuilder().create());


private static RetrofitHelper instance = null;


private Retrofit mRetrofit = null;


public static RetrofitHelper getInstance(Context context){


if (instance == null){


instance = new RetrofitHelper(context);


}


return instance;


}


private RetrofitHelper(Context mContext){


mCntext = mContext;


init();


}


private void init() {


resetApp();


}


private void resetApp() {


mRetrofit = new Retrofit.Builder()


.baseUrl("https://api.douban.com/v2/")


.client(client)


.addConverterFactory(factory)


.addCallAdapterFactory(RxJavaCallAdapterFactory.create())


.build();


}


public RetrofitService getServer(){


return mRetrofit.create(RetrofitService.class);


}


}`


代码并不复杂,其中 resetApp 方法,就是前面介绍的 Retrofit 的创建,getServer 方法就是为了获取 RetrofitService 接口类的实例化。然后定义了一个静态方法 getInstance 用于获取自身 RetrofitHelper 的实例化,并且只会实例化一次。


接下来,看一下 RetrofitService,其中代码还是上面一样:


`public interface RetrofitService {


@GET("book/search")


Observable<Book> getSearchBooks(@Query("q") String name,


@Query("tag") String tag, @Query("start") int start,


@Query("count") int count);


}`


然后我们依次来看一下 service 文件夹下的四个文件夹:entity、manager、presenter 和 view。其中 entity 下放我们请求的实体类,这里就是 Book。接下来我们来看一下 manager 中 DataManager。这个类其实就是为了让你更方便的调用 RetrofitService 中定义的方法:


`public class DataManager {


private RetrofitService mRetrofitService;


public DataManager(Context context){


this.mRetrofitService = RetrofitHelper.getInstance(context).getServer();


}


public Observable<Book> getSearchBooks(String name,String tag,int start,int count){


return mRetrofitService.getSearchBooks(name,tag,start,count);


}


}`


可以看到,在它的构造方法中,我们得到了 RetrofitService 的实例化,然后定义了一个和 RetrofitService 中同名的方法,里面其实就是调用 RetrofitService 中的这个方法。这样,把 RetrofitService 中定义的方法都封装到 DataManager 中,以后无论在哪个要调用方法时直接在 DataManager 中调用就可以了,而不是重复建立 RetrofitService 的实例化,再调用其中的方法。


好了,我们再来看一下 presenter 和 view,我们在前面说过,presenter 主要用于网络的请求以及数据的获取,view 就是将 presenter 获取到的数据进行展示。首先我们先来看 view,我们看到我们建了两个接口类 View 和 BookView,其中 View 是空的,主要用于和 Android 中的 View 区别开来:


`public interface View {


}`


然后让 BookView 继承自我们自己定义的 View :


`public interface BookView extends View {


void onSuccess(Book mBook);


void onError(String result);


}`


可以看到在里面定义两个方法,一个 onSuccess,如果 presenter 请求成功,将向该方法传入请求下来的实体类,也就是 Book,view 拿到这个数据实体类后,就可以进行关于这个数据的展示或其他的一些操作。如果请求失败,就会向这个 view 传入失败信息,你可以弹个 Toast 来提示请求失败。通常这两个方法比较常用,当然你可以根据项目需要来定义一些其他的方法。接下来我们看看 presenter 是如何进行网络请求的 。我们也定义了一个基础 Presenter:


`public interface Presenter {


void onCreate();


void onStart();//暂时没用到


void onStop();


void pause();//暂时没用到


void attachView(View view);


void attachIncomingIntent(Intent intent);//暂时没用到


}`


里面我们可以看到,定义了一些方法,前面几个 onCreate、onStart 等方法对应着 Activity 中生命周期的方法,当然没必要写上 Activity 生命周期中所有回调方法,通常也就用到了 onCreate 和 onStop,除非需求很复杂,在 Activity 不同生命周期请求的情况不同。接着我们定义了一个 attachView 方法,用于绑定我们定义的 View。也就是,你想把请求下来的数据实体类给哪个 View 就传入哪个 View。下面这个 attachIncomingIntent 暂且没用到,就不说了。好了,我们来看一下 BookPresenter 具体是怎么实现的:


`public class BookPresenter implements Presenter {


private DataManager manager;


private CompositeSubscription mCompositeSubscription;


private Context mContext;


private BookView mBookView;


private Book mBook;


public BookPresenter (Context mContext){


this.mContext = mContext;


}


@Override


public void onCreate() {


manager = new DataManager(mContext);


mCompositeSubscription = new CompositeSubscription();


}


@Override


public void onStart() {


}


@Override


public void onStop() {


if (mCompositeSubscription.hasSubscriptions()){


mCompositeSubscription.unsubscribe();


}


}


@Override


public void pause() {


}


@Override


public void attachView(View view) {


mBookView = (BookView)view;


}


@Override


public void attachIncomingIntent(Intent intent) {


}


public void getSearchBooks(String name,String tag,int start,int count){


mCompositeSubscription.add(manager.getSearchBooks(name,tag,start,count)


.subscribeOn(Schedulers.io())


.observeOn(AndroidSchedulers.mainThread())


.subscribe(new Observer<Book>() {


@Override


public void onCompleted() {


if (mBook != null){


mBookView.onSuccess(mBook);


}


}


@Override


public void onError(Throwable e) {


e.printStackTrace();


mBookView.onError("请求失败!!");


}


@Override


public void onNext(Book book) {


mBook = book;


}


})


);

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Android 教你一步步搭建MVP+Retrofit+RxJava网络请求框架