How to make Model View Presenter on Android

We 4 parts in our android app:

– Model
– View
– Presenter
– Activity

More explanation about this design pattern here.

you can see the complete code here.

In model is the same, nothing new:

public class SignInRequest implements Serializable {
private String username,name, lastname,password,email;

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getLastname() {
return lastname;
}

public void setLastname(String lastname) {
this.lastname = lastname;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}
}

Our view is a interface, and it connects presenter with activity:

public interface LoginView {
void showLoading(boolean state);
void onRequestSuccess(Object object);
void onRequestError(Object object);

Context getContext();

}

In presenter We make call, you can use retrofit or any other way, in this case We choose volley:

public class LoginPresenter {
private static final String TAG ="LoginPresenter" ;
private LoginView loginView;
private RequestQueue queue;
private LoginResponse loginResponse;

public LoginPresenter(LoginView loginView) {
this.loginView = loginView;
}

public void login(String username, String password)
{
queue = Volley.newRequestQueue(loginView.getContext());

final String url = loginView.getContext().getString(R.string.url_login)+"?username="+username+"&password="+password;
final String appID= loginView.getContext().getString(R.string.app_id);
final String key= loginView.getContext().getString(R.string.rest_key);

Log.i(TAG, "url " + url);

JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET,
url, null,
new Response.Listener()
{

@Override
public void onResponse(JSONObject response)
{
Log.i(TAG, "response "+response.toString());
GsonBuilder gsonb = new GsonBuilder();
Gson gson = gsonb.create();

loginResponse=null;
try
{
loginResponse= gson.fromJson(response.toString(),LoginResponse.class);
if(loginResponse!=null)
{
Log.i(TAG, "loginResponse "+loginResponse.toString());
loginView.onRequestSuccess(response);
}

}catch (Exception e)
{
loginView.onRequestError(e);
}

}
}, new Response.ErrorListener() {

@Override
public void onErrorResponse(VolleyError error)
{
Log.i(TAG, "Error: " + error);
loginView.onRequestError(error);
}
})
{
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("X-Parse-Application-Id", appID);
params.put("X-Parse-REST-API-Key", key);

return params;
}
};
queue.add(jsonObjReq);
}

public void login(Object object)
{

}
}

Finally our activity is few lineas and clear code:

public class LoginActivity extends AppCompatActivity implements LoginView {

private static final String TAG = "HomeActivity";
private EditText eteUsername,etePassword;
private View btnLogin,vLoading,tviSignIn;

private String username, password;
private LoginPresenter loginPresenter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
loginPresenter= new LoginPresenter(this);
initiateUI();
}

private void initiateUI() {
eteUsername = (EditText)findViewById(R.id.eteUsername);
etePassword = (EditText)findViewById(R.id.etePassword);
btnLogin = findViewById(R.id.btnLogin);
vLoading = findViewById(R.id.vLoading);
tviSignIn = findViewById(R.id.tviSignIn);
vLoading.setVisibility(View.GONE);
events();
}

private void events() {
btnLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

if (validate()) {
login();
}
}
});
tviSignIn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
gotoSignIn();
}
});
}

private boolean validate() {

username = eteUsername.getText().toString().trim();
password = etePassword.getText().toString().trim();

eteUsername.setError(null);
etePassword.setError(null);
if(username.isEmpty())
{
eteUsername.setError(getString(R.string.msg_ingresar));
return false;
}
if(password.isEmpty())
{
etePassword.setError(getString(R.string.msg_ingresar));
return false;
}
return true;
}

private void gotoSignIn() {

}

private void login()
{
showLoading(true);
loginPresenter.login(username,password);
}

@Override
public void showLoading(boolean state) {
int visibility= (state)?(View.VISIBLE):(View.GONE);
vLoading.setVisibility(visibility);
}

@Override
public void onRequestSuccess(Object object) {
showLoading(false);
gotoHome();
}

@Override
public void onRequestError(Object object) {
showLoading(false);
}

private void gotoHome() {
startActivity(new Intent(this,MainActivity.class));
finish();
}

@Override
public Context getContext() {
return this;
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
return false;
}

@Override
public boolean onOptionsItemSelected(MenuItem item)
{
return false;
}

}

You can see the complete code here.

Also more explanation about this design pattern here.