RxJava理解系列(一)


有人说RxJava非常好用,那么,它究竟好用在哪里?今天来具体分析下。
首先,先来阐述RxJava到底是什么,RxJava官方的解释是:“a library for composing asynchronous and event-based programs using observable sequences for the Java VM”,其核心就是“asynchronous”这个词,直白的说,RxJava就是一个实现异步操作的库。
那为什么大家会觉得RxJava好用,而不是使用AsyncTask/Handler...?这里可以归结一个词,简洁。
举个例子,我们要从网络上获取图片然后显示。利用AsyncTask的做法是这样的:
public class ImageTask extends AsyncTask<String, Void, Bitmap> {

        @Override
        protected Bitmap doInBackground(String... params) {

            String imageUrl = params[0];
            try {
                URL url = new URL(imageUrl);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                InputStream is = conn.getInputStream();
                Bitmap bitmap = BitmapFactory.decodeStream(is);
                if (bitmap != null) {
                    return bitmap;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            if(bitmap!=null){
                showBitMap();
            }
        }
    }
如果使用RxJava,那么实现方式是这样的:
   Observable.just(imageUrl)
                .map(new Func1<String, Bitmap>() {
                    @Override
                    public Bitmap call(String url) {
                        return getBitmapFromUrl(url);
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<Bitmap>() {
                    @Override
                    public void call(Bitmap bitmap) {
                        showBitMap();
                    }
                }); 
 可能有的朋友要说话了,(没看出什么区别啊,好用个毛线啊)。其实我们观察下就能发现,RxJava的这个实现,就是一条链式调用,在逻辑上没有任何的嵌套,简单明了,更进一步说,当我们需求变得复杂时,比如在大量的图片资源中选择一张,亦或者是选择前几张图片的时候,你还能在你那片代码中能迅速理清逻辑,并快速调整?RxJava在处理复杂逻辑时,一条链式调用,虽然很长,但胜在逻辑清晰。
 接下来,以一个例子具体阐述下RxJava到底逻辑清晰在哪里。有一个需求,谁是最可爱的人(sb需求,哈哈哈)。就是网络请求查询一组图片,每张图片有一个可爱系数(一个整型值),而我们的任务,就是下载一组可爱人的照片集合,然后选择最可爱的那个。

首先,定义一个简单的数据结构:
   public class CutestPeople implements Comparable<CutestPeople> {

    private Bitmap image;
    private int cuteness;

    @Override
    public int compareTo(CutestPeople cutestPeople) {
        return Integer.compare(cuteness, cutestPeople.cuteness);
    }
   }  

然后,提供获取查询和存储的api:

 public interface QueryApi {
    /** * 获取集合 * @param query * @return */
    List<CutestPeople>  queryCuestPeople(String query);
    /** * 获取需要保存的Uri * @param people * @return */
    Uri store(CutestPeople people);
}

最后,整体逻辑大体是这个样子的:

public class DataHelper {
    private QueryApi mApi;

    public Uri saveTheCutestPeople(String query) {
        List<CutestPeople> cutestPeoples = mApi.queryCuestPeople(query);
        CutestPeople cutestPeople = findCutestPeople(cutestPeoples);
        Uri savedUrl = mApi.store(cutestPeople);
        return savedUrl;
    }

    /** * 获取 * @param people * @return */
    public CutestPeople findCutestPeople(List<CutestPeople> people) {
        return Collections.max(people);
    }
}

等等,似乎少了什么,没错,异常处理机制,赶紧加上:

   try {
       List<CutestPeople> cutestPeoples = mApi.queryCuestPeople(query);
       CutestPeople cutestPeople = findCutestPeople(cutestPeoples);
       Uri savedUrl = mApi.store(cutestPeople);
       return savedUrl;
   } catch (Exception e) {
       e.printStackTrace();
       return error;
   }

看看上面的代码,我们继续优化,加入异步回调方式,现在QueryApi变成这样:

public interface QueryApi {


    interface CuestPeopleQueryCallback {
        void onCuestPeopleReceived(List<CutestPeople> people);
        void onQueryError(Exception e);
    }

    interface StoreCallback {
        void onCuestPeopleStore(Uri uri);
        void onStoreError(Exception e);
    }

    /** * 获取可爱人儿集合 * * @param query * @return */
    List<CutestPeople> queryCutestPeople(String query,CutestPeopleQueryCallback callback);

    /** * 保存最可爱的人到本地 * * @param people * @return */
    Uri store(CutestPeople people,StoreCallback callback);
}

相应的,我们的逻辑处理也进行相应的更改:

public class DataHelper {

    private QueryApi mApi;

    public interface CutestPeopleCallback {
        void onCutestPeopleSaved(Uri uri);
        void onError(Exception e);
    }

    public void saveTheCuestPeople(String query, final CutestPeopleCallback cutestCallback) {
     mApi.queryCutestPeople(query, new QueryApi.CutestPeopleQueryCallback() {
     @Override
     public void onCutestPeopleReceived(List<CutestPeople> people) {
        CutestPeople cutestPeople = findCutestPeople(people);
        mApi.store(cutestPeople, new QueryApi.StoreCallback() {
        @Override
        public void onCutestPeopleStore(Uri uri) {
                             cutestPeopleCallback.onCutestPeopleSaved(uri);
        }

        @Override
        public void onStoreError(Exception e) {
            cutestPeopleCallback.onError(e);
            }
          });
        }

            @Override
            public void onQueryError(Exception e) {
                cutestPeopleCallback.onError(e);
            }
        });
    }

    /** * 获取 * * @param people * @return */
    public CutestPeople findCutestPeople(List<CutestPeople> people) {

        return Collections.max(people);
    }
}

这样的代码看起来怎样?是不是非常的冗余,对于每一个异步操作,我们都需要定义相应的回调接口手动的一条条的进行插入,而且缺少错误传递机制。
接下来,我们继续修改上面的代码,目前,回调接口是这样的:

void onCutestPeopleReceived(List<CutestPeople> people);
void onCutestPeopleStore(Uri uri);
...
void onQueryError(Exception e);
void onStoreError(Exception e);

我们不能修改api中的方法,但是我们可以将上面的回调接口用泛型进行包装:

public interface Callback<T> {
    void onGetResult(T result);
    void onError(Exception e);
}

接下来,我们将Api的方法进行封装:

public class ApiWarpper {

    private QueryApi mApi;

    public void queryQuestPeople(String query, final MyCallback<List<CutestPeople>> myCallback) {

        mApi.queryCutestPeople(query, new QueryApi.CutestPeopleQueryCallback() {
            @Override
            public void onCutestPeopleReceived(List<CutestPeople> people) {
                myCallback.onGetResult(people);
            }

            @Override
            public void onQueryError(Exception e) {

                myCallback.onError(e);
            }
        });

    }

    public void storeUri(CutestPeople people, final MyCallback<Uri> myCallback) {
        mApi.store(people, new QueryApi.StoreCallback() {
            @Override
            public void onCutestPeopleStore(Uri uri) {
                myCallback.onGetResult(uri);
            }

            @Override
            public void onStoreError(Exception e) {
                myCallback.onError(e);
            }
        });
    }
}

最后,我们的逻辑处理优化后如下:

public class DataHelper {

    ApiWrapper mApiWrapper;

    public void saveTheCutestPeople(String query, final MyCallback<Uri> myCallBack) {

        mApiWrapper.queryQuestPeople(query, new MyCallback<List<CutestPeople>>() {
            @Override
            public void onGetResult(List<CutestPeople> result) {

                CutestPeople cutestPeople = findCutestPeople(result);
                mApiWrapper.storeUri(cutestPeople, myCallBack);
            }

            @Override
            public void onError(Exception e) {
                myCallBack.onError(e);
            }
        });

    }

    /** * 获取 * * @param people * @return */
    public CutestPeople findCutestPeople(List<CutestPeople> people) {

        return Collections.max(people);
    }
}

现在来说,目前代码大体没有什么问题,但是,我们能不能将异步操作分解为更小的操作,即每个异步操作仅仅只携带一个参数对象,然后返回一些携带着回调信息的临时对象。
接下来,定义一个通用的临时对象,该对象只携带一个参数对象:

public abstract class MyAsyncTask<T> {
    public abstract void start(MyCallback<T> callback);
}

修改ApiWrapper中的内容,如下所示:

public class ApiWrapper {

    private QueryApi mApi;

    public MyAsyncTask<List<CutestPeople>> queryQuestPeople(final String query) {
    return new MyAsyncTask<List<CutestPeople>>() {
    @Override
    public void start(final MyCallback<List<CutestPeople>> callback) {
       mApi.queryCutestPeople(query, new QueryApi.CutestPeopleQueryCallback() {
    @Override
    public void onCutestPeopleReceived(List<CutestPeople> people) {
       callback.onGetResult(people);
    }

    @Override
    public void onQueryError(Exception e) {
       callback.onError(e);
            }
         });
        }
      };
   }

    public MyAsyncTask<Uri> storeUri(final CutestPeople people){
        return new MyAsyncTask<Uri>() {
            @Override
            public void start(final MyCallback<Uri> callback) {

                mApi.store(people, new QueryApi.StoreCallback() {
                    @Override
                    public void onCutestPeopleStore(Uri uri) {
                        callback.onGetResult(uri);
                    }

                    @Override
                    public void onStoreError(Exception e) {

                        callback.onError(e);
                    }
                });
            }
        };
    }
}

相应的,逻辑部分进行相应的调整:

public class DataHelper {

    ApiWrapper mApiWrapper;

    public MyAsyncTask<Uri> saveTheCuestPeople(final String query) {

        final MyAsyncTask<List<CutestPeople>> listMyAsyncTask = mApiWrapper.queryQuestPeople(query);

        final MyAsyncTask<CutestPeople> myCutestAsyncTask = new MyAsyncTask<CutestPeople>() {

            @Override
            public void start(final MyCallback<CutestPeople> callback) {

             @Override
             public void onGetResult(List<CutestPeople> result) {                       
             callback.onGetResult(findCutestPeople(result));
             }

             @Override
             public void onError(Exception e) {
             callback.onError(e);
                }
             });
            }
        };

     MyAsyncTask<Uri> uriMyAsyncTask = new MyAsyncTask<Uri>() {
          @Override
          public void start(final MyCallback<Uri> callback) {
           myCutestAsyncTask.start(new MyCallback<CutestPeople>() {
                    @Override
                    public void onGetResult(CutestPeople result) {
                        mApiWrapper.storeUri(result)
                                .start(new MyCallback<Uri>() {
                                 @Override
                                public void onGetResult(Uri result) {
                                        callback.onGetResult(result);
                                    }

                                  @Override
                                  public void onError(Exception e) {
                                        callback.onError(e);
                                    }
                                });
                    }

                    @Override
                    public void onError(Exception e) {
                        callback.onError(e);
                    }
                });
            }
        };
        return uriMyAsyncTask;
    }


    /** * 获取 * * @param people * @return */

    public CutestPeople findCutestPeople(List<CutestPeople> people) {
        return Collections.max(people);
    }
}

这样的修改似乎更加复杂,但是,我们能够返回一个组合的操作,这样我们的Activity或者Fragment就能通过组合的工作来进行操作。

将我们的代码简化表达,如下所示:


public class DataHelper {

    ApiWrapper mApiWrapper;

    public MyAsyncTask<Uri> saveTheCuestPeople(final String query) {

      final MyAsyncTask<List<CutestPeople>> listMyAsyncTask = mApiWrapper.queryQuestPeople(query);

      final MyAsyncTask<CutestPeople> myCutestAsyncTask = new MyAsyncTask<CutestPeople>() { ...};
      MyAsyncTask<Uri> uriMyAsyncTask = new MyAsyncTask<Uri>() {...};
      return uriMyAsyncTask;
    }

    /** * 获取 * * @param people * @return */

    public CutestPeople findCutestPeople(List<CutestPeople> people) {
        return Collections.max(people);
    }

}

在来看看我们最初逻辑部分的代码:

public class DataHelper {
    private QueryApi mApi;

    public Uri saveTheCutestPeople(String query) {
        List<CutestPeople> cutestPeoples = mApi.queryCuestPeople(query);
        CutestPeople cutestPeople = findCutestPeople(cutestPeoples);
        Uri savedUrl = mApi.store(cutestPeople);
        return savedUrl;
    }

    /** * 获取 * @param people * @return */
    public CutestPeople findCutestPeople(List<CutestPeople> people) {
        return Collections.max(people);
    }
}

对比上述的代码,是否发现逻辑是一致的,区别是我们将异步操作都细分为更小的模块,然后组合在一起,最后返回一个组合后的结果对象而已。

写了这么多,我们到底是为了阐述什么呢?这个跟RxJava有什么关系呢?不急,我们接下来使用RxJava来实现上述这个需求,如下所示:

ApiWrapper类:

public class ApiWrapper {

    private QueryApi mApi;

    public Observable<List<CutestPeople>> queryQuestPeople(final String query) {

        return Observable.create(new Observable.OnSubscribe<List<CutestPeople>>() {
            @Override
            public void call(final Subscriber<? super List<CutestPeople>> subscriber) {

                mApi.queryCutestPeople(query, new QueryApi.CutestPeopleQueryCallback() {
                    @Override
                    public void onCutestPeopleReceived(List<CutestPeople> people) {
                        subscriber.onNext(people);
                    }

                    @Override
                    public void onQueryError(Exception e) {
                        subscriber.onError(e);
                    }
                });
            }
        });
    }

    public Observable<Uri> storeUri(final CutestPeople people) {
        return Observable.create(new Observable.OnSubscribe<Uri>() {
         @Override
         public void call(final Subscriber<? super Uri> subscriber) {
                mApi.store(people, new QueryApi.StoreCallback() {
                    @Override
                    public void onCutestPeopleStore(Uri uri) {
                        subscriber.onNext(uri);
                    }

                    @Override
                    public void onStoreError(Exception e) {
                        subscriber.onError(e);
                    }
                });
            }
        });
    }
}

DataHelper类:

public class DataHelper {

    ApiWrapper mApiWrapper;

    public Observable<Uri> saveTheCuestPeople(String query) {
        Observable<List<CutestPeople>> listObservable = mApiWrapper.queryQuestPeople(query);
        Observable<CutestPeople> cutestPeople = listObservable.map(new Func1<List<CutestPeople>, CutestPeople>() {
            @Override
            public CutestPeople call(List<CutestPeople> cutestPeoples) {
                return findCutestPeople(cutestPeoples);
            }
        });
        Observable<Uri> storeObservable = cutestPeople.flatMap(new Func1<CutestPeople, Observable<Uri>>() {
            @Override
            public Observable<Uri> call(CutestPeople people) {
                return mApiWrapper.storeUri(people);
            }
        });
        return storeObservable;
    }

    /** * 获取 * * @param people * @return */

    public CutestPeople findCutestPeople(List<CutestPeople> people) {

        return Collections.max(people);
    }

}

利用lambdas表达式我们再看看这段逻辑代码:

public class DataHelper {
    ApiWrapper mApiWrapper;

    public Observable<Uri> saveTheCuestPeople(String query) {
        Observable<List<CutestPeople>> listObservable = mApiWrapper.queryQuestPeople(query);

        Observable<CutestPeople> cutestPeopleObservable = listObservable.map(peopleList -> findCutestPeople(peopleList));

        Observable<Uri> storeObservable = cutestPeopleObservable.flatMap(people -> mApiWrapper.storeUri(people));

        return storeObservable;
    }

    public CutestPeople findCutestPeople(List<CutestPeople> people) {
        return Collections.max(people);
    }
}

利用Rxjava实现的逻辑,跟我们最初实现的逻辑基本一致,而区别就是利用RxJava将一个个的异步操作单独的抽象出来,这样我们可以避免各种嵌套的回调,然后将这些抽象出来的异步操作进行组合作为一个结果返回即可。

总结:Rxjava的核心思想就是处理异步操作,将异步操作独立的抽象出来,在异步操作非常复杂的情况下,Rxjava以一条链式调用来将一系列复杂的逻辑穿成一条线,从而实现代码的简洁性与易读性。

参考文献:
[https://github.com/cn-ljb/rxjava_for_android]


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
© 2014-2019 ITdaan.com 粤ICP备14056181号  

赞助商广告