Reputation: 860
I am creating an android application using the MVP pattern. For dependency injection I use dagger 2. I have an abstract fragment that implements the "view" interface, making it the view in Model-View-Presenter.
public abstract class MediaDetailFragment extends Fragment implements DetailsMvpView {
private static final String RESOURCE = "resource";
private static final String POSTER_SIZE = "w342/";
@Inject DetailPresenter mDetailPresenter;
@Inject CreditPresenter mCreditPresenter;
@BindView(R.id.media_image_flipper) ControllableFlipper mImageFlipper;
@BindView(R.id.keyword_recyclerview) RecyclerView mKeywordRecyclerView;
@BindView(R.id.title_textview) TextView mTitleTextView;
@BindView(R.id.overview_content_textview) TextView mOverviewTextView;
@BindView(R.id.cast_recyclerview) CreditRecyclerView mCastRecyclerView;
@BindView(R.id.crew_recyclerview) CreditRecyclerView mCrewRecyclerView;
@BindView(R.id.empty_view) TextView mRecyclerviewEmpty;
@BindView(R.id.button_share) ImageButton mShare;
@BindView(R.id.button_trailers) ImageButton mTrailers;
@BindView(R.id.button_reviews) ImageButton mReviews;
@BindBool(R.bool.isTablet) boolean mIsTablet;
@OnClick(R.id.button_share) public void shareMedia(View view) {
startActivity(new Intent(Intent.ACTION_SEND)
.putExtra(Intent.EXTRA_TEXT, getActivity().getString(R.string.base_youtube_url)
+ POSTER_SIZE + mMedia.posterPath() + "\n\n"
+ mMedia.title() + "\n\n" + mMedia.overview())
.setType("text/plain"));
}
@OnClick(R.id.button_trailers) public void requestTrailers(View view) {
mDetailPresenter.loadMovies(mMedia.id());
}
@OnClick(R.id.button_reviews) public void requestReviews(View view) {
if (NetworkUtil.isNetworkConnected(getContext())) {
((FragmentHandler) getActivity()).onReviewsRequested(mMedia);
} else {
ViewUtil.displayNoNetworkSnackbar(getActivity());
}
}
private Media mMedia;
private DisplayMetrics mDisplayMetrics = new DisplayMetrics();
private OnGlobalLayoutListener mListener;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMedia = getArguments().getParcelable(RESOURCE);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.media_details_fragment, container, false);
((BaseActivity) getActivity()).activityComponent().inject(this);
ButterKnife.bind(this, rootView);
getActivity().getWindowManager().getDefaultDisplay().getMetrics(mDisplayMetrics);
mTitleTextView.setText(mMedia.title());
mOverviewTextView.setText(mMedia.overview());
mKeywordRecyclerView.setAdapter(new KeywordAdapter(getContext()));
mCastRecyclerView.setAdapter(R.layout.item_credit_normal, mRecyclerviewEmpty);
mCrewRecyclerView.setAdapter(R.layout.item_credit_normal, mRecyclerviewEmpty);
mListener = () -> rootView.post(() -> {
if (mIsTablet) {
mImageFlipper.getLayoutParams().height =
ViewUtil.setHeightForAspectRatio(rootView.getWidth(), ViewUtil.STANDARD);
} else {
mImageFlipper.getLayoutParams().height =
ViewUtil.setHeightForAspectRatio(mDisplayMetrics.widthPixels, ViewUtil.STANDARD);
}
rootView.getViewTreeObserver().removeOnGlobalLayoutListener(mListener);
});
rootView.getViewTreeObserver().addOnGlobalLayoutListener(mListener);
return rootView;
}
@Override
public void onStart() {
super.onStart();
mDetailPresenter.attachView(this);
mDetailPresenter.loadImages(mMedia.id());
mDetailPresenter.loadKeywords(mMedia.id());
mCreditPresenter.attachCastView(mCastRecyclerView);
mCreditPresenter.attachCrewView(mCrewRecyclerView);
mCreditPresenter.loadCredits(mMedia.id());
}
@Override
public void onStop() {
mDetailPresenter.detachView();
mCreditPresenter.detachCastView();
mCreditPresenter.detachCrewView();
super.onStop();
}
@Override
public void showImages(String image) {
mImageFlipper.addImagePath(image);
}
@Override
public void showKeywords(List<String> keywords) {
((KeywordAdapter) mKeywordRecyclerView.getAdapter()).setKeywords(keywords);
}
@Override
public void showVideos(List<Video> videos) {
TrailerDialogFragment.newInstance(videos).show(getFragmentManager(), null);
}
@Override
public void showError() {
if (!NetworkUtil.isNetworkConnected(getContext())) {
ViewUtil.displayNoNetworkSnackbar(getActivity());
}
}
}
Depending on the situation I will use one of two subclasses of this abstract view. As you can see, I inject a "DetailsPresenter" into the view. DetailsPresenter is also an abstract class with two subclasses (one for each subclass of the view).
However, if the view is a MovieDetailFragment, it should have a MovieDetailPresenter, and if it is a ShowDetailFragment, it should have a ShowDetailPresenter.
My question is: where should I implement the logic for checking what kind of view it is and providing the right DetailsPresenter? Should I do it in the Dagger module (maybe in the method that returns the presenter)? Should I do it in the fragment itself?
This is my module:
@Module
public class ConfigPersistentModule {
@Provides
DetailPresenter provideDetailPresenter(DataManager dataManager) {
return new MovieDetailPresenter(dataManager);
}
}
Please help me.
Upvotes: 1
Views: 293
Reputation: 15087
You must inject your presenter in the child classes (MovieDetailFragment & ShowDetailFragment) and in your module you need to have TWO provide module like below :
@Module
public class ConfigPersistentModule {
@Provides
MovieDetailFragment provideDetailPresenter(DataManager dataManager) {
return new MovieDetailPresenter(dataManager);
}
@Provides
ShowDetailFragment provideDetailPresenter(DataManager dataManager) {
return new ShowDetailFragment(dataManager);
}
}
and then in your child classes inject like this :
in ShowDetailFragment:
@Inject ShowDetailFragment mCreditPresenter;
in MovieDetailFragment:
@Inject MovieDetailFragment mCreditPresenter;
now in your father class (MediaDetailFragment) put a abstract function called "getPresenter" that is mandatory for children to override it, like below:
public abstract class MediaDetailFragment extends Fragment implements DetailsMvpView {
private mDetailPresenter;
public abstract DetailPresenter getPresenter();
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
this.mDetailPresenter = getPresenter();
...
...
}
...
...
}
now every class implementing MediaDetailFragment have to tell the father about his presenter and father uses that presenter. so in the children classes (MovieDetailFragment & ShowDetailFragment) write:
@Override
public DetailPresenter getPresenter()
{
return mCreditPresenter;
}
Upvotes: 1