封装一个实用的Android请求数据的工具类

在app开发过程中,我们经常需要从网络拉取数据然后在界面上显示,如果每次显示都从网络上请求数据,不仅会浪费流量,而且还会影响性能,一般我们会在本地缓存一份,当更新ui时有限从本地拿数据,手动更新时再从网络请求数据。这里分享一个使用Rxjava2实现的请求数据的工具类

public abstract class QueryDataHelper<T> {

    /**
     * 请求数据
     * @param type 发起的请求的类型 Type.NORMAL表示正常类型,优先从本地拉取数据
     *             Type.REFRESH表示刷新类型,优先从网络拉取数据
     * @return 返回数据的可订阅主题,默认的观察者在主线程,发布者在io线程
     */
    @SuppressLint("CheckResult")
    public Maybe<T> queryData(Type type){
        switch (type){
            case NORMAL:
                return Observable.concat (queryFromLocal (),queryFromNet ())
                        .firstElement ()
                        .subscribeOn (Schedulers.io ())
                        .observeOn (AndroidSchedulers.mainThread ());
            case REFRESH:
                return Observable.concat (queryFromNet (), queryFromLocal ())
                        .firstElement ()
                        .subscribeOn (Schedulers.io ())
                        .observeOn (AndroidSchedulers.mainThread ());
            default:
                return Observable.concat (queryFromNet (), queryFromLocal ())
                        .firstElement ()
                        .subscribeOn (Schedulers.io ())
                        .observeOn (AndroidSchedulers.mainThread ());
        }
    }

    /**
     * 从网络获取数据
     * @return 获取到的数据的主题,可订阅
     */
    public abstract Observable<T> queryFromNet();

    /**
     * 从本地获取数据
     * @return 获取到的数据的主题,可订阅
     */
    public abstract Observable<T> queryFromLocal();

    /**
     * 访问类型
     */
    public enum Type{
        /**
         * 正常的访问类型,优先从本地拿数据,比如读取地理位置的列表
         */
        NORMAL,

        /**
         * 刷新式的访问类型,优先请求网络拿数据,比如刷新界面
         */
        REFRESH
    }
}

这里使用rxjavaconcat操作符和firstElement实现访问顺序的控制。concat的作用是合并多个Observable对象并按顺序发射(这里区别merga,merga也是合并多个Observable对象,但是它不能保证发射的顺序),firstElement的作用对于多个Observable对象,按照它们的顺序,只发射第一个发射出的内容(与first操作符不同的是,first操作符需要一个默认的形参作为当所有Observable对象都不发射时的返回值)。这样便实现了操作顺序的控制。
然后提供两个访问类型,NORMAL类型和REFRESH类型。NORMAL用作处理普通的访问方式,即:先调用本地数据,当本地没有数据的时候再请求网络,而REFRESH类型则是表示刷新类的访问方式,即:先从网络拿数据,如果失败了再从本地拿数据,不至于让ui空着没数据。

使用步骤

1.添加依赖

可以在gradle中添加如下依赖,这个是jakewharton提供的rxbinding,其中包含有rxJava2RxAndroid2

implementation 'com.jakewharton.rxbinding3:rxbinding:3.0.0-alpha2'

或者分别导入rxJava2RxAndroid2

implementation "io.reactivex.rxjava2:rxjava:2.2.7"
implementation 'io.reactivex.rxjava2:rxjava:2.1.1'

最新版本可以访问项目主页RxAndroid进行查看。

2.重写抽象类

在需要查询数据的地方重写该抽象类并实现从网络访问从本地访问的逻辑。比如我的现在有一个这样的业务逻辑:访问网络拿到天气预报里面的生活建议的数据,然后显示在ui里面显示。那么我们就可以写一个QuerySuggestionHelper类让它继承QueryDataHelper并将泛型指定为Suggestion(这里我用了Retrofit2来做网络请求,Suggestion是返回的json的javabean)。再实现两个抽象方法,分别处理不同的逻辑即可。

class QuerySuggestionHelper extends QueryDataHelper<Suggestion>{

        @Override
        // 从网络拿数据并存到本地,这里是存储在sharePreference里面
        public Observable<Suggestion> queryFromNet() {
            return RetrofitManager.getInstance ()
                    .create ()
                    .querySuggestion (WEATHER_USER_KEY, mLocation)
                    .filter (new Predicate<com.xiaogege.jerry.model.gson.Suggestion> () {
                        @Override
                        public boolean test(com.xiaogege.jerry.model.gson.Suggestion suggestion) throws Exception {
                            return suggestion != null
                                    && suggestion.getHeWeather6 () != null
                                    && suggestion.getHeWeather6 ().size () > 0
                                    && WEATHER_STATUE_SUCCESS.equals (suggestion.getHeWeather6 ().get (0).getStatus ())
                                    && suggestion.getHeWeather6 ().get (0).getLifestyle () != null
                                    && suggestion.getHeWeather6 ().get (0).getLifestyle ().size () > 0;
                        }
                    })
                    .flatMap (new Function<com.xiaogege.jerry.model.gson.Suggestion, ObservableSource<Suggestion>> () {
                        @Override
                        public ObservableSource<Suggestion> apply(com.xiaogege.jerry.model.gson.Suggestion suggestion) throws Exception {
                            //拿到数据
                            String comfort = suggestion.getHeWeather6 ().get (0).getLifestyle ().get (0).getTxt ();
                            String sport = suggestion.getHeWeather6 ().get (0).getLifestyle ().get (3).getTxt ();
                            String carWash = suggestion.getHeWeather6 ().get (0).getLifestyle ().get (6).getTxt ();
                            String travel = suggestion.getHeWeather6 ().get (0).getLifestyle ().get (4).getTxt ();
                            Suggestion xmlSuggestion = new Suggestion (comfort, carWash, sport, travel);
                            //写入sharePreference
                            String suggestionJson = new Gson ().toJson (xmlSuggestion);
                            XmlIOUtils.xmlPut (SUGGESTION_JSON_KEY, suggestionJson, mContext);
                            return Observable.just (xmlSuggestion);
                        }
                    })
                    ;
        }

        @Override
        // 从本地拿数据,这里是从sharePreference中拿数据
        public Observable<Suggestion> queryFromLocal() {
            final String suggestionJson = XmlIOUtils.xmlGet (SUGGESTION_JSON_KEY, mContext);
            return Observable.create (new ObservableOnSubscribe<Suggestion> () {
                @Override
                public void subscribe(ObservableEmitter<Suggestion> emitter) throws Exception {
                    if(suggestionJson != null){
                        Suggestion suggestion = new Gson ().fromJson (suggestionJson, Suggestion.class);
                        emitter.onNext (suggestion);
                    }
                    emitter.onComplete ();
                }
            });
        }
    }

3.调用queryData()方法

在需要请求数据的地方调用queryData()方法,并传入一个类型参数,指定当前请求数据的方式,是优先本地还是优先网络。

@Override
	//普通的显示方式,优先显示缓存
    public void queryAll() {
        querySuggestion (QueryDataHelper.Type.NORMAL);
    }

    @Override
    //刷新式的请求方式,优先显示网络数据
    public void refresh() {
        querySuggestion (QueryDataHelper.Type.REFRESH);
    }

@SuppressLint("CheckResult")
	//订阅返回的结果,并执行相应的逻辑
    private void querySuggestion(QueryDataHelper.Type type){
        new QuerySuggestionHelper ().queryData (type)
                .subscribe (new Consumer<Suggestion> () {
                    @Override
                    public void accept(Suggestion suggestion) throws Exception {
                    	//成功就显示出数据
                        mWeatherActivityView.showSuggestion (suggestion);
                    }
                }, new Consumer<Throwable> () {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                    	//失败显示错误信息
                        throwable.printStackTrace ();
                        mWeatherActivityView.showError (SUGGESTION_ERROR_MESSAGE);
                    }
                });
    }

这里只是简单的封装了一个小工具,代码量并没有减少,但是明显感觉结构更清晰,耦合度降低。方便维护和管理。
Rxjava2真的是一个非常好用的工具,用好了可以大大提升我们的开发效率。搭配Retrofit2更有意想不到的效果。这是Rxjava操作符的官网。我们需要的都在这里了。
后记:我是学习郭霖老师的第一行代码入坑的,学完rxjava后我用rxjava2+retrofit2重新写了一遍最后的实战天气项目,大家如果有空的话可以看看,提点建议呀,点点星星呀!!!
https://github.com/XiaogegeChen/Android-weather

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值