Develop an Android project architectural design pattern.
The reusability of code with a project architectural design pattern for Android Developers.
I have witnessed the ability of a project architectural design pattern when I have implemented one and, I got momentum in my development. It just happens because of a good design pattern I began reusing a lot of code.
I used MVP design and I did not limit myself to implementing my approach inside it.
Before starting any project we should think about maintaining the project’s architectural design pattern.
Many improvements for development are associated with a good project architectural design pattern.
- Good maintenance can be done.
- Reusability of modules.
- Fast CR Implementations.
- Adding a new module is easy.
- Removes redundant code as much as possible.
- The main advantage of the architectural design pattern is the source code will be easy to understand.
- It speeds up and makes development easy for developers.
- Clean source code.
I am going to accord perspectives about a customized architectural design pattern on top of MVP.
It is our view on how we should manage our project design, We don’t have to obey any design practices strictly because if we don’t keep ourselves restricted we can make a unique or better design for our projects.
The Android application developer needs to design many screen layouts. They have to design an Activity or Fragments for around all the screens and from all the screens there will be a network call to the server, This is very common in all Android applications.
I have used the MVP architecture and designed many applications and found good outcomes with that like all the above-listed advantages.
I will explain how it was implemented, It is anyhow like MVP and This design will be very useful for a common network call code for all the screens We are not going to write the network call code for, a second time in the application source code.
If anyone does not know about MVP then please read about MVP Design pattern.
In a usual way, an Android developer who develops an application without any architectural design pattern creates Activity or Fragments and writes all the code in the same activity. There is no rule for writing the number of lines in one file but it is good that it should not exceed 1000 lines.
So let’s design the project and see the difference when we have a good design pattern.
Prerequisite: Android Studio
Step1:
- Create a new Android project with an empty Activity.
Here I have just created an Android project, where one activity is created, without any design pattern we have the freedom to start writing all the code into the same activity now even if it is a network call-related code or view access.
“But we won’t do that now, we are going to create the project architectural design pattern and will reuse the network calling module everywhere in the project”
Step2:
- The current package for me is “com.example.project-design pattern” It’s better to maintain the same for the exercise.
- Suppose we have the Registration module/screen called registration.
- Create the following files into the project and change them as shown in the image below.
- Add a package/folder called “registration”
- RegistrationActivity.java
- IRegisrationPresenter.java
- IRegistrationView.Java
- RegistrationPresenter.java
- XML for registration activity.
Now we have created the structure for one screen/activity, and we can follow it for other activities also, It is just to add a package/folder with the name of the respective module name, and always two interfaces and one presenter java class will be added for each screen.
Setp3:
- Now write the following code as mentioned below in all the files one by one.
RegistrationActivity.java
public class RegistrationActivity extends AppCompatActivity implements IRegistrationView {private IRegistrationPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_registaration);
presenter = new RegistrationPresenter(this);
}public void onRegistration(View view) {
presenter.RegisterUser("Username", "Phone", "Password");
}@Override
public void onSuccessFullRegistration() {}
}
IRegisrationPresenter.java
public interface IRegistrationPresenter {
void RegisterUser(String username, String phone, String password);
}
IRegistrationView.Java
public interface IRegistrationView {
void onSuccessFullRegistration();
}
RegistrationPresenter.java
public class RegistrationPresenter implements IRegistrationPresenter {IRegistrationView view;public RegistrationPresenter(IRegistrationView view) {
this.view = view;
}@Override
public void RegisterUser(String username, String phone, String password) {
view.onSuccessFullRegistration();
}
}
activity_registaration.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".registration.RegistrationActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/registrationButton"
android:text="Register"
android:onClick="onRegistration">
</Button>
</RelativeLayout>
The architectural view of the implementation so far.
As per the architecture so far:
- Activity >> calls Presenter interface and send view data>> Interface will be implemented by the Presenter class.
- The presenter is a java class that will execute all the business logic and network call-related code.
- Activities contain the code of accessing UI elements and passing data to the presented via the presenter interface.
- Methods of the Presenter will be accessed by Activity and Activity data will be passed to the presenter class for processing network calling.
We have implemented half part of the design pattern so far so let’s go further.
Step4:
Add the following structure into the code and the project structure will be like this:
Newly added files into a design pattern.
- package “network call”
- IrequestNetworkCalle.java interface
- IResponseNetworkCaller.java
- NetworkCaller.java
- added some Gradle dependencies for retrofit support.
Note: Gradle dependency is to understand the implementation batter throughout the project and how we can use a common network calling code.
Let’s edit the code one more time.
RegistrationActivity.java
import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.view.View;import com.example.projectdesignpattern.R;public class RegistrationActivity extends AppCompatActivity implements IRegistrationView { private IRegistrationPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_registaration);
presenter = new RegistrationPresenter(this);
} public void onRegistration(View view) {
presenter.RegisterUser("Username", "Phone", "Password");
} @Override
public void onSuccessFullRegistration() {
/**
* This method get called on successful network call
*/
} @Override
public void onFailedRegistration() {
/**
* This method get called on failed network call
*/
}
}
IRegisrationPresenter.java
public interface IRegistrationPresenter {
void RegisterUser(String username, String phone, String password);
}
IRegistrationView.Java
public interface IRegistrationView {
void onSuccessFullRegistration(); void onFailedRegistration();
}
RegistrationPresenter.java
import com.example.projectdesignpattern.networkcall.IRequestNetworkCaller;
import com.example.projectdesignpattern.networkcall.IResponseNetworkCaller;
import com.example.projectdesignpattern.networkcall.NetworkCaller;
import com.google.gson.JsonObject;import retrofit2.Response;public class RegistrationPresenter implements IRegistrationPresenter, IResponseNetworkCaller { IRegistrationView view;
IRequestNetworkCaller caller; public RegistrationPresenter(IRegistrationView view) {
this.view = view;
caller = new NetworkCaller(this);
} @Override
public void RegisterUser(String username,
String phone,
String password) {
/**
* User name
* phone
* password
* ALl will be processed for network call here.
*/ /**
* @POST("employee/device")
* Call<FcmModel> getRegister(@Body JsonObject obj,
* @Header("Authorization") String authenticationKey);
*/
/**
* This method has to be uncommented and resolved.
*/
//caller.callApi("Need to pass call object","Post" ); view.onSuccessFullRegistration();
} @Override
public void onResponseSuccess(retrofit.Response response,
String reqType) {
view.onSuccessFullRegistration();
} @Override
public void onResponseFailure(String responseError) {
view.onFailedRegistration();
}
}
IrequestNetworkCaller.java interface
import retrofit.Call;public interface IRequestNetworkCaller {
void callApi(Call call, final String reqType);
}
IResponseNetworkCaller
import retrofit.Response;public interface IResponseNetworkCaller { void onResponseSuccess(Response response, String reqType); void onResponseFailure(String responseError);
}
NetworkCaller.java
import com.google.gson.JsonObject;import java.net.ConnectException;import retrofit.Call;
import retrofit.Callback;
import retrofit.Response;
import retrofit.Retrofit;public class NetworkCaller implements IRequestNetworkCaller {
IResponseNetworkCaller caller;
public NetworkCaller(IResponseNetworkCaller
iResponseNetworCaller) {
this.caller = iResponseNetworCaller;
} @Override
public void callApi(Call call, final String reqType) {
call.enqueue(new Callback() {
@Override
public void onResponse(Response response,
Retrofit retrofit) {
caller.onResponseSuccess(response, reqType);
} @Override
public void onFailure(Throwable throwable) {
if (throwable instanceof ConnectException) {
caller.onResponseFailure(
"No Internet Connection");
} else {
throwable.printStackTrace();
caller.onResponseFailure(
"Response Failed");
}
}
});
}
}
build.gradle
apply plugin: 'com.android.application'android {
compileSdkVersion 29
buildToolsVersion "29.0.2" defaultConfig {
applicationId "com.example.projectdesignpattern"
minSdkVersion 16
targetSdkVersion 29
versionCode 1
versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}}dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:multidex:1.0.1'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' implementation 'com.squareup.retrofit2:retrofit:2.1.0'
implementation 'com.squareup.retrofit2:converter-gson:2.1.0'
implementation 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta2'}
Above Code is the final project architecture and this can be used.
So now I can explain the full architecture with network calling and how it will be reused always.
Project architecture:
The above pattern is ready for one screen and one can keep on adding screens to it, I am explaining the sequence diagram of all the components so that the responsibility of all the components will be clear and one can map the sequence diagram with the code so it will help to understand it easily.
Thanks for Reading! If this article was helpful. Please hit the clap!
Follow on medium https://medium.com/@narendra147h
Connect on Linked In: linkedin.com/in/narendraharny
Please Follow & subscribe to Make Android Publication by Narendra K H for prompt updates on Android platform-related blogs.
Thank you!