Implementing generic type interface - java

Let's say I have the following interfaces:
public interface MvpView { }
public interface MvpPresenter<V extends MvpView> {
void attach(V view);
}
Then a base class that implements MvpPresenter
public class BasePresenter<V extends MvpView> implements MvpPresenter<V> {
private V view;
#Override
public void attach(V view) {
this.view = view;
}
}
And finally the following class that extends BasePresenter
public abstract class BaseFragment<P extends MvpPresenter> implements MvpView {
P presenter;
public void someMethod() {
presenter.attach(this);
}
}
While this compiles it's not safe because there is no guarantee that implementations of the class will implement the correct MvpView (the one that P presenter uses). In order to be safe I've left out the code of someMethod and every implementation must fill it with the exact same code presenter.attach(this)
What I'd like to do but I don't know how is something like the following:
public abstract class BaseFragment<V extends MvpView, P extends MvpPresenter<V>> implements V {
P presenter;
public void someMethod() {
presenter.attach(this);
}
}
Is there any way to achieve this?

Declare BaseFragment like this.
abstract class BaseFragment<P extends MvpPresenter<R>, R extends BaseFragment<P,R>> implements MvpView {
P presenter;
public void someMethod() {
presenter.attach(getThis());
}
abstract R getThis();
}
}
and use the extensions like this,
class MyFragment extends BaseFragment<MvpPresenter<MyFragment>, MyFragment> {
#Override
MyFragment getThis() {
return this;
}
}

This compiles:
public abstract class BaseFragment<P extends MvpPresenter<BaseFragment>> implements MvpView {
P presenter;
public void someMethod() {
presenter.attach(this);
}
}
But I haven't found a way to actually subclass it. I am not sure if MvpView is actually required for anything. Maybe something like this will be useful:
public interface MvpPresenter<V> {
void attach(V view);
}
public class BasePresenter<V> implements MvpPresenter<V> {
private V view;
#Override
public void attach(V view) {
this.view = view;
}
}
public abstract class BaseFragment<R extends BaseFragment> {
MvpPresenter<R> presenter;
public void someMethod() {
presenter.attach(getThis());
}
abstract R getThis();
}
public class MyBaseFragment extends BaseFragment<MyBaseFragment> {
#Override
MyBaseFragment getThis() {
return this;
}
}

Based on boobalan gnanasekaran and user158037 answers, I did it like this:
public interface MvpView { }
public interface MvpPresenter<V extends MvpView> {
void attach(V view);
}
public class BasePresenter<V extends MvpView> implements MvpPresenter<V> {
private V view;
#Override
public void attach(V view) {
this.view = view;
}
public V getView() {
return view;
}
}
public abstract class BaseFragment<V extends MvpView, P extends MvpPresenter<V>> {
P presenter;
protected abstract V getThis();
public void someMethod() {
presenter.attach(getThis());
}
public P getPresenter() { return presenter; }
}
And an example implementation
public interface MoviesContract {
interface Presenter extends MvpPresenter<MoviesContract.View> {
void loadMovies();
}
interface View extends MvpView {
void onMoviesLoaded();
}
}
public class MoviesPresenter extends BasePresenter<MoviesContract.View>
implements MoviesContract.Presenter {
#Override
public void loadMovies() {
getView.onMoviesLoaded();
}
}
public class MoviesFragment extends BaseFragment<MoviesContract.View, MoviesContract.Presenter>
implements MoviesContract.View {
#Override
public MoviesContract.View getThis() {
return this;
}
public loadMovies() {
getPresenter().loadMovies();
}
#Override
public void onMoviesLoaded() {
//
}
}

Related

How to communicate with fragments inside FragmentStatePagerAdapter?

I'm trying to update the content of all the fragments inside TabAdapter class based on the data input in the GradeFragment. In the GradeFragment I'm updating Grupe object but I'm unable to notify other fragments when it happens. I've tried to use an interface but I can't attach it to the GradeFragment. How can I achieve this?
Here's my TabAdapter class:
public class TabAdapter extends FragmentStatePagerAdapter {
private int totalTabs;
private Grupe grupe;
private GradeFragment gradeFragment;
public TabAdapter(FragmentManager fm, int totalTabs, Grupe grupe) {
super(fm);
this.totalTabs = totalTabs;
this.grupe = grupe;
}
// this is for fragment tabs
#Override
public Fragment getItem(int position) {
Bundle bundle = new Bundle();
bundle.putSerializable("gr", grupe);
switch (position) {
case 0:
gradeFragment = new GradeFragment();
gradeFragment.setArguments(bundle);
return gradeFragment;
case 1:
GradeAverageFragment gradeAverageFragment = new GradeAverageFragment();
gradeAverageFragment.setArguments(bundle);
return gradeAverageFragment;
case 2:
GroupAverageFragment groupAverageFragment = new GroupAverageFragment();
groupAverageFragment.setArguments(bundle);
return groupAverageFragment;
case 3:
TopGradesFragment topGradesFragment = new TopGradesFragment();
topGradesFragment.setArguments(bundle);
return topGradesFragment;
default:
return null;
}
}
// this counts total number of tabs
#Override
public int getCount() {
return totalTabs;
}
}
Set GradeFragment as target fragment for each other Fragment (GradeAverageFragment, GroupAverageFragment, TopGradesFragment ...) like this:
GradeAverageFragment gradeAverageFragment = new GradeAverageFragment();
gradeAverageFragment.setArguments(bundle);
gradeAverageFragment.setTargetFragment(gradeFragment, 0);
return gradeAverageFragment;
Simple prototype:
interface OnUpdateGrupeListener {
void onGrupeUpdated(Grupe newGrupe);
}
interface UpdateGrupeHost {
void onAttachUpdateGrupeListener(OnUpdateGrupeListener listener);
void onDetachUpdateGrupeListener(OnUpdateGrupeListener listener);
}
public static class GradeFragment extends Fragment implements UpdateGrupeHost {
private final ArrayList<OnUpdateGrupeListener> listeners = new ArrayList<>();
#Override
public void onAttachUpdateGrupeListener(OnUpdateGrupeListener listener) {
listeners.add(listener);
}
#Override
public void onDetachUpdateGrupeListener(OnUpdateGrupeListener listener) {
listeners.remove(listener);
}
private void notifyOthers(Grupe newGrupe) {
for (OnUpdateGrupeListener l : listeners) {
l.onGrupeUpdated(newGrupe);
}
}
}
/*
GradeAverageFragment,
GroupAverageFragment,
TopGradesFragment
*/
public static class GradeAverageFragment extends Fragment implements OnUpdateGrupeListener {
#Nullable
private UpdateGrupeHost callback;
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (getTargetFragment() instanceof UpdateGrupeHost) {
callback = (UpdateGrupeHost) getTargetFragment();
callback.onAttachUpdateGrupeListener(this);
}
}
#Override
public void onDetach() {
super.onDetach();
if (callback != null) {
callback.onDetachUpdateGrupeListener(this);
}
callback = null;
}
#Override
public void onGrupeUpdated(Grupe newGrupe) {
// updated grupe received
}
}

Native Android BottomSheet is not appearing in React Native

I am building a custom component in Java and trying to display that in React Native but the component is not appearing. I've been looking through forums and documentation for solutions but can't find a solution. I am not sure if it's an issue on the native side or the React Native side. Any help or advice on improvement is highly appreciated.
Bottom Sheet View
public class BottomSheetView extends NestedScrollView {
private BottomSheetBehavior bSheetBehavior;
public BottomSheetView(Context context) {
super(context);
init();
}
private void init() {
inflate(getContext(), R.layout.bottom_sheet, this);
CoordinatorLayout coordinaterLayout = findViewById(R.id.coordinate_layout);
View bottomSheet = coordinaterLayout.findViewById(R.id.bottom_sheet_component);
bSheetBehavior = BottomSheetBehavior.from(bottomSheet);
bSheetBehavior.setHideable(false);
bSheetBehavior.setPeekHeight((int) PixelUtil.toPixelFromDIP(200));
}
#Override
protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
}
}
Bottom Sheet Manager
public class BottomSheetManager extends ViewGroupManager<BottomSheetView> {
public static final String REACT_CLASS = "BottomSheet";
private BottomSheetView bottomSheet;
#Override
public String getName() {
return REACT_CLASS;
}
#Override
protected BottomSheetView createViewInstance(ThemedReactContext reactContext) {
return new BottomSheetView(reactContext);
}
}
Bottom Sheet Package
public class BottomSheetPackage implements ReactPackage {
private Activity mActivity = null;
BottomSheetPackage(Activity activity) {
mActivity = activity;
}
public BottomSheetPackage() {
}
#Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = Collections.emptyList();
return modules;
}
#Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Arrays.<ViewManager>asList(new BottomSheetManager());
}
}
React Native
class BottomSheet extends Component {
render() {
return (<BottomSheet style={{height: 200}}/>);
}
}

MVP Structure in Vaadin Spring

I'm setting up my first Vaadin application with Vaadin 7.5.6 and the official Vaadin Spring 1.0.0. I want to use the MVP pattern but I'm asking myself how the components work together. Because I'm new to MVP i don't want to use any Addons, so i tried to set it up by myself.
So if I'm right, the LoginViewPresenter will give me the view over presenterInstance.getView(). This is already working fine, but how should i access to the presenter over the view? When i want to do a logic operation for my view i should do it in the presenter class. But how to call a presenter method from a view Buttonclicklistener?
My second question is if I have the UIScope annotation over my presenter class, when does Spring instantiate a new object from this class? I thougt as long as the UI exists. But after generating a random string in the constructor I'm printing out the content of the randomString variable (in the UI.class init() method) but there is always a new value.
Regards
LoginViewPresenter.java
#SpringComponent
#UIScope
public class LoginViewPresenter implements Serializable
{
private static final long serialVersionUID = 6286518141570430211L;
#Autowired
private LoginView view;
public final String randomString;
public LoginViewPresenter()
{
randomString = Utils.generateRandomString(8);
}
#PostConstruct
public void init()
{
}
public LoginView getView()
{
return view;
}
public void setView(LoginView view)
{
this.view = view;
}
}
LoginView.java
#SuppressWarnings("serial")
#UIScope
#SpringView(name = LoginView.NAME)
public class LoginView extends VerticalLayout implements View
{
public static final String NAME = "LoginView";
#PostConstruct
private void init()
{
}
#Override
public void enter(ViewChangeEvent event)
{
}
}
Your view should'nt be aware of the presenter. It should fire events, and your presenter can listen to them.
Here is how I do it:
LoginView.java
#SuppressWarnings("serial")
#UIScope
#SpringView(name = LoginView.NAME)
public class LoginView extends VerticalLayout implements View {
public static final String NAME = "LoginView";
#Autowired
private transient Collection<LoginViewListener> loginViewListeners;
#PostConstruct
private void init() {
...
Button b = new Button("click me");
b.addClickListener(e -> loginViewListeners.forEach(l -> l.eventFired()));
addComponent(b);
...
loginViewListeners.forEach(listener -> listener.viewInitialized(this));
}
#Override
public void enter(ViewChangeEvent event)
{
}
public interface LoginViewListener {
void viewInitialized(LoginView view);
void eventFired();
}
}
LoginViewPresenter.java
#SpringComponent
#UIScope
public class LoginViewPresenter implements LoginViewListener, Serializable {
private static final long serialVersionUID = 6286518141570430211L;
private LoginView view;
public final String randomString;
public LoginViewPresenter() {
randomString = Utils.generateRandomString(8);
}
#PostConstruct
public void init() {
}
public LoginView getView() {
return view;
}
public void setView(LoginView view) {
this.view = view;
}
#Override
public void viewInitialized(LoginView v) {
setView(v);
}
#Override
void eventFired() {
...
}
}
Does your randomString still have always a new value with this design?

Java inheritance and generic issue

I'm having the following classes/interfaces:
public class GenericViewModel<T extends AbstractDatabaseObject> {
private Class<?> type;
#SuppressWarnings("unchecked")
public GenericViewModel(Class<?> cl) {
type = cl;
}
}
and a specialization:
public class PersonViewModel extends GenericViewModel<Person> implements IPersonViewModel{
public PersonViewModel() {
super(Person.class);
}
}
Now, my problem is in the presenter:
public class GenericPresenter implements IGenericView.IGenericViewListener {
private GenericViewModel<AbstractDatabaseObject> model;
private IGenericView view;
public GenericPresenter(GenericViewModel<AbstractDatabaseObject> model, IGenericView view) {
this.model = model;
this.view = view;
view.addListener(this);
}
}
To be more precise, I cannot call the constructor of the super class with the given arguments:
public class PersonPresenter extends GenericPresenter {
PersonViewModel model;
IPersonView view;
public PersonPresenter(PersonViewModel model, IPersonView view) {
super(model, view); // Here is the problem. No such constructor in superclass found
// IGenericView i = (IGenericView) view; <-- this seems to work
// GenericViewModel<AbstractDatabaseObject> m = model; <-- this doesn't
}
}
What do I have to change?
Try to change the GenericPresenter class in this way:
private GenericViewModel<? extends AbstractDatabaseObject> model;
private IGenericView view;
public GenericPresenter(GenericViewModel<? extends AbstractDatabaseObject> model,
IGenericView view) {
this.model = model;
this.view = view;
view.addListener(this);
}

Android: Fragments using a method from MainActivity not defined in the interface?

So I'm having some design pattern confusion/issues. I have a Fragment that needs to call methods from the MainActivity that's not defined in the Fragment's interface. An obvious solution would be just to cast the attached Activity as a MainActivity, but doesn't that defeat the purpose of the interface?
This is my MainActivity has methods a(), b(), and c():
public class MainActivity extends Activity implements AInterface, CInterface {
#Override
public void a(){//method A body}
public void b(){//method b body} //no Override
#Override
public void c(){//method C body}
}
This is my Fragment Class and NEEDS a(), b() and c().
Method c() is from another Fragment's interface:
public class SomeFragment extends Fragment{
private AInterface mActivity;
#Override
public void onAttach(Activity activity) {
mActivity = (AInterface)activity;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.my_layout, container, false);
mActivity.a();
(MainActivity) mActivity.b(); //is it ok to just call it like this?
(MainActivity) mActivity.c(); //is it ok to just call it like this?
return v;
}
public interface AInterface{
public void a();
}
}
Is this the correct way of calling those methods? Thanks.
I would not do it like this, since your are creating a tight coupling between your Activity and your fragment.
A better approach would be to use a callback.
public class MenuFragment extends Fragment {
public interface Interface1{
public void b();
}
public interface Interface2 extends Interface1{
public void a();
}
public interface Interface3 extends Interface1{
public void c();
}
Interface2 mCallback;
#Override
public void onAttach(Activity activity){
super.onAttach(activity);
try {
mCallback = (Interface2 ) activity;
}
catch (ClassCastException e) {
throw new ClassCastException(activity.toString()+ " must implement ItemselectedCallback");
}
}
#Override
public void onDetach(){
mCallback = null;
super.onDetach();
}
//somewhere
mCallback.a();
}
Your activity would then implement the callback interface and handle the callbacks.
public class TaskActivity extends Activity implements MenuFragment.Inferface2, MenuFragment.Interface3{
public void a() {
//do something
}
public void b() {
//do something
}
public void c() {
//do something
}
}
Yes you can do that and it will work, BUT you will also need to be careful when the casting failed (solveable with instanceof)
It will also make your SomeFragment class coupled to your MainActivity class which is not a best practice.
I think the better and safer approach is to use interface.

Categories