10

I am following MVP architecture in my application. My HomeActivity contains a Sliding Panel with list icon having selector that is upon selecting the Sliding Panel item the icon state is changed and i am not using any list selector.

I am keeping a model class NavItemData for populating the navigation drawer and using a class SlidingPanelItemSelector that extends StateListDrawable generates the appropriate selector for the sliding panel icon.

In MVP architecture we have a presenter class that communicates with the model and generates the input for views. In my case if am using the presenter for getting the data for Sliding Panel i am calling a class from presenter that using android context is that's a good approach, or we are having any alternative solution that strictly following MVP architecture?

Currently i am using a ViewBinderUtils class and injected it directly to the activity class and gets the list of data for Sliding Panel. Is it following Mvp Architcture?

SlidingPanelItemSelector.class

public class SlidingPanelItemSelector extends StateListDrawable {
    private Context mContext;

    public SlidingPanelItemSelector(Context mContext){
        this.mContext = mContext;
    }

    public StateListDrawable getHomeSelector(){
    StateListDrawable stateListDrawable = new StateListDrawable();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            stateListDrawable.addState(new int[]{android.R.attr.state_pressed},
                mContext.getDrawable(R.drawable.ic_nav_home_active));
            stateListDrawable.addState(new int[]{},mContext.getDrawable(R.drawable.ic_nav_home));
        }else{
            stateListDrawable.addState(new int[]{android.R.attr.state_pressed},
                mContext.getResources().getDrawable(R.drawable.ic_nav_home_active));
            stateListDrawable.addState(new int[]{},mContext.getResources().getDrawable(R.drawable.ic_nav_home));
        }

        return stateListDrawable;
    }
}

ViewBinderUtils.class

public class ViewDataBinderUtils {
    Context mContext;
    @Inject
    public ViewDataBinderUtils(@ActivityContext Context mContext) {
        this.mContext = mContext;
    }
    public List<SlidingPanelData> getListData(String [] titles){
        List<SlidingPanelData> items = new ArrayList<>();
        items.add(new SlidingPanelData(new SlidingPanelItemSelector(mContext).getHomeSelector(),titles[0],true));
        items.add(new SlidingPanelData(new SlidingPanelItemSelector(mContext).getConfigurationSelector(),titles[1],false    ));
    items.add(new SlidingPanelData(new SlidingPanelItemSelector(mContext).getConfigurationSelector(),titles[2],false));
        items.add(new SlidingPanelData(true));
        items.add(new SlidingPanelData(new SlidingPanelItemSelector(mContext).getQuoteSelector(),titles[3],false));
        items.add(new SlidingPanelData(new SlidingPanelItemSelector(mContext).getEquipmentInventorySelector(),titles[4],false));
        items.add(new SlidingPanelData(new SlidingPanelItemSelector(mContext).getCustomerSelector(),titles[5],false));
        items.add(new SlidingPanelData(new SlidingPanelItemSelector(mContext).getQuoterSelector(),titles[6],false));
        items.add(new SlidingPanelData(new SlidingPanelItemSelector(mContext).getSalesProgramsSelector(),titles[7],false));
        items.add(new SlidingPanelData( new SlidingPanelItemSelector(mContext).getCreditAppsSelector(),titles[8],false));
        items.add(new SlidingPanelData(new SlidingPanelItemSelector(mContext).getRetailOffersSelector(),titles[9],false));
        items.add(new SlidingPanelData(true));
        items.add(new SlidingPanelData(new SlidingPanelItemSelector(mContext).getPayOffersSelector(),titles[10],true));
        items.add(new SlidingPanelData(new SlidingPanelItemSelector(mContext).getAlertsSelector(),titles[11],true));
        items.add(new SlidingPanelData(true));
        items.add(new SlidingPanelData(new SlidingPanelItemSelector(mContext).getTermofUseSelector(),titles[12],false));
        items.add(new SlidingPanelData(new SlidingPanelItemSelector(mContext).getLegalInfoSelector(),titles[11],false));
        return items;
    }
}
DGKarlsson
  • 1,091
  • 12
  • 18
Sunny
  • 1,066
  • 1
  • 13
  • 32

1 Answers1

3

The presenter should be isolated from context stuff, because the only part that should know about the context is the View(V) part. I didn't understand well your goal with this classes, but in generic way you should follow this logic

if am using the presenter for getting the data for Sliding Panel i am calling a class from presenter that using android context

Create a interface that is responsible to manage the communication between the View (V) with Presenter (P).

Communication.java

public interface Communication {
    void showLoading();
    void hideLoading();
    void setSlidingData(String [] titles);
}

Your View should implement this interface Comunication, and has a reference for the Presenter. And if you need to use the context for an Interactor (I), you should have a class that manages this (in my case RequestHolder).

View.java

public View implements Communication{
    private Presenter mPresenter;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
           // your view already implements the Comunication interface
           mPresenter = new Presenter(this);
        }
        (...)
       private void getData(){
         mPresenter.getData(new RequestHolder(getApplicationContext()));
       }

       @Override
       public void setSlidingData(String [] titles){
          List<SlidingPanelData> items = new ArrayList<>();
          items.add(new SlidingPanelData(new SlidingPanelItemSelector(getApplicationContext()).getHomeSelector(),titles[0],true));
       }
    }

in presenter has a reference for your interface

Presenter.java

private Communication mView;

public Presenter(Communication view) {
    mView = view;
}

/** event to receive data from the model **/
public void onEvent(GetDataMessage event){
   mView.setSlidingData(event.getData());
} 

public void getData(final RequestHolder holder){
   new GetDataInteractor(holder);
}

RequestHolder.java

// you can put the data important to the interactor
public RequestHolder(final Context context, int accountId) {
    super(context); 
}
//getters and setters

With this you can access to the context inside your interactor, without mix concepts


In sum,

  • View is the only one that provides context
  • View has a reference to the Presenter
  • Presenter "talks" with View between a Interface

In your specific case, why you don't create the List that needs the context in your View part and fills List items = new ArrayList<>(); in your presenter part? with this you keep everything isolated

rafaelasguerra
  • 2,685
  • 5
  • 24
  • 56
  • Thank you for your response.So that i have to call the view related stuff (Communication View) from the presenter class right? – Sunny Apr 28 '16 at 04:39
  • My model class has another object which requires context on its instantiation, so if i write the interactor implementation from presenter that uses context is not a good approach right? – Sunny Apr 28 '16 at 04:47
  • In your case you used an instance of RequestHolder which is instantiated from the view and passed it to presenter. In my case the same approach but used in little different way. I created a ViewBinderUtil class that returns the list of items for SlidingPanel and the instance of ViewBinderUtil is created in the view itself. So you are saying the creation of ViewBinderUtils class in the presenter and returns the list of data back to view? Please correct me if am stated anything wrong. – Sunny Apr 28 '16 at 08:10
  • Do you need the context again inside the interactor? Or it's just to create the List? This getListData is startic information, or do you need to request some information? – rafaelasguerra Apr 28 '16 at 08:22
  • 1
    Model class for my view is SlidingPanelData. The model class contains an instance of SlidingPanelItemSelector class which needs the context for getting the drawable (You can see in code given in the question). So my concern is where I need to call the method for constructing the List. In normal scenario(i mean there is no context required) i know we can create from another helper class and get the result back to presenter and then to view, but in cases where the List needs context, where should i place the code. Please let me know my concern is clear or not. – Sunny Apr 28 '16 at 08:38
  • If I understood, you should fill the list in the view part because you need the context, and in my point of view the SlidingPanelSelector belongs to the view part as well. If you fill these objects that needs context from the View and send the presenter the list of objects it still the logic isolated – rafaelasguerra Apr 28 '16 at 08:48
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/110483/discussion-between-sunny-and-rguerra). – Sunny Apr 28 '16 at 08:55