3

I have an application with let's say 15 screens. There are 3 main, completely separate Activities:

  • LoginActivity - quite obvious one, some login things
  • MainActivity - THE big one, most importat
  • TheOtherOneNotRelevantAtTheMoment

I decided to use Conductor, because I've found Fragment's lifecycle too complicated, and for me Conductor is now "hot shit"

I've got many Conductor's controllers. Most of them are like XXXListController with corresponding XXXDetailController. All of these Controllers live only inside MainActivity. It's something like "single-activity-application". LoginActivity was introduced basically due to callbacks from third party OAuths like FbLogin & Google Login. I am just trying to make MainActivity completely mine - without any other strange behaviours.

To organize the dependencies a little bit, I've decided to use Dagger2. I've got quite good experience with Spring and JavaEE so I though it would be easy.

I recognized few Modules without any problems:

AppModule - with my App-related things like server address etc AndroidModule - with things like SharedPreferences, Application

Then I've pretty much "improvised" with how to organize my views. This is what I've got:

  • 3 additional Scopes: ActivityScope, ControllerScope, and ServiceScope - not relevant.
  • each Controller has it's own corresponding Module & Component. I've read that this could not be a very good idea, but I am ok with it - each Controller is pretty independend and has it's own unique set of dependencies.
  • ApplicationComponent is of course root of the hierarchy.
  • MainActivityComponent is a @Subcomponent of the ApplicationComponent
  • XXXControllerComponent is a @Subcomponent of the MainActivityComponent

To inject dependencies inside MainActivity I am using and I found this code pretty common:

protected void injectDependencies(ApplicationComponent component) {
    component.plus(new MainActivityModule(this)).inject(this);
}

The problem appears when I want to create & inject dependencies to my Controllers.

The MainActivity looks as follows:

@ActivityScope
@Subcomponent(modules = {
        MainActivityModule.class
})
public interface MainActivityComponent {

    XXXListComponent newXXXListComponent(XXXListModule xxxListModule);

    void inject(MainActivity activity);
}

At the moment, the typical Controller looks like this:

@ControllerScope
@Subcomponent(modules = {
        XXXListModule.class
})
public interface XXXListComponent {
    void inject(XXXListController controller);
}

and the corresponding Module:

@Module
public class XXXListModule {

    private XXXListController listController;

    public XXXListModule(XXXListController listController) {
        this.listController = listController;
    }

    @Provides
    @ControllerScope
    public XXXListController getMainView() {
        return ListController;
    }
// other not important
}

Basically every Controller should be singleton - I don't want to have two instances inside MainActivity - but this not a 'must-have'.

The problem is how to create Controller the right way. At the moment, MainActivity do it as follows:

router.pushController(RouterTransaction.with(new XXXListController()));

I am not sure about this, why to create Controller by hand?

Inside Controller in onCreateView() I've injecting all needed dependencies - in my opinion in very ugly way:

((MainActivity) getActivity()).getMainActivityComponent()
    .newXXXListComponent(new XXXListModule(this))
    .inject(this);

This long question helps me organize my knowledge about Dagger - maybe someone find it helpful. But! For those Stackoverflowers who reach this line, is this a good way or is there any other, better way to do it?

Kai
  • 1,709
  • 1
  • 23
  • 36
Michał
  • 616
  • 1
  • 7
  • 22

1 Answers1

0

I'm not sure I fully understand your question, but since you have multiple Activities you probably want to do your injecting inside your Application rather than MainActivity. Otherwise they will no longer be singletons as the activities get re-created when you move between them. For example if you make a class called ConductorApplication:

public class ConductorApplication extends Application {
    static AppComponent app_component;
    static ClockComponent component;

    @Override
    public void onCreate() {
        super.onCreate();
        app_component = DaggerAppComponent.builder().appModule(new AppModule(this)).build();
        component = createComponent();
    }



    protected ClockComponent createComponent() {
        return DaggerClockComponent.builder().build();
    }

    public static ClockComponent getClockComponent() {
        return component;
    }

    public ClockComponent component() {
        return component;
    }

    public static AppComponent GetAppComponent() {
        return app_component;
    }
}

Then inside when your controller is created eg inside your inflateView() within HomeController

public class HomeController extends BaseController {

    private HomeViewModel homeViewModel;
    private ControllerHomeBinding binding;


    @Inject
    Clock clock;

    @NonNull
    @Override
    protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
        ConductorApplication.getClockComponent().inject(this);
        return inflater.inflate(R.layout.controller_home, container, false);
...
}

If you haven't already, you may need to add:

<application 
    android:name=".ConductorApplication" 
    ...
    <activity
        android:name=".MainActivity"
        ...
    </activity>
</application>

inside your AndroidMainifest.xml

Kai
  • 1,709
  • 1
  • 23
  • 36