美文网首页
rxJava与Retrofit结合使用 基础篇(1)

rxJava与Retrofit结合使用 基础篇(1)

作者: ZzzRicardo_Yue | 来源:发表于2016-11-21 15:31 被阅读0次

    整理自:
    http://blog.csdn.net/whuhan2013/article/details/51635653
    http://gank.io/post/56e80c2c677659311bed9841


    这篇文章从一个侧面反映rxJava的优越性,主要讲解如何将rxJava与Retrofit2这两个现在热门的框架整合使用。
    在看这篇文章之前,请先了解基本的rxJava和Retrofit2的知识


    一、使用rxJava&Retrofit的好处

    先让我们看一下如果单纯使用Retrofit会有什么问题:

    1. 复杂逻辑很难实现:

    比如:你的程序取到的 User 并不应该直接显示,而是需要先与数据库中的数据进行比对和修正后再显示。使用 Callback 方式大概可以这么写:

    getUser(userId, new Callback<User>() {
        @Override
        public void success(User user) {
            processUser(user); // 尝试修正 User 数据
            userView.setUser(user);
        }
    
        @Override
        public void failure(RetrofitError error) {
            // Error handling
            ...
        }
    };
    

    很简便,但不要这样做。为什么?因为这样做会影响性能。数据库的操作很重,一次读写操作花费 10~20ms 是很常见的,这样的耗时很容易造成界面的卡顿。所以通常情况下,如果可以的话一定要避免在主线程中处理数据库。所以为了提升性能,这段代码可以优化一下:

    getUser(userId, new Callback<User>() {
        @Override
        public void success(User user) {
            new Thread() {
                @Override
                public void run() {
                    processUser(user); // 尝试修正 User 数据
                    runOnUiThread(new Runnable() { // 切回 UI 线程
                        @Override
                        public void run() {
                            userView.setUser(user);
                        }
                    });
                }).start();
        }
    
        @Override
        public void failure(RetrofitError error) {
            // Error handling
            ...
        }
    };
    

    性能问题解决,但……这代码实在是太乱了,迷之缩进啊!杂乱的代码往往不仅仅是美观问题,因为代码越乱往往就越难读懂,而如果项目中充斥着杂乱的代码,无疑会降低代码的可读性,造成团队开发效率的降低和出错率的升高。
    这时候,如果用 RxJava 的形式,就好办多了。 RxJava 形式的代码是这样的:

    getUser(userId)
        .doOnNext(new Action1<User>() {
            @Override
            public void call(User user) {
                processUser(user);
            })
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Observer<User>() {
            @Override
            public void onNext(User user) {
                userView.setUser(user);
            }
    
            @Override
            public void onCompleted() {
            }
    
            @Override
            public void onError(Throwable error) {
                // Error handling
                ...
            }
        });
    

    代码中oOnNext()的执行在onNext()之前,对数据进行相关处理。doOnNext具体的使用方法不是本文讨论的重点。

    1. ProgressDialog的show方法应该在哪调用:

    这个问题如果不用rxJava,解决起来也很容易:只要在调用Retrofit之前写一遍show()的代码,但是这样不容易操控整个网络请求的逻辑(这个我没尝试过,暂时这么认为)。但是这个如果用rxJava解决的话就很简单,不在这里单讲了,可以看下面的代码。

    二、在Retrofit上添加rxJava

    1. 添加Rxjava:
      先在Gradle中添加依赖。
      接着在创建Retrofit的过程中添加如下代码:
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
            .build();
    

    注意第四行,这样一来我们定义的service返回值就不在是一个Call了,而是一个Observable

    1. 修改接口:
    public interface MovieService {
        @GET("top250")
        Observable<MovieEntity> getTopMovie(@Query("start") int start, @Query("count") int count);
    }
    
    1. 修改getMovie:
    //进行网络请求
    private void getMovie(){
        String baseUrl = "https://api.douban.com/v2/movie/";
    
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();
    
        MovieService movieService = retrofit.create(MovieService.class);
    
        movieService.getTopMovie(0, 10)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<MovieEntity>() {
                    @Override
                    public void onCompleted() {
                        Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
                    }
    
                    @Override
                    public void onError(Throwable e) {
                        resultTV.setText(e.getMessage());
                    }
    
                    @Override
                    public void onNext(MovieEntity movieEntity) {
                        resultTV.setText(movieEntity.toString());
                    }
                });
    }
    

    三、封装上述代码

    创建一个对象HttpMethods

    public class HttpMethods {
    
        public static final String BASE_URL = "https://api.douban.com/v2/movie/";
    
        private static final int DEFAULT_TIMEOUT = 5;
    
        private Retrofit retrofit;
        private MovieService movieService;
    
        //构造方法私有
        private HttpMethods() {
            //手动创建一个OkHttpClient并设置超时时间
            OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
            httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
    
            retrofit = new Retrofit.Builder()
                    .client(httpClientBuilder.build())
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .baseUrl(BASE_URL)
                    .build();
    
            movieService = retrofit.create(MovieService.class);
        }
    
        //在访问HttpMethods时创建单例
        private static class SingletonHolder{
            private static final HttpMethods INSTANCE = new HttpMethods();
        }
    
        //获取单例
        public static HttpMethods getInstance(){
            return SingletonHolder.INSTANCE;
        }
    
        /**
         * 用于获取豆瓣电影Top250的数据
         * @param subscriber 由调用者传过来的观察者对象
         * @param start 起始位置
         * @param count 获取长度
         */
        public void getTopMovie(Subscriber<MovieEntity> subscriber, int start, int count){
            movieService.getTopMovie(start, count)
                    .subscribeOn(Schedulers.io())
                    .unsubscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(subscriber);
        }
    }
    

    用一个单例来封装该对象,在构造方法中创建Retrofit和对应的Service。 如果需要访问不同的基地址,那么你可能需要创建多个Retrofit对象,或者干脆根据不同的基地址封装不同的HttpMethod类。
    我们回头再来看MainActivity中的getMovie方法:

    private void getMovie(){
         subscriber = new Subscriber<MovieEntity>() {
             @Override
             public void onCompleted() {
                 Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
             }
    
             @Override
             public void onError(Throwable e) {
                 resultTV.setText(e.getMessage());
             }
    
             @Override
             public void onNext(MovieEntity movieEntity) {
                 resultTV.setText(movieEntity.toString());
             }
         };
         HttpMethods.getInstance().getTopMovie(subscriber, 0, 10);
    }        
    

    其中subscriber是MainActivity的成员变量。

    相关文章

      网友评论

          本文标题:rxJava与Retrofit结合使用 基础篇(1)

          本文链接:https://www.haomeiwen.com/subject/cvtypttx.html