美文网首页Android 开发技术分享Android开发Android开发学习
Retrofit结合Lifecycle, 将Http生命周期管理

Retrofit结合Lifecycle, 将Http生命周期管理

作者: xcheng_ | 来源:发表于2019-08-27 15:11 被阅读0次
    http请求一直是开发中无法避免的存在,生命周期的管理也一直是开发者的痛点,稍不注意就在回调是抛出异常,如NullPointerException,showDialog导致的WindowLeaked等。

    Google 最新推荐的 Lifecycle 架构就是可以让你自己的类拥有像 activity 或 fragment 一样生命周期的功能。

    于是我决定采用lifecycle结合retrofit 将http请求和Activity或Fragment的生命周期相结合

    本文将从以下几个方面一步步实现功能

    • 多线程分发Lifecycle. Event
    • retrofit如何与其关联?自定义 CallAdapter.Factory
    • 异步请求如何关联
    • 同步请求如何关联

    如果有不熟悉lifecycle的可以自行学习,这里不做介绍了

    lifecycle官方文档地址:https://developer.android.com/topic/libraries/architecture/lifecycle

    为什么要使用lifecycle?

    activity 和fragment 是有声明周期的,有时候,我们的很多操作需要写在声明周期的方法中,比如,下载,文件操作等,这样很多情况下回导致,我们在activity中的声明周期方法中写越来越多的代码,activity或者fragment 越来越臃肿,代码维护越来越困难。 使用lifecycle就可以很好的解决这类问题。
    lifecycle代码简洁,我们可以通过实现LifecycleObserver 接口,来监听声明周期,然后我们在activity和fragment中去注册监听。

    一 、分发lifecycle event

    对于event的分发我们采用观察者模式,需要支持多线程环境,因为http请求可能在任意线程中发起。

    首先定义一个 LifecycleProvider类,如下

    /**
     * 统一分发Activity和 Fragment的生命周期时间.
     */
    public interface LifecycleProvider {
        /**
         * Adds an observer to the list. The observer cannot be null and it must not already
         * be registered.
         *
         * @param observer the observer to register
         * @throws IllegalArgumentException the observer is null
         */
        void observe(Observer observer);
    
        /**
         * Removes a previously registered observer. The observer must not be null and it
         * must already have been registered.
         *
         * @param observer the observer to unregister
         * @throws IllegalArgumentException the observer is null
         */
        void removeObserver(Observer observer);
    
        /**
         * A simple callback that can receive from {@link android.arch.lifecycle.Lifecycle}
         */
        interface Observer {
            /**
             * Called when the event is changed.
             *
             * @param event The new event
             */
            void onChanged(@NonNull Lifecycle.Event event);
        }
    }
    

    实现类 为AndroidLifecycle 继承了LifecycleObserver接口监听Lifecycle event

    public final class AndroidLifecycle implements LifecycleProvider, LifecycleObserver {
        private final Object mLock = new Object();
    
        @GuardedBy("mLock")
        private final ArrayList<Observer> mObservers = new ArrayList<>();
        /**
         * 缓存当前的Event事件
         */
        @GuardedBy("mLock")
        @Nullable
        private Lifecycle.Event mEvent;
    
        @MainThread
        public static LifecycleProvider createLifecycleProvider(LifecycleOwner owner) {
            return new AndroidLifecycle(owner);
        }
    
        private AndroidLifecycle(LifecycleOwner owner) {
            owner.getLifecycle().addObserver(this);
        }
    
        @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
        void onEvent(LifecycleOwner owner, Lifecycle.Event event) {
            synchronized (mLock) {
                //保证线程的可见性
                mEvent = event;
                for (int i = mObservers.size() - 1; i >= 0; i--) {
                    mObservers.get(i).onChanged(event);
                }
            }
            if (event == Lifecycle.Event.ON_DESTROY) {
                owner.getLifecycle().removeObserver(this);
            }
        }
    
        @Override
        public void observe(Observer observer) {
            if (observer == null) {
                throw new IllegalArgumentException("The observer is null.");
            }
            synchronized (mLock) {
                if (mObservers.contains(observer)) {
                    return;
                }
                mObservers.add(observer);
                if (mEvent != null) {
                    observer.onChanged(mEvent);
                }
            }
        }
    
        @Override
        public void removeObserver(Observer observer) {
            if (observer == null) {
                throw new IllegalArgumentException("The observer is null.");
            }
            synchronized (mLock) {
                int index = mObservers.indexOf(observer);
                if (index == -1) {
                    return;
                }
                mObservers.remove(index);
            }
        }
    }
    

    使用时只要在onChanged方法中就可以处理对应的事件,使用如下

        LifecycleProvider provider = AndroidLifecycle.createLifecycleProvider(this);
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            provider.observe(new LifecycleProvider.Observer() {
                @Override
                public void onChanged(@NonNull Lifecycle.Event event) {
                    //do...
                }
            });
        }
    
    

    observe方法不依赖于主线程,可以在任何地方调用。这样二次分发设计的目的有两个

    • owner.getLifecycle().addObserver(LifecycleObserver)方法是线程不安全的,需要依赖主线程

    • 可以缓存最新的Lifecycle.Event

    二、retrofit 关联生命周期

    ​ retrofit 如何才能关联生命周期呢,通用的做法肯定是自定义CallAdapter.Factory,我们可以返回我们想要的自定义Call,在Call接口添加bindToLifecycle方法于LifecycleProvider相关联

    • 自定义Call接口如下,添加了绑定生命周期的方法,这里只展示核心方法
    public interface Call<T> extends Callable<T>, Cloneable {
              //忽略其他代码
        /**
         * 绑定生命周期
         *
         * @param provider LifecycleProvider
         * @param event    {@link Lifecycle.Event}, {@link Lifecycle.Event#ON_ANY} is not allowed
         * @return LifeCall
         */
        LifeCall<T> bindToLifecycle(LifecycleProvider provider, Lifecycle.Event event);
    
        /**
         * default event is {@link Lifecycle.Event#ON_DESTROY}
         *
         * @param provider LifecycleProvider
         * @return LifeCall
         * @see Call#bindToLifecycle(LifecycleProvider, Lifecycle.Event)
         */
        LifeCall<T> bindUntilDestroy(LifecycleProvider provider);
    }
    
    • ​ 且看如何实现此接口 RealCall

      final class RealCall<T> implements Call<T> {
            //忽略其他代码
          @Override
          public LifeCall<T> bindToLifecycle(LifecycleProvider provider, Lifecycle.Event event) {
              Utils.checkNotNull(provider, "provider==null");
              Utils.checkNotNull(event, "event==null");
              if (event == Lifecycle.Event.ON_ANY) {
                  throw new IllegalArgumentException("ON_ANY event is not allowed.");
              }
              return new RealLifeCall<>(clone(), event, provider);
          }
      
          @Override
          public LifeCall<T> bindUntilDestroy(LifecycleProvider provider) {
              return bindToLifecycle(provider, Lifecycle.Event.ON_DESTROY);
          }
      }
      
    • LifeCall 生命周期管理的接口类,它继承了LifecycleProvider.Observer,因此可以在onChanged方法接收分发的Lifecycle.Event

      public interface LifeCall<T> extends Callable<T>, LifecycleProvider.Observer {
      
          /**
           * Returns true if this call has been disposed.
           *
           * @return true if this call has been disposed
           */
          boolean isDisposed();
          /**
           * The method may be called concurrently from multiple
           * threads; the method must be thread safe. Calling this method multiple
           * times has no effect.
           * <p>
           * like {@code Observable#doOnDispose(Action)},{@code SingleSubject#onSuccess(Object)}
           * <p>
           * you can invoke with {@link Lifecycle.Event#ON_ANY} to dispose from outside immediately.
           */
          @Override
          void onChanged(@NonNull Lifecycle.Event event);
      }
      
    • 且看如何实现此接口RealLifeCall

      onChanged中判断,当event参数为指定的event时取消请求,并且标记为disposed,从provider中移除RealLifeCall观察对象。注意的是可以手动调用LifeCall.onChanged(LifeCycle.Event.ON_ANY)取消请求用于你想处理的任何场景,如果isDisposed()返回为true,在异步Callback调用的情况下是不会回调的。

      final class RealLifeCall<T> implements LifeCall<T> {
          private final Call<T> delegate;
          private final Lifecycle.Event event;
          private final LifecycleProvider provider;
       
          private final AtomicBoolean once = new AtomicBoolean();
      
          RealLifeCall(Call<T> delegate, Lifecycle.Event event, LifecycleProvider provider) {
              this.delegate = delegate;
              this.event = event;
              this.provider = provider;
              provider.observe(this);
          }
            //忽略其他代码
            
          @Override
          public void onChanged(@NonNull Lifecycle.Event event) {
              if (this.event == event
                      || event == Lifecycle.Event.ON_DESTROY
                      //Activity和Fragment的生命周期是不会传入 {@code Lifecycle.Event.ON_ANY},
                      //可以手动调用此方法传入 {@code Lifecycle.Event.ON_ANY},用于区分是否为手动调用
                      || event == Lifecycle.Event.ON_ANY) {
                  if (once.compareAndSet(false, true)/*保证原子性*/) {
                      delegate.cancel();
                      provider.removeObserver(this);
                  }
              }
          }
          @Override
          public boolean isDisposed() {
              return once.get();
          }
      }
      
    • 如何返回Call ?自定义CallAdapter.Factory

    retrofit的解耦灵活我们可以做很多自定义的配置,自定义Factory返回我们的Call接口对象,只需在创建retrofit对象是调用addCallAdapterFactory(CallAdapterFactory.INSTANCE)添加进去即可。

    注:executor默认为Android主线程调度使用,Callback回调函数会在对应线程执行。详情可以看retrofit2.Platform.Android.defaultCallbackExecutor()方法

    public final class CallAdapterFactory extends CallAdapter.Factory {
        private static final String RETURN_TYPE = Call.class.getSimpleName();
    
        public static final CallAdapter.Factory INSTANCE = new CallAdapterFactory();
    
        private static final Executor OPTIONAL_NULL_EXECUTOR = new Executor() {
            @Override
            public void execute(@NonNull Runnable command) {
                command.run();
            }
        };
    
        private CallAdapterFactory() {
        }
        
        @Override
        public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
            if (getRawType(returnType) != Call.class) {
                return null;
            }
            if (!(returnType instanceof ParameterizedType)) {
                throw new IllegalArgumentException(
                        String.format("%s return type must be parameterized as %s<Foo> or %s<? extends Foo>", RETURN_TYPE, RETURN_TYPE, RETURN_TYPE));
            }
            final Type responseType = getParameterUpperBound(0, (ParameterizedType) returnType);
            final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
                    ? null
                    : retrofit.callbackExecutor();
            return new CallAdapter<Object, Call<?>>() {
                @Override
                public Type responseType() {
                    return responseType;
                }
    
                @Override
                public Call<Object> adapt(retrofit2.Call<Object> call) {
                    if (executor != null) {
                        return new RealCall<>(executor, call);
                    }
                    return new RealCall<>(OPTIONAL_NULL_EXECUTOR, call);
                }
            };
        }
    }
    
    • 丰富的Callback接口

      支持开始、结束、成功、失败、异常统一解析、简单的数据二次处理操作,HttpError统一包装异常信息

      public interface Callback<T> {
          /**
           * @param call The {@code Call} that was started
           */
          void onStart(Call<T> call);
        
          @NonNull
          HttpError parseThrowable(Call<T> call, Throwable t);
      
          /**
           * 过滤一次数据,如剔除List中的null等,默认可以返回t
           */
          @NonNull
          T transform(Call<T> call, T t);
      
          void onError(Call<T> call, HttpError error);
      
          void onSuccess(Call<T> call, T t);
      
          /**
           * @param t 请求失败的错误信息
           */
          void onCompleted(Call<T> call, @Nullable Throwable t);
      }
      
    • 异步调用

      定义接口

      @FormUrlEncoded
      @POST("user/login")
      Call<LoginInfo> getLogin(@Field("username") String username, @Field("password") String password);
      

      安全的异步发起请求:

      public class MainActivity extends AppCompatActivity {
      
          LifecycleProvider provider = AndroidLifecycle.createLifecycleProvider(this);
      
          @Override
          protected void onCreate(@Nullable Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              RetrofitFactory.create(ApiService.class)
                      .getLogin("loginName", "password")
                      //.bindUntilDestroy(provider)
                      .bindToLifecycle(provider, Lifecycle.Event.ON_STOP)
                      .enqueue(new DefaultCallback<LoginInfo>() {
                          @Override
                          public void onStart(Call<LoginInfo> call) {
                              showLoading();
                          }
      
                          @Override
                          public void onError(Call<LoginInfo> call, HttpError error) {
                              Toast.makeText(MainActivity.this, error.msg, Toast.LENGTH_SHORT).show();
                          }
      
                          @Override
                          public void onSuccess(Call<LoginInfo> call, LoginInfo loginInfo) {
                              Toast.makeText(MainActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
                          }
      
                          @Override
                          public void onCompleted(Call<LoginInfo> call, @Nullable Throwable t){
                              hideLoading();
                          }
                      });
          }
      
      }
      
    • 如何同步调用

      一般同步调用的场景不多,一些连续且相互依赖的请求可以使用同步请求减少逻辑复杂性

      如:注册成功后直接登录,如果采用异步的方式实现,回调接口缠绕在一起,代码不好维护。采用同步的方式实现更为方便。

      @FormUrlEncoded
      @POST("user/register")
      Call<RegisterInfo> register(@Field("username") String username, @Field("password") String password);
      
      @FormUrlEncoded
      @POST("user/login")
      Call<LoginInfo> getLogin(@Field("username") String username, @Field("password") String password);
      
      new Thread(){
          @Override
          public void run() {
              super.run();
              try {
                  RegisterInfo registerInfo=RetrofitFactory.create(ApiService.class)
                          .register("loginName", "password")
                          .bindToLifecycle(provider, Lifecycle.Event.ON_STOP)
                          .execute();
                  //注册成功开始登录
                  LoginInfo loginInfo=RetrofitFactory.create(ApiService.class)
                          .getLogin("loginName", "password")
                          .bindToLifecycle(provider, Lifecycle.Event.ON_STOP)
                          .execute();
                  //登录成功
                
      
              } catch (Throwable throwable) {
                  //异常处理
                  throwable.printStackTrace();
              }
          }
      }.start();
      

      这里涉及二个问题

      • 关于Thread,可以自行用线程池实现,这里制作演示

      • 线程调度,成功和失败的结果需要回调到主线程中,android中回调主线程采用的Handler.post(Runnable)或者postDelayed(Runnable, long)方法实现,当主线程调度执行run方法是可能Activity或者Fragment已经被销毁。那么怎样才能安全的回调到主线程呢?

        调度方法和生命周期关联,在主线程执行时再次做判断。NetTaskExecutor 是做的Handler的封装

      public final class ToMainThread implements LifecycleProvider.Observer {
          @Nullable
          private volatile Lifecycle.Event mEvent;
          private final LifecycleProvider provider;
      
          public ToMainThread(LifecycleProvider provider) {
              this.provider = provider;
              provider.observe(this);
          }
      
          public void to(@NonNull final Runnable runnable, final Lifecycle.Event event) {
              NetTaskExecutor.getInstance().postToMainThread(new Runnable() {
                  @Override
                  public void run() {
                      if (mEvent == event || mEvent == Lifecycle.Event.ON_DESTROY)
                          return;
                      runnable.run();
                  }
              });
      
          }
      
          public void toDelayed(@NonNull final Runnable runnable, final Lifecycle.Event event, long delayMillis) {
              NetTaskExecutor.getInstance().postToMainThreadDelayed(new Runnable() {
                  @Override
                  public void run() {
                      if (mEvent == event || mEvent == Lifecycle.Event.ON_DESTROY)
                          return;
                      runnable.run();
                  }
              }, delayMillis);
          }
      
          @Override
          public void onChanged(@NonNull Lifecycle.Event event) {
              this.mEvent = event;
              if (event == Lifecycle.Event.ON_DESTROY) {
                  provider.removeObserver(this);
              }
          }
      }
      

      完整的同步执行代码如下,这样处理完全关联了生命周期。不会出任何问题

      new Thread() {
          @Override
          public void run() {
              super.run();
              try {
                  RegisterInfo registerInfo = RetrofitFactory.create(ApiService.class)
                          .register("loginName", "password")
                          .bindToLifecycle(provider, Lifecycle.Event.ON_STOP)
                          .execute();
                  //注册成功开始登录
                  LoginInfo loginInfo = RetrofitFactory.create(ApiService.class)
                          .getLogin("loginName", "password")
                          .bindToLifecycle(provider, Lifecycle.Event.ON_STOP)
                          .execute();
                  //登录成功
                  toMainThread.to(new Runnable() {
                      @Override
                      public void run() {
                          Toast.makeText(MainActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
                      }
                  }, Lifecycle.Event.ON_STOP);
      
              } catch (Throwable throwable) {
                  //异常处理,这里只做简单的演示
                    //你可以对throwable做解析分类
                  toMainThread.to(new Runnable() {
                      @Override
                      public void run() {
                          Toast.makeText(MainActivity.this, "服务异常", Toast.LENGTH_SHORT).show();
                      }
                  }, Lifecycle.Event.ON_STOP);
              }
          }
      };
      

    相关文章

      网友评论

        本文标题:Retrofit结合Lifecycle, 将Http生命周期管理

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