一、框架优点
1.1,Retrofit封装更彻底,通过注解的方式调用
1.2,RXJava订阅者模式的实现让组件内通信更方便
1.3,MVP的开发模式减少耦合,便于项目各个模块的分离,应付产品需求的调整
二、Retrofit的使用
(以请求并解析https://api.douban.com/v2/book/search?q=%E9%87%91%E7%93%B6%E6%A2%85&tag=&start=0&count=1中的数据为例)
2.1,需要用到的module里面添加依赖
compile 'com.squareup.retrofit2:retrofit:2.1.0' compile 'com.squareup.retrofit2:converter-gson:2.1.0'2.2,定义一个接口类
//和别的接口类一样,我们在其中定义了一个方法getSearchBook,返回Call实体类 //作用:拼接一个URL然后进行网络请求
public interface RetrofitService {
@GET("book/search")
Call<Book> getSearchBook(@Query("q") String name,
@Query("tag") String tag,
@Query("start") int start,
@Query("count") int count);
}
2.3,Activity中具体使用
//初始化
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.douban.com/v2/")
.addConverterFactory(GsonConverterFactory.create(new GsonBuilder().create()))
.build();
//实例化RetrofitService对象
RetrofitService service = retrofit.create(RetrofitService.class);
//调用RetrofitService对象的方法
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().toString());
}
@Override
public void onFailure(Call<Book> call, Throwable t) {
Toast.makeText(MainActivity.this, "failed", Toast.LENGTH_SHORT).show();
}
});
2.4,单纯Retrofit的简单使用就这么多,然后就是Retrofit提供的一些接口
提供的注解主要有:
GET ----------查找资源(查) POST --------修改资源(改) PUT ----------上传文件(增) DELETE ----删除文件(删) HEAD--------只请求页面的首部
todo one: @GET("book/search") Call<Book> getSearchBook(@Query("q") String name);//name由调用者传入 相当于: @GET("book/search?q=name") Call<Book> getSearchBook(); todo two: @QueryMap(GET请求): 当然如果入参比较多,就可以把它们都放在Map中,例如: @GET("book/search") Call<Book> getSearchBook(@QueryMap Map<String, String> options); todo three: @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); todo four: @Body(POST请求): 可以指定一个对象作为HTTP请求体,比如: @POST("users/new") Call<User> createUser(@Body User user); 它会把我们传入的User实体类转换为用于传输的HTTP请求体,进行网络请求。 todo five: @Field(POST请求): 用于传送表单数据: @FormUrlEncoded @POST("user/edit") Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last); 注意开头必须多加上@FormUrlEncoded这句注释,不然会报错。表单自然是有多组键值对组成,这里的first_name就是键,而具体传入的first就是值啦。 todo six: @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()
三、MVPHelper插件的使用
3.1,在插件仓库搜索MVpHelper,Setting->Plugins->install
3.2,两种模式,模式在自定义后缀的情况下不会删除原有 Presenter, 因此我们建议使用Contract 模式
Contract模式:包名命名为至少一个包以constract结尾,抽象类名需以Contract结尾。右键generate->mvpHelper(快捷键alt+insert)即可生成。
生成的结果是:一个model包下的Model实体类实现了Contract抽象类中的Model接口,一个presenter包下的Presenter实体类实现了Contract抽象类中的Presenter接口.
Presenter模式:同上
Model模式:无
3.3,后缀支持,setting->OtherSetting->mvpHelper->输入例如lmpl确定
四、RXJava的简单解析
首先,RxJava 有四个基本概念:Observable (可观察者,即被观察者)、 Observer (观察者)、 subscribe (订阅)、事件。Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer。
onNext(): RxJava 的事件回调方法(相当于 观察者模式中的onClick() / onEvent())。
onCompleted(): 事件队列完结。RxJava 不仅把每个事件单独处理,还会把它们看做一个队列。RxJava 规定,当不会再有新的 onNext() 发出时,需要触发 onCompleted() 方法作为标志。
onError(): 事件队列异常。在事件处理过程中出异常时,onError() 会被触发,同时队列自动终止,不允许再有事件发出。
在一个正确运行的事件序列中, onCompleted() 和 onError() 有且只有一个,并且是事件序列中的最后一个。需要注意的是,onCompleted() 和 onError() 二者也是互斥的,即在队列中调用了其中一个,就不应该再调用另一个。
one:Observable发射源
创建Obervable,create方式:
//RxJava 使用 create() 方法来创建一个 Observable ,并为它定义事件触发规则
Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello");
subscriber.onNext("Hi");
subscriber.onNext("Aloha");
subscriber.onCompleted();
}
});
创建Obervable,just方式:
//将传入的参数依次发送出来。
Observable observable = Observable.just("Hello", "Hi", "Aloha");
// 将会依次调用:
// onNext("Hello");
// onNext("Hi");
// onNext("Aloha");
// onCompleted();
创建Observable,from(T[]) / from(Iterable<? extends T>)方式
//将传入的数组或 Iterable 拆分成具体对象后,依次发送出来。
String[] words = {"Hello", "Hi", "Aloha"};
Observable observable = Observable.from(words);
// 将会依次调用:
// onNext("Hello");
// onNext("Hi");
// onNext("Aloha");
// onCompleted();
two:Observer接收源,创建Observer
//Observer 即观察者,它决定事件触发的时候将有怎样的行为。
Observer<String> observer = new Observer<String>() {
@Override
public void onNext(String s) {
Log.d(tag, "Item: " + s);
}
@Override
public void onCompleted() {
Log.d(tag, "Completed!");
}
@Override
public void onError(Throwable e) {
Log.d(tag, "Error!");
}
};
three:Subject是一个比较特殊的对象,既可充当发射源,也可充当接收源
这里以后补充
four:Subscriber订阅者,也是接收源。比Observer多一个unsubscribe()方法,推荐使用
//Subscriber 对 Observer 接口进行了一些扩展,但他们的基本使用方式是完全一样的
Subscriber<String> subscriber = new Subscriber<String>() {
@Override
public void onNext(String s) {
Log.d(tag, "Item: " + s);
}
@Override
public void onCompleted() {
Log.d(tag, "Completed!");
}
@Override
public void onError(Throwable e) {
Log.d(tag, "Error!");
}
};
five:Subscription,Observable调用subscribe()方法返回的对象,同样有unsubscribe()方法,可以用来取消订阅事件
Subscribe (订阅)
observable.subscribe(observer);
// 或者:
observable.subscribe(subscriber);
six:interval轮询
//interval()函数在你需要创建一个轮询程序时非常好用。
Observable.interval(3, TimeUnit.SECONDS)
.subscribeOn(Schedulers.newThread())//在子线程执行,否则不能执行轮询
.subscribe(new Action1<Long>() {
@Override
public void call(final Long aLong) {
//如果要更新UI,可以runOnUiThread方法或添加Rxandroid库
Log.i("interval", "I say :" + along);
}
});
//interval()函数的两个参数:一个指定两次发射的时间间隔,另一个是用到的时间单位。这个只会执行一次,添加subscribeOn(Schedulers.newThread())能够达到轮训的效果
seven:timer定时器
//如果你需要一个一段时间之后才发射的Observable,你可以像下面的例子使用timer():
Observable.timer(3,TimeUnit.SECONDS)
.subscribe(new Action1<Long>() {
@Override
public void call(Long aLong) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "timer 3 delay", Toast.LENGTH_SHORT).show();
}
});
}
});
//它将3秒后发射0,然后就完成了。
eight:filter过滤
//RxJava让我们使用filter()方法来过滤我们观测序列中不想要的值
Observable.just("H1", "h2", "h3", "h4", "h5").filter(new Func1<String, Boolean>() {
@Override
public Boolean call(String s) {
return s.startsWith("H");
}
}).subscribe(new Action1<String>() {
@Override
public void call(final String s) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, s, Toast.LENGTH_SHORT).show();
}
});
}
});
//通过设置filter,然后在call里面添加s.startsWith("H"),如果是H开头就返回true,否则返回false。
// 从而能够过滤掉不是h开头的消息,打印出以H开头的消息。
五、Retrofit+RXJava+MVP的搭建与使用
5.1,文件目录树状图
├─app
├─service
│ │ RetrofitHelper.java
│ │ RetrofitService.java
│ ├─entity
│ │ Book.java
│ ├─manager
│ │ DataManager.java
│ ├─presenter
│ │ BookPresenter.java
│ │ Presenter.java
│ └─view
│ BookView.java
│ View.java
└─ui
├─activity
│ MainActivity.java
├─adapter
└─fragment
5.2,定义RetrofitHelper类初始化Retrofit
//主要用于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;
//静态方法getInstance用于获取自身RetrofitHelper的实例化,并且只会实例化一次
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();
}
//Retrofit的创建
private void resetApp() {
mRetrofit = new Retrofit.Builder()
.baseUrl("https://api.douban.com/v2/")
.client(client)
.addConverterFactory(factory)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
}
//获取RetrofitService接口类的实例化
public RetrofitService getServer(){
return mRetrofit.create(RetrofitService.class);
}
}
5.3,提供网络请求的服务接口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);
}
5.4,编写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);
}
}
5.5,给UI界面提供接口
public interface View {
}
/*可以看到在里面定义两个方法,一个onSuccess,如果presenter请求成功,将向该方法传入请求下来的实体类,
也就是Book,view拿到这个数据实体类后,就可以进行关于这个数据的展示或其他的一些操作。
如果请求失败,就会向这个view传入失败信息,你可以弹个Toast来提示请求失败。通常这两个方法比较常用*/
public interface BookView extends View {
void onSuccess(Book mBook);
void onError(String result);
}
5.6,在Presenter中定义接口,根据项目需求给出常用的抽象方法
/*attachView方法,用于绑定我们定义的View。也就是,你想把请求下来的数据实体类给哪个View就传入哪个View。
下面这个attachIncomingIntent暂且没用到*/
public interface Presenter {
void onCreate();
void onStart();//暂时没用到
void onStop();
void pause();//暂时没用到
void attachView(View view);
void attachIncomingIntent(Intent intent);//暂时没用到
}
5.7,给出实体类的处理类,用于进行数据的网络请求,以及结果的反馈
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() {
//创建DataManager的实体类,便于调用RetrofitService中的方法
manager = new DataManager(mContext);
/*
* 创建CompositeSubscription对象,用来存放RxJava中的订阅关系的,注意请求完数据要及时清掉这个订阅关系,不然会发生内存泄漏
* */
mCompositeSubscription = new CompositeSubscription();
}
@Override
public void onStart() {
}
@Override
public void onStop() {
/*
* 可在onStop中通过调用CompositeSubscription的unsubscribe方法来取消这个订阅关系,
* 不过一旦调用这个方法,那么这个CompositeSubscription也就无法再用了,要想再用只能重新new一个
* */
if (mCompositeSubscription.hasSubscriptions()){
mCompositeSubscription.unsubscribe();
}
}
@Override
public void pause() {
}
@Override
public void attachView(View view) {
// 我们把BookView传进去。也就是说我们要把请求下来的实体类交给BookView来处理
mBookView = (BookView)view;
}
@Override
public void attachIncomingIntent(Intent intent) {
}
/*
* 这个方法也就是请求的具体实现过程。其实也很简单,就是向CompositeSubscription添加一个订阅关系
* */
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;
}
})
);
}
}
5.8,主页面xml布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:orientation="vertical"
android:paddingTop="@dimen/activity_vertical_margin">
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<Button
android:id="@+id/button"
android:onClick="getFollowers"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="请求"/>
</LinearLayout>
5.9,Activity中进行ui的展示
public class MainActivity extends AppCompatActivity {
private TextView text;
private Button button;
private BookPresenter mBookPresenter = new BookPresenter(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView)findViewById(R.id.text);
button = (Button)findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mBookPresenter.getSearchBooks("金瓶梅", null, 0, 1);
}
});
mBookPresenter.onCreate(); //初始化BookPresenter对象
mBookPresenter.attachView(mBookView);//绑定bookview
}
private BookView mBookView = new BookView() {
@Override
public void onSuccess(Book mBook) {
text.setText(mBook.toString());
}
@Override
public void onError(String result) {
Toast.makeText(MainActivity.this,result, Toast.LENGTH_SHORT).show();
}
};
@Override
protected void onDestroy(){
super.onDestroy();
mBookPresenter.onStop();//当活动销毁时记得调用BookPresenter的onStop方法来释放订阅关系,防止内存泄漏
}
}
参考网址:http://www.apkbus.com/blog-719059-63069.html