Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it a good practice to access the Actvity's Context in the Presenter class? If no then is there any other better way to do it?

I am new to Android MVP Architecture. As far as I have researched the Presenter should be kept free from any android things like for example: Don't use getActivity or Context in the Presenters. I have written the following code where a BasePresenter is the parent class of all the Presenter classes that I will be using.The BaseView interface is the parent interface of all View classes and BaseActivity class is the parent class of all Activity classes. I have more than one activity and it is required to show Toast messages in all of my activity. So I have written the following code as follows. I am not very sure whether using the getactivity from the presenter class is a good practice or not. If it is not then can anyone suggest any better way to do it?

BasePresenter class

public class BasePresenter<V extends BaseView> {
private V mView;
private Context mContext;

public void attachView(V view) {
    mView = view;
     mContext=mView.getActivity();
}

public void showToast(String msg) {
    Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show();
}

private Context getContext() {
    return mContext;
}

public void detachView() {
    mView = null;
}

} 

BaseView class

 public interface BaseView {
 AppCompatActivity getActivity();
 }

BaseActivity class

public class BaseActivity extends AppCompatActivity {
public AppCompatActivity getActivity() {
    return this;
}

}

MainActivity class

public class MainActivity extends BaseActivity implements MainView {
 MainPresenter basePresenter;
 @Override
protected void onStart() {
    super.onStart();
    basePresenter = new MainPresenter();
    basePresenter.attachView(this);
}

  // some more codes here

        switch (item.getItemId()) {
                case R.id.about:
                    basePresenter.showToast("About is Clicked");

                    break;
                case R.id.cart:
                    basePresenter.showToast("Cart is Clicked");

                    break;
                case R.id.favs:
                    basePresenter.showToast("Favs is Clicked");

                    break;
                case R.id.home:
                    basePresenter.showToast("Home is Clicked");

                    break;
            }
        }
like image 940
anu_r Avatar asked Sep 01 '16 05:09

anu_r


1 Answers

It is not a good idea. You Presenter (base or otherwise) should not know about Context, Activity, Toast or anything else Android based.

View

  1. displays things.
  2. handles user input and passes it to the Presenter.

Presenter

  1. decides what to do with user input.
  2. gathers data from the model.
  3. tells the View what to do.

So for your example of clicking Buttons and showing Toasts you would need a setup something like:

View Interface

This is how your Presenter will talk to your View. It will be implemented by the Activity.

public interface MainView {

    void showToast(String message);
}

Presenter (Base & Main)

BasePresenter has almost no tasks at all. Simply there to bind the View interface. Note the method names in the MainPresenter are ambiguous to things like 'click' to seperate them from the View implementation.

public class BasePresenter<V> {

    protected V view;

    public void attachView(V view) {
        this.view = view;
    }
}

public class MainPresenter extends BasePresenter<MainView> {

    public void about() {
        view.showToast("About was clicked");
    }

    public void cart() {
        view.showToast("Cart was clicked");
    }
}

Activity

The Activity implements the View interface. It's responsible for passing user events to the Presenter and actioning the Presenter commands.

public class MainActivity extends AppCompatActivity implements MainView {

    private MainPresenter presenter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        presenter = new MainPresenter();
        presenter.attachView(this);

        Button about = findViewById(R.id.button_about);
        about.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                presenter.about();
            }
        });

        Button cart = findViewById(R.id.button_cart);
        cart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                presenter.cart();
            }
        });
    }

    @Override
    public void showToast(String message) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
    }
}

In this setup the Presenter no longer knows anything about Android (has no imports from the framework at all) and you are able to write unit tests for it which can run directly on the JVM without Android dependencies.

like image 120
Jahnold Avatar answered Nov 02 '22 03:11

Jahnold