写于 2017年 05 月 24 日

public interface Api{
    void queryPhoto(String query,QueryCallback QueryCallback);
    interface QueryCallback{
        void onQuerySuccess(List<Photo> photoList);
        void onQueryFailed(Exception e);
    }
}
public class PhotoUtils{
    Api mApi;
    public void handlePhotoSync(){
        mApi.queryPhoto("flyer", new Api.QueryCallback() {
            @Override
            public void onQuerySuccess(List<Photo> photoList) {
                Photo photo = getBestPhoto(photoList);
              	String imgUrl = photo.getUrl();
            }

            @Override
            public void onQueryFailed(Exception e) {
				ToastUtils.show(e);
            }
        });
    }
}

此时假设有一个包裹类,他可以运行 getBestPhoto(photoList)photo.getUrl() 这两行代码,而这两行代码由外部放入

那么调用就会如下:

RxJob<List<Photo>> queryPhotoJob = new RxJob<List<Photo>>(){
  				@Override
                public void doJob(final RxCallback<List<Photo>> rxCallback) {
                    mApi.queryPhoto("flyer", new Api.QueryCallback() {
                        @Override
                        public void onQuerySuccess(List<Photo> photoList) {
                            rxCallback.onNext(photoList);
                        }
                      

                        @Override
                        public void onQueryFailed(Exception e) {
                            rxCallback.onError(e);
                        }
                    });
                }
            };
};
  // 如果有这么一个包裹类,代码就可以写成下面这样,则当需要调用的时候,
  // 代码就会和 RxJava 很类似( java 8 上会变成 Lambda 表达式 )
  // 从而使得代码具有很清晰的逻辑,异步代码看上去也会变的如同步代码一样。
queryPhotoJob
  .map(photoList -> { return getBestPhoto(photoList);})
  //.map(new Func<List<Photo>,Photo>()
  //          @Overide
  //          Photo call(List<Photo> photoList){
  //		    return getBestPhoto(photoList);
  //		  })
  .map(photo -> {return photo.getUrl()})
  .doJob(new RxCallback<T>() {
            @Override
            public void onNext(T t) {

            }

            @Override
            public void onError(Exception e) {

            }
   });

因此接下来需要考虑如何实现这个包裹的类,使得其调用会像 RxJava 一般。首先需要确定该类需要处理以下几个问题

  • 该包裹的类有哪些方法及其使用
  • map 函数如何实现,其调用逻辑

整体介绍:

确定一个包裹类 —> 创建包裹类 new RxJob() —> map 方法实现

map 方法实现包括 :

入参和出参的基本类型确定 —> 转变函数的确定 —> doJob 调用 —> map 返还值具体介绍 —> func.call() 返还值的传递

包裹类方法和作用

首先取名,该类叫 RxJob

RxJob 类的意义,它被定义成一个任务,类似 AsyncTask ,而运行该任务的方法就是 doJob 有入参 RxCallback

类的定义还有一个泛型 T ,主要决定了 doJob 方法中 RxCallback<T> 中的 T 类型

该类型会影响很多部分的参数类型,具体需要参考后面的分析。

代码如下:

public abstract class RxJob<T> {
    public abstract void doJob(RxCallback<T> rxCallback);
    public <R> RxJob<T> map(final Func<T,R> func){...}
}

先忽略 map 方法,现看 doJob(RxCallback<T> rxCallback)

doJob(RxCallback<T> rxCallback) 有一个回调,回调接口定义如下:

public interface RxCallback<T> {
    void onNext(T t);
    void onError(Exception e);
}

两个方法,onNext(T t)onError(Exception e) ,一个用来传递内容 T,一个用来处理错误

也就是说,RxJob 执行的内容最终都是 doJob(RxCallback<T> rxCallback) 方法,这个方法是链接起所有回调的核心

保证了所有的方法能一个一个根据链式调用一个一个执行

创建包裹类 new RxJob(..)

直接带入当前的栗子中,代码如下

RxJob<List<Photo>> queryPhotoJob = new RxJob<List<Photo>>(){
  	        @Override
                public void doJob(final RxCallback<List<Photo>> rxCallback) {
                    mApi.queryPhoto("flyer", new Api.QueryCallback() {
                        @Override
                        public void onQuerySuccess(List<Photo> photoList) {
                            rxCallback.onNext(photoList);
                        }
                      

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

其中RxJob<T> 中的 T 的值是 List<Photo>,这主要决定于 mApi.queryPhoto()onQuerySuccess(List<Photo> photoList) 中的参数类型,让 rxCallback.onNext(photoList) 能取到对应的类型。从而把拿到的数据内容,借助 RxCallback 回调往外层抛出。

即,如果我们需要调用 queryPhotoJob ,让他执行对应的操作代码如下

queryPhotoJob.doJob(new RxCallback<List<Photo>>(){
  	public void onNext(List<Photo> photoList){
           Photo photo = getBestPhoto(photoList);
           String imgUrl = photo.getUrl();
  	}
  	public void onError(Exception e){...}
});

核心部分 map 函数如何实现

首先可以确定的是 map 函数返回的类型肯定是 RxJob,因为 map方法是可以连续调用的,

其次,可以确定 map 函数的入参是 Func

一个匿名内部类(Java 8 中的 Lambda 表达式),在其他某些语言中就是函数对象、函数引用之类的

由此可以确定 map 方法基本的样子如下代码:

public RxJob map(Func<T,R> func){
  	...
    return rxJob;
};

然后考虑入参 Func<T,R> func 的实现,即这个转变函数该如何实现。

1. 转变函数的确定

首先可以确定这个匿名内部类会实现一个从 T 类型—> R 类型的转换,

其次 func 对象是在 map 方法调用的时候,才确定具体的实现内容,因此,它必然是一个接口或者抽象方法,待实现

然后,考虑到 T 类型—> R 类型 的转换在具体代码编写的时候是可以确定的,由此考虑可以用泛型方法和泛型类就可以实现。

从而创建 Func<T,R> 接口,该接口有一个 R call(T t) 方法待实现

看如下代码:

public interface Func<T,R> {
    /**
     *
     * @param t transform 的对象类型
     * @return 返还的对象类型
     */
    R call(T t);
}

该方法返回的类型,是泛型类 Func<T,R> 中的 R,其入参是泛型类 Func<T,R> 中的 T

即该类的作用就是进行一个从 T —> R 的转换,而具体的转换方法由外部实现。

应用到上面的例子就是,List —> Photo 的转换,即 R call<T t> 方法 变成了 Photo call<List photoList>

于是乎,代码就变成了如下的样子

RxJob queryPhotoJob = new RxJob(..)...;
queryPhotoJob
  .map(new Func<List<Photo>,Photo>()
            @Overide
            Photo call(List<Photo> photoList){
			    return getBestPhoto(photoList);
  			})
  // 同理第二个 map 就成了如下,
  // 入参是上个操作的出参 Photo
  // 而出参则是 String 类型的
  .map(new Func<Photo,String>(){
            @Overide
            String call(Photo photo){
                return photo.getUrl()//返还 String 类型
            }
          })
  .doJob(...);

至此,map 函数的入参整体已经介绍完毕。

2.doJob 方法的调用

然后考虑里面具体的调用逻辑,首先考虑任务调用,第一个 map 方法在触发的时候,queryPhotoJob 本身已经是一个 RxJob 对象了

它的实现内容也简单,在创建包裹类时已经有解释了。

queryPhotoJob.doJob(new RxCallback<List<Photo>>(){
  	public void onNext(List<Photo> photoList){..}
  	public void onError(Exception e){...}
});

也就是说,如果我要调用 map 方法触发传入的 func 匿名内部类,就必须先调用 queryPhotoJob.doJob(..)

于是把代码变成

public RxJob map(Func<T,R> func){
  rxJob.doJob(new RxCallback<T>() {
      @Override
      public void onNext(T t) {
      }

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

应用到上述例子中其具体的泛型值变化就成了如下代码

public RxJob map(Func<List<Photo>,R> func){
  rxJob.doJob(new RxCallback<List<Photo>>() {
      @Override
      public void onNext(List<Photo> photoList) {
      }

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

此时需要考虑的就是在哪里调用 func 函数,它是负责把T —> R

因此该部分代码必然是在当前任务执行完后,拿到当前任务的回调值,然后进行转换,即 map 方法会变成如下

public RxJob map(Func<T,R> func){
  rxJob.doJob(new RxCallback<T>() {
      @Override
      public void onNext(T t) {
        R mapped = func.call(t);
      }

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

3. map 方法返还值

接下来考虑返回值,首先 map 方法返回的是一个 RxJob对象

其次,因为当前任务已经执行完了,而下一个任务需要当前任务执行后处理的返回值,即func.call(t) 返回的 mapped

如果返回的是原有的 RxJob 那么每次调用 map 方法时执行的代码永远是 this.doJob 因此每次执行的内容都是第一个任务了

应用到此处就是 queryPhotoJob.doJob(..)

因此 map 方法返回的值应该是一个新创建的 RxJob 对象,并且该对象的 doJob 方法会先运行当前任务的 doJob 方法

代码如下:

public RxJob map(Func<T,R> func){
  	 RxJob curJob = this;
      return new RxJob() {
            @Override
            public void doJob(final RxCallback rxCallback) {
                curJob.doJob(new RxCallback<T>() {
                    @Override
                    public void onNext(T t) {
                        R mapped = func.call(t);
                      	...
                    }

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

把当前例子的泛型值带入如下:

public RxJob map(Func<List<Photo>,R> func){
  	 RxJob queryPhotoJob = this;
     RxJob mapJob = new RxJob() {
            @Override
            public void doJob(final RxCallback rxCallback) {
                queryPhotoJob.doJob(new RxCallback<List<Photo>>() {
                    @Override
                    public void onNext(List<Photo> photoList) {
                        R mapped = func.call(photoList);
                      	...
                    }

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

4. func.call() 的返还值传递

考虑如何把 func.call() 调用后的返回的数据往下一个 RxJob 传递

直接调用下一个 RxJob 中回调的 rxCallback.onNext()方法即可,对于错误也同样调用 rxCallback.onError(e) 即可。

public RxJob map(Func<T,R> func){
  	 RxJob curJob = this;
      return new RxJob() {
            @Override
            public void doJob(final RxCallback rxCallback) {
                curJob.doJob(new RxCallback<T>() {
                    @Override
                    public void onNext(T t) {
                        R mapped = func.call(t);
                      	rxCallback.onNext(t);
                    }

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

代入当前例子:

public RxJob map(Func<List<Photo>,R> func){
  	 RxJob<List<Photo>> queryPhotoJob = this;
     RxJob mapJob = new RxJob() {
            @Override
            public void doJob(final RxCallback mapJobCallback) {
                queryPhotoJob.doJob(new RxCallback<List<Photo>>() {
                    @Override
                    public void onNext(List<Photo> photoList) {
                        R mapped = func.call(photoList);
                      	mapJobCallback.onNext(mapped);
                    }

                    @Override
                    public void onError(Exception e) {
                        mapJobCallback.onError(e);
                    }
                });
            }
        };
  return mapJob;
}

最终只需要确定泛型参数类型 R,他的作用是确定下一个RxJob 对象的泛型值

Rfunc.call() 方法 确定,也就是之前说的,在具体的 map 方法被调用时,参数的泛型值是可以确定的

Func 函数负责把 T —> R 转换,因此,最终的 map 方法如下:

public <R> RxJob<R> map(Func<T,R> func){
      RxJob curJob = this;
      return new RxJob<R>() {
            @Override
            public void doJob(final RxCallback<R> rxCallback) {
                curJob.doJob(new RxCallback<T>() {
                    @Override
                    public void onNext(T t) {
                        R mapped = func.call(t);
                        rxCallback.onNext(mapped);
                    }

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

应用到当前例子,带入泛型值如下

public<Photo> RxJob<Photo> map(Func<List<Photo>,Photo> func){
  	 RxJob<List<Photo>> queryPhotoJob = this;
     RxJob<Photo> mapJob = new RxJob<Photo>() {
            @Override
            public void doJob(final RxCallback<Photo> mapJobCallback) {
                queryPhotoJob.doJob(new RxCallback<List<Photo>>() {
                    @Override
                    public void onNext(List<Photo> photoList) {
                        Photo mapped = func.call(photoList);
                      	mapJobCallback.onNext(mapped);
                    }

                    @Override
                    public void onError(Exception e) {
                        mapJobCallback.onError(e);
                    }
                });
            }
        };
  return mapJob;
}

整个任务如何运行

RxJob<List<Photo>> queryPhotoJob = new RxJob<List<Photo>>(){
  				@Override
                public void doJob(final RxCallback<List<Photo>> rxCallback) {
                    mApi.queryPhoto("flyer", new Api.QueryCallback() {
                        @Override
                        public void onQuerySuccess(List<Photo> photoList) {
                            rxCallback.onNext(photoList);
                        }
                      

                        @Override
                        public void onQueryFailed(Exception e) {
                            rxCallback.onError(e);
                        }
                    });
                }
            };
};
RxJob<Photo> bestPhotoJob = queryPhotoJob.map(photoList -> { return getBestPhoto(photoList);})
RxJob<String> urlJob = .map(photo -> {return photo.getUrl();})
urlJob.doJob(new RxCallback<String>() {
            @Override
            public void onNext(String s) {
				ToastUtils.show(s);
            }

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

解释代码,第一个 map 方法 返还了一个 RxJob<Photo> 对象,第二个 map 返还了一个 RxJob<String> 对象,第三个 doJob 方法触发整个任务

doJob 方法触发的第一个方法是 urlJob 中的 doJob 方法,由于 urlJob 对象是由 map 方法创建的

因此,在执行 ToastUtils.show(s) 方法之前,会先执行 bestPhotoJob.doJob()

同样,queryPhotoJob.doJob()也会执行在 bestPhotoJob.doJob() 方法之前

因此整体过程就是 queryPhotoJob.doJob()—> bestPhotoJob.doJob() —> urlJob.doJob()

而这执行过程中,R mapped = func.call(T) 会先被调用,因此单个 RxJob 调用链如下:

在调用每个 RxJob.onNex()情况下(即成功的情况下,没有出错)

queryPhotoJob.doJob() : mApi.query —> func.call(t) —> getBestPhoto(photoList)

bestPhotoJob.doJob()func.call(t) —> photo.getUrl()

urlJob.doJob()ToastUtil.show()

比较炫酷的写法如下:

RxJob<List<Photo>> queryPhotoJob = new RxJob<List<Photo>>(){
  				@Override
                public void doJob(final RxCallback<List<Photo>> rxCallback) {
                    mApi.queryPhoto("flyer", new Api.QueryCallback() {
                        @Override
                        public void onQuerySuccess(List<Photo> photoList) {
                            rxCallback.onNext(photoList);
                        }
                      

                        @Override
                        public void onQueryFailed(Exception e) {
                            rxCallback.onError(e);
                        }
                    });
                }
            };
};
queryPhotoJob
  .map(photoList -> { return getBestPhoto(photoList);})
  .map(photo -> {return photo.getUrl()})
  .doJob(...);

=================================

异步里面还有异步方法,flatMap 待续

=================================