Mortar + Flow with third party libraries hooked to activity lifecycle

前端 未结 2 655
心在旅途
心在旅途 2021-01-30 18:52

Some third party libraries use hooks into the activity lifecycle to work correctly - for instance, the Facebook SDK (https://developers.facebook.com/docs/android/login-with-face

2条回答
  •  逝去的感伤
    2021-01-30 19:21

    We haven't had a need for start and stop so far, but do have a few spots that rely on pause and resume. We use an ActivityPresenter as you suggest, but avoid any kind of universal superclass. Instead it exposes a service that interested presenters can opt in to. This kind of hookup need is why the onEnterScope(Scope) method was added. Here's the code.

    First, have the activity implement this interface:

    /**
     * Implemented by {@link android.app.Activity} instances whose pause / resume state
     * is to be shared. The activity must call {@link PauseAndResumePresenter#activityPaused()}
     * and {@link PauseAndResumePresenter#activityResumed()} at the obvious times.
     */
    public interface PauseAndResumeActivity {
      boolean isRunning();
    
      MortarScope getMortarScope();
    }
    

    And have it inject the presenter and make the appropriate calls:

    private boolean resumed;
    @Inject PauseAndResumePresenter pauseNarcPresenter;
    
    @Override protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      pauseNarcPresenter.takeView(this);
    }
    
    @Override public boolean isRunning() {
      return resumed;
    }
    
    @Override protected void onResume() {
      super.onResume();
      resumed = true;
      pauseNarcPresenter.activityResumed();
    }
    
    @Override protected void onPause() {
      resumed = false;
      super.onPause();
      pauseNarcPresenter.activityPaused();
    }
    
    @Override protected void onDestroy() {
      pauseNarcPresenter.dropView(this);
      super.onDestroy();
    }
    

    Now interested parties can inject a registrar interface to opt-in to pause and resume calls, without subclassing anything.

    /**
     * Provides means to listen for {@link android.app.Activity#onPause()} and {@link
     * android.app.Activity#onResume()}.
     */
    public interface PauseAndResumeRegistrar {
      /**
       * 

    Registers a {@link PausesAndResumes} client for the duration of the given {@link * MortarScope}. This method is debounced, redundant calls are safe. * *

    Calls {@link PausesAndResumes#onResume()} immediately if the host {@link * android.app.Activity} is currently running. */ void register(MortarScope scope, PausesAndResumes listener); /** Returns {@code true} if called between resume and pause. {@code false} otherwise. */ boolean isRunning(); }

    Have the client presenter implement this interface:

    /**
     * 

    Implemented by objects that need to know when the {@link android.app.Activity} pauses * and resumes. Sign up for service via {@link PauseAndResumeRegistrar#register(PausesAndResumes)}. * *

    Registered objects will also be subscribed to the {@link com.squareup.otto.OttoBus} * only while the activity is running. */ public interface PausesAndResumes { void onResume(); void onPause(); }

    And hook things up like this. (Note that there is no need to unregister.)

    private final PauseAndResumeRegistrar pauseAndResumeRegistrar;
    
    @Inject
    public Presenter(PauseAndResumeRegistrar pauseAndResumeRegistrar) {
      this.pauseAndResumeRegistrar = pauseAndResumeRegistrar;
    }
    
    @Override protected void onEnterScope(MortarScope scope) {
      pauseAndResumeRegistrar.register(scope, this);
    }
    
    @Override public void onResume() {
    }
    
    @Override public void onPause() {
    }
    

    Here's the presenter that the activity injects to make it all work.

    /**
     * Presenter to be registered by the {@link PauseAndResumeActivity}.
     */
    public class PauseAndResumePresenter extends Presenter
        implements PauseAndResumeRegistrar {
    
      private final Set registrations = new HashSet<>();
    
      PauseAndResumePresenter() {
      }
    
      @Override protected MortarScope extractScope(PauseAndResumeActivity view) {
        return view.getMortarScope();
      }
    
      @Override public void onExitScope() {
        registrations.clear();
      }
    
      @Override public void register(MortarScope scope, PausesAndResumes listener) {
        Registration registration = new Registration(listener);
        scope.register(registration);
    
        boolean added = registrations.add(registration);
        if (added && isRunning()) {
          listener.onResume();
        }
      }
    
      @Override public boolean isRunning() {
        return getView() != null && getView().isRunning();
      }
    
      public void activityPaused() {
        for (Registration registration : registrations) {
          registration.registrant.onPause();
        }
      }
    
      public void activityResumed() {
        for (Registration registration : registrations) {
          registration.registrant.onResume();
        }
      }
    
      private class Registration implements Scoped {
        final PausesAndResumes registrant;
    
        private Registration(PausesAndResumes registrant) {
          this.registrant = registrant;
        }
    
        @Override public void onEnterScope(MortarScope scope) {
        }
    
        @Override public void onExitScope() {
          registrations.remove(this);
        }
    
        @Override
        public boolean equals(Object o) {
          if (this == o) return true;
          if (o == null || getClass() != o.getClass()) return false;
    
          Registration that = (Registration) o;
    
          return registrant.equals(that.registrant);
        }
    
        @Override
        public int hashCode() {
          return registrant.hashCode();
        }
      }
    }
    

提交回复
热议问题