Search code examples
androidmortarsquare-flow

Recommended way to get Activity inside Mortar screen?


I am using Mortar and Flow to power my app. If I have the following View:

public class MyView extends LinearLayout {
  @Inject MyScreen.Presenter presenter;
  private EditText someText;

  public MyView(Context context) {
    super(context);
    Mortar.inject(context, this);
  }

  @Override protected void onFinishInflate() {
    super.onFinishInflate();

    presenter.takeView(this);
  }

  @Override protected void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    presenter.dropView(this);
  }
 }

And the following screen:

@Layout(R.layout.my_view)
public class MyScreen implements Blueprint {
  @Override public String getMortarScopeName() {
    return getClass().getName();
  }

  @Override public Object getDaggerModule() {
    return new Module();
  }

  @dagger.Module(injects = MyView.class, addsTo = MyActivity.Module.class)
  public class Module {
  }

  @Singleton
  public class Presenter extends ViewPresenter<MyView> {
    private final SomeAsyncService service;

    @Inject
    Presenter() { }

    @Override public void onLoad(Bundle savedInstanceState) {
    }

    @Override public void onSave(Bundle outState) {
    }

  }
}

Now I would like to get access to Activity which is using this Screen and View. I would to have access to some of the Activity methods like:

getWindow()
finish()
getLayoutInflater()
getFragmentManager()

etc

I have tried to cast a Context like this inside my Screen:

Activity activity = (Activity)getView.getContext;

But this of course throws the following exception:

java.lang.ClassCastException: mortar.MortarContextWrapper cannot be cast to 
android.app.Activity

How to get that activity? Thank you.


Solution

  • Not for sure, but Mortar is not recommended to use activity instance directly ?

    This mortal sample is helpful. So, I implemented as follows.

    class WindowOwner extends Presenter<WindowOwner.Activity> {
    
        interface Activity {
            void addFragsToWindow(int flags);
        }
    
        public static class Config() {
            final private int flags;
            Config(int flags) { this.flags = flags; }
            public int getFlags() { return this.flags; }
        }
    
        private Config config;
    
        public void setConfig(Config config) {
            this.config = config;
            update();
        }
    
        private void update() {
             WindowOwner.Activity activity = getView();
             if (activity != null) {
                  activity.addFlagsToWindow(config.getFlags());
             }
        }
    
        @dagger.Module(injects = {}, library = true)
        public static class WindowOwnerModule {
             @Provides
             @Singleton
             WindowOwner provideWindowOwnerPersenter() { return new WindowOwner(); }
        }
    }
    

    You define a WindowOwner.Module , and include of this class to your module like this.

    @Module(injects = {}, library = true)
    public class AndroidModule {
    
        // WindowOwner provider
        @Provides
        @Singleton
        SystemBarOwner provideWindowOwnerPersenter() {
            return new WindowOwner();
        } 
    }
    
    @Module(
            includes = {
                AndroidModule.class, // Includes your modules
            },
            injects = {
                   MainApplication.class
            },
            library = true
    )
    public final class MainModule {
    
        private final MainApplication mApplication;
    
        public MainModule(MainApplication application) {
            mApplication = application;
        }
    
        @Provides
        @Singleton
        Application provideApplication() {
            return mApplication;
        }
    }
    

    And you implement Activivty like follows.

     class AwesomeActivity extends Activity implements WindowOwner.Activity {
          @Inject WindowOwner windowOwner;
    
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              Mortar.inject(this, this);
              this.windowOwner.takeView(this);
          }
    
          @Override
          void addFragsToWindow(int flags) {
              getWindow().addFlags(flags);
          }
     }
    

    You can be used via WindowOwner

    @Layout(R.layout.awesome_view)
    public class AwesomeScreen implements Blueprint {
    
        @Override
        public String getMortarScopeName() {
            return getClass().getName();
        }
    
        @Override
        public Object getDaggerModule() {
            return new Module(getViewState());
        }
    
        @dagger.Module(
                injects = {
                        AwesomeView.class // inject your view
                },
                addsTo = MainModule.class,
                library = true
        )
        public static class Module {
        }
    
        @Singleton
        public static class Presenter extends ViewPresenter<AwesomeView> {
    
             private final WindowOwner windowOwner;
    
             @Inject
             Presenter(WindowOwner windowOwner) {
                 this.windowOwner = systemBarOwner;
             }
    
             @Override
             protected void onEnterScope(MortarScope scope) {
                 super.onEnterScope(scope);
    
                 // Update window flags via WindowOwner.Config
                 this.windowOwner.setConfig(new WindowOwner.Config(YOUR_FLAGS));
             }
        }
    }