This will be a long post about how to structure MVP project before getting into solving your problem at very last of my answer.
I just report MVP structure here how to structure MVP project from my own answer.
I often put business logic code in Model Layer (don't make confusion with model in database). I often rename as XManager
for avoiding confusion (such as ProductManager
, MediaManager
...) so presenter class just uses for keeping workflow.
The rule of thumb is no or at least limit import android package in presenter class. This best practice supports you easier in testing presenter class because presenter now is just a plain java class, so we don't need android framework for testing those things.
For example here is my mvp workflow.
View class: This is a place you store all your view such as button, textview ... and you set all listeners for those view components on this layer. Also on this View, you define a Listener class for presenter implements later. Your view components will call methods on this listener class.
class ViewImpl implements View {
Button playButton;
ViewListener listener;
public ViewImpl(ViewListener listener) {
// find all view
this.listener = listener;
playButton.setOnClickListener(new View.OnClickListener() {
listener.playSong();
});
}
public interface ViewListener {
playSong();
}
}
Presenter class: This is where you store view and model inside for calling later. Also presenter class will implement ViewListener interface has defined above. Main point of presenter is control logic workflow.
class PresenterImpl extends Presenter implements ViewListener {
private View view;
private MediaManager mediaManager;
public PresenterImpl(View, MediaManager manager) {
this.view = view;
this.manager = manager;
}
@Override
public void playSong() {
mediaManager.playMedia();
}
}
Manager class: Here is the core business logic code. Maybe one presenter will have many managers (depend on how complicate the view is). Often we get Context
class through some injection framework such as Dagger
.
Class MediaManagerImpl extends MediaManager {
// using Dagger for injection context if you want
@Inject
private Context context;
private MediaPlayer mediaPlayer;
// dagger solution
public MediaPlayerManagerImpl() {
this.mediaPlayer = new MediaPlayer(context);
}
// no dagger solution
public MediaPlayerManagerImpl(Context context) {
this.context = context;
this.mediaPlayer = new MediaPlayer(context);
}
public void playMedia() {
mediaPlayer.play();
}
public void stopMedia() {
mediaPlayer.stop();
}
}
Finally: Put those thing together in Activities, Fragments ... Here is the place you initialize view, manager and assign all to presenter.
public class MyActivity extends Activity {
Presenter presenter;
@Override
public void onCreate() {
super.onCreate();
IView view = new ViewImpl();
MediaManager manager = new MediaManagerImpl(this.getApplicationContext());
// or this. if you use Dagger
MediaManager manager = new MediaManagerImpl();
presenter = new PresenterImpl(view, manager);
}
@Override
public void onStop() {
super.onStop();
presenter.onStop();
}
}
You see that each presenter, model, view is wrapped by one interface. Those components will called through interface. This design will make your code more robust and easier for modifying later.
In short, in your situation, I propose this design:
class ViewImpl implements View {
Button button;
TextView textView;
ViewListener listener;
public ViewImpl(ViewListener listener) {
// find all view
this.listener = listener;
button.setOnClickListener(new View.OnClickListener() {
textView.setText(resource_id);
});
}
}
In case the logic view is complicated, for example some conditions for setting value. So I will put logic into DataManager
for getting back text. For example:
class Presenter {
public void setText() {
view.setText(dataManager.getProductName());
}
}
class DataManager {
public String getProductName() {
if (some_internal_state == 1) return getResources().getString(R.string.value1);
if (some_internal_state == 2) return getResources().getString(R.string.value2);
}
}
So you never put android related-thing into presenter class. You should move that to View
class or DataManager
class depend on context.
This is a very long post discuss in detail about MVP and how to solve your concreted problem. Hope this help :)