Creating Interactions with Presenters & Listeners

Stephen Jaya
MeetU Engineering
Published in
4 min readApr 17, 2018

When developing an Android application, we often need something or do something to our other activity or databases. While there are various ways to do this, the Model-View-Presenter (MVP) pattern is the most common way to creating a solid interactions with another android Activities or Fragments and your Backend models and services.

For example, let’s have an activity where we need to fetch a list of time given a date interval :

After fetching the data from the backend

Creating the Listeners

Listeners are just an interface which the presenter use to interact with the activity/fragments. The activity/fragments will be implementing the listener, and presenters will be able to call it.

Lets make a listener for a callback/reaction for a successful post :

public interface TimeRecommendationPresenterListener {
void onPostSuccess(List<List<TimeRecommendationDetail>> listTimeRecommendation);
void onError(String message);
}

Creating the Presenters

Presenter feels like the connecting bridge between the activity using the listeners, and the backend data service using the services. Imagine we have a Backend service capable of doing a post request :

Time Recommendation Services

Where we need to do an API Calls to api/recommendation/ with a corresponding request. Then what we have to do in the presenter is :

TimeRecommendationPresenter, lovely.

Notice what the presenter does, it creates a Request Object, consisting the requests of the API. Using the API call service, we’ll now create a Callback object, consisting of an onResponse and onFailure methods, and implement them. When finished, we can just notify the listeners.

Notifying the listeners

When we are done with fetching the data, we are able to notify the corresponding activity/fragments by implementing the listeners that have been made. For example, let’s have a TimeRecommendationFragment extends Fragment implements TimeRecommendationPresenterListener which will need to implements our listeners and uses the presenter for API calls :

TimeRecommendationPresenter presenter = new TimeRecommendationPresenter(this);@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

recommendedDate = new ArrayList<>();
recommendationMap = new TreeMap<>();

DateTime timeZone = new DateTime(1900, 1, 1, 0, 0);
DateTime startDate = new DateTime(2018, 4, 16, 12, 0);
DateTime endDate = new DateTime(2018, 4, 20, 14, 0);
String repeatType = "ONCE";
int repeatCount = 1;
presenter.postRecommendation(timeZone, startDate, endDate, repeatType, repeatCount);
}
@Override
public void onPostSuccess(List<List<TimeRecommendationDetail>> listTimeRecommendation) {
for (List<TimeRecommendationDetail> date : listTimeRecommendation) {
DateTime dateTime = date.get(0).getDate();
this.recommendedDate.add(dateTime);

String textDate = DateTimeFormat.forPattern("dd MMMM")
.print(dateTime);
this.recommendationMap.put(textDate, date);
}

updatePosition();
}

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

And finally, our activity/fragments are able to interact with the backend services, Cheers :)

Testing the Presenters

In this section, I will cover up the basic purposes of testing and various ways for testing, as well as testing our presenters. Testing is a convenient ways to ensure our code is well-written, that is being able to deliver a good and working product.

In general, there are 2 types of testing, Functional Tests, and Non-functional Tests. Functional Tests are a test to see how our software works as expected, these type of tests includes Unit tests, Usability Testing, etc. Non-functional tests includes the architecture test rather than the software, example of this would be how many users can access the page at the same time.

Let’s see some of the purposes of Testing in different point of view, Developer, Product Owner, and the Users.

  • Developers
We don’t even remember our code

After writing code, we need to check if our code works as expected, and another fellow developers who need to uses our code need not to recheck and understand the code again. Why ? because it’s already being tested ! We even sometimes don’t remember our own code and how it works. This is easily solved if we test our code before releasing it to production.

  • Product Owner

Another important aspect of testing is, We can show to the product owner that the product works as expected, without explaining the technical stuffs ! Remember that product owner isn’t involved much in the development and even the code itself. So it’s a good way to show and assure our product works.

  • Users

When we have tested our code, we are making sure that the users that use our product won’t have any technical problems, hence not creating tests produces a bad experience to the users.

This may even leads to a security thread, where some users (a.k.a. hackers) can done some nasty stuffs to our product like dropping database tables or steal some data if our product is not secure. How to avoid these things ? Test it !

Therefore, let’s test our Presenter :) Using PowerMock and JUnitTest, lets create a test for post a time recommendation :

@Test
public void testPostTimeRecommendationSuccess() {

final Call<List<List<TimeRecommendationResponse>>> callBaseMock = (Call<List<List<TimeRecommendationResponse>>>) mock(
Call.class);
final Response<List<List<TimeRecommendationResponse>>> responseMock = (Response<List<List<TimeRecommendationResponse>>>) (mock(
Response.class));

final List<List<TimeRecommendationResponse>> response = new ArrayList<>();
response.add(new ArrayList<TimeRecommendationResponse>());
when(responseMock.isSuccessful()).thenReturn(true);
when(responseMock.body()).thenReturn(response);

doAnswer(new Answer() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
Callback<List<List<TimeRecommendationResponse>>> callback = invocation
.getArgumentAt(1, Callback.class);
callback.onResponse(callBaseMock, responseMock);

return null;
}
}).when(meetUpServiceMock)
.postTimeRecommendations(any(TimeRecommendationRequest.class), any(Callback.class));

timeRecommendationPresenter
.postRecommendation(new DateTime(), new DateTime(), new DateTime(), "ONCE", 1);

verify(listenerMock, times(1)).onPostSuccess(any(List.class));
}

What this test does, is ensuring that we send a empty interval date, we should expect an empty time recommendation as well. Using power mock, we can mock a response and request objects and a function behaviour so it can be tested without worrying about its dependencies.

Conclusion

Presenters and Listeners are used to define a interactions between activity/fragments (Frontend) and Backend. Using MVP pattern, it provides way to seperate the UI elements and the data elements. Lastly to test the presenters and any code that we made, we should create a unit tests for it.

--

--