I'm trying to adapt Mortar&Flow in my app and faced with an issue, that I can't make PageAdapter works with Screens, instead of Fragments.
Anyone managed to get it right?
I didn't succeed but, probably someone can guide me from this point:
The initial Dagger Registration:
@Module(
injects = {
MainActivity.class,
},
library = true,
complete = false
)
public class DaggerConfig {
@SuppressWarnings("unused")
@Provides @Singleton Gson provideGson() {
return new GsonBuilder().create();
}
}
MainScreen, whose View is hosting ViewPager:
@Layout(R.layout.screen_main) @WithModule(MainScreen.Module.class)
public class MainScreen extends Path {
@dagger.Module(injects = MainView.class, addsTo = DaggerConfig.class)
public static class Module {}
@Singleton
public static class Presenter extends ViewPresenter<MainView> {
@Inject
public Presenter() {}
}
}
MainView:
...........
@Inject
MainScreen.Presenter presenter;
...........
@Override protected void onFinishInflate() {
super.onFinishInflate();
ButterKnife.inject(this);
final Path[] screens = {
new SubScreen("1"),
new SubScreen("2"),
new SubScreen("3"),
};
CustomPagerAdapter customPagerAdapter = new CustomPagerAdapter(getContext(), screens );
customPagerAdapter .setAdapter(firstRunPagerAdapter);
}
.....
Now, the main part, SubScreen (3 similar screens, that differs only by the parameters we are passing into them => they should adjust views according these parameters)
@Layout(R.layout.screen_subscreen) @WithModule(SubScreen.Module.class)
public class SubScreen extends Path {
private final String title;
public SubScreen(String titleParam) {
title = titleParam;
}
@dagger.Module(injects = SubView.class, addsTo = DaggerConfig.class)
public class Module {
@Provides
SubViewMetadata provideSubViewMetadata() {
return new SubViewMetadata(backgroundColor, title);
}
}
@Singleton
public static class Presenter extends ViewPresenter<SubView> {
private String title;
@Inject
public Presenter(String title) {
this.title= title;
}
@Override
protected void onLoad(Bundle savedInstanceState) {
super.onLoad(savedInstanceState);
if (!hasView()) {
return;
}
getView().setTitle(subViewMetadata.title);
}
}
}
and it's view public class SubView extends FrameLayout {
@InjectView(R.id.subViewTitleTextView)
TextView subViewTitleTextView;
@Inject
SubScreen.Presenter presenter;
public SubView(Context context, AttributeSet attrs) {
super(context, attrs);
ObjectGraphService.inject(context, this);
}
public void setTitle(String title) {
subViewTitleTextView.setText(title);
}
@Override protected void onAttachedToWindow() {....}
@Override protected void onDetachedFromWindow() {....}
......
}
Custom Pager adapter:
public class CustomPagerAdapter extends PagerAdapter {
private final Context context;
private final Path[] screens;
public CustomPagerAdapter(Context context, Path[] screens) {
this.context = context;
this.screens = screens;
}
@Override
public int getCount() {
return (screens == null)? 0 : screens.length;
}
@Override
public boolean isViewFromObject(View view, Object o) {
return view.equals(o);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Path screen = screens[position];
MortarScope originalScope = MortarScope.getScope(context);
MortarScope newChildScope = originalScope.buildChild().build("tutorialpage" + position);
Context childContext = newChildScope.createContext(context);
View newChild = Layouts.createView(childContext, screen);
container.addView(newChild);
return newChild;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
View view = ((View) object);
container.removeView(view);
MortarScope.getScope(view.getContext()).destroy();
}
}
The problem statement: it's crashing, as SubView class hasn't been added into list of Injections at the "Layouts.createView(childContext, screen);" moment in the Adapter, and I can't add it by default, because I want to have a @provider of data from SubScreen to SubScreen.Presenter. (I'm using local variable.
If I add SubView.class into list of injections and convert local Screen's variables into static, then I'll have 3 identical pages inside the ViewPager (which is logical, as every next call of the constructor - overrides old static variables).
Any help/ideas? Thanks for your help, Konstantin
Ok, I figured out.
First of all, adding SubView into list of globally injected classes Then modifying SubScreen class:
@Layout(R.layout.screen_subscreen)
public class SubScreen extends Path {
private static String titleStatic; // Introducing static variable
private final String title;
public SubScreen(String titleParam) {
title = titleParam;
}
public void refreshPresenter() {
titleStatic = title;
}
@Singleton
public static class Presenter extends ViewPresenter<SubView> {
private String title;
@Inject
public Presenter() {
}
@Override
protected void onLoad(Bundle savedInstanceState) {
super.onLoad(savedInstanceState);
if (!hasView()) {
return;
}
getView().setTitle(titleStatic);
}
}
}
and then in Custom adapter do this changes:
public class CustomPagerAdapter extends PagerAdapter {
private final Context context;
private final SubScreen[] screens;
public CustomPagerAdapter(Context context, SubScreen[] screens) {
this.context = context;
this.screens = screens;
}
......
@Override
public Object instantiateItem(ViewGroup container, int position) {
SubScreen screen = screens[position];
MortarScope originalScope = MortarScope.getScope(context);
MortarScope newChildScope = originalScope.buildChild().build("tutorialpage" + position);
Context childContext = newChildScope.createContext(context);
screen.refreshPresenter(); // updating the static var with local one!
View newChild = Layouts.createView(childContext, screen);
container.addView(newChild);
return newChild;
}
....
}
I.e. the solution is to keep the local AND static variables in the Screen, if the same screen is going to be reused. And when we inflate the view it - just setting the right value to the static one (that would be used in the Presenter).
I am not sure, that it is the best possible solution, but it works. It would be nice to hear, if it can be improved.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With