Retrofit+RXJava+MVP的框架搭建

一、框架优点

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

猛戳这里下载demo








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流星雨在线

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值