ANDROID MVP FOR BEGINNERS — BEST FOLDER STRUCTURE
MVP is an one architectural pattern for separate presentation logic and business logic. I believe when these layers keeping separately from each others is kind on pain.
But to present these kind of implementation we should provide layers across all the application.
Layers
On android development, we have few more layers. It will help to maintains , writing test cases . Lets see about main layers on android development.
1. Domain layer — This is our business logic in mobile application . Data model for rest.
2. Model Layer — database connection related things
3. Presentation or app layer — android related part (android UI kit related . e.g. : Context)
4. Common Layer — This is for third party library stuff or common things across the application .
Lets see more detail about above business layers.
Domain Layers
Domain layer is fully independent. because this represents business logics for application. According to the naming convention, there are interfaces that represent logic of the application, and controller classes that implement these interfaces and define the way of working for application.
Model Layers
All the REST and database connectivity (insert, delete, update) related works in your project. I think we can keep sub folders
e.g.: rest , database, entity.
One additional thing.
Sometimes you want to create business model classes that differs from data model classes.
e.g.: if you want to show the first name and last with as a full name of employees , you shouldn’t need to get first name and given name of user from data model classes and make string convention in your adapter or view classes. You should define a business model classes (may be inherent from another class) . You many think creating another class is bad. Yes you are correct and its really silly. But it is very counts.
App Layer / Presentation Layer
This is the layer who all known layer among all. this is the layer that android application itself.
View
When it comping to MVP design pattens, it’s ui components.
Lets see the example. We will do a small Add Users application.
Here
1. “Android View” refers to the android.view.View class.
2. Common Android support libraries — Packages in the com.android.support.* namespace provide backwards compatibility and other features.
3. Android Testing Support Library — A framework used to support UI tests, using both Espresso, and AndroidJUnitRunner.
4. Mockito — A mocking framework used to implement unit tests.
5. Guava — A set of core libraries for Java by Google, commonly used in Android apps.
This app consists of three UI Screens:
1. Users
2. UserDetail
3. AddUser
Each screen is implemented using the following classes and interfaces.
1. A contract class that define the connection between the view and the presenter.
2. An Activity that creates fragments and presenters.
3. A Fragment which implements the view interface.
4. A Presenter which implements the presenter interface in corresponding contract.
We better to use fragments because of following reasons:
⦿ The use of both activities and fragments allows for a better separation of concerns which complements this implementation of MVP. the Activity is the overall controller which creates and connects views and presenters.
The use of fragments supports tablet layouts or UI screens with multiple views
⦿ sample ap includes a no of unit tests whine covers presenters, repositories and the data sources. I the next tutorial we can do urtext with fake data facilitated by dragger2 dependency injection.
First of all create a new app on android studio.
When we are doing Better to create few more packages inside your package.
–> data
–>–> rest
–>–> entity
–> domain
–> event
–> presentation
–>–> Your screen1 — eg: users
–>–> Your screen2 — eg: adduser
–> util
* you can add more packages if you want.
As a next step we need to create new base presenter and base view. We will add this to presentation folder since it using all the sub packages.
Select presentation folder and File > new java class > enter name as “BasePresenter” and kind should be interface.
Paste following code on it.
public interface BaseView {
void start();
}
Repeat for create presenter base class
public interface BasePresenter <T extends BasePresenter> {
void setPresenter(T presenter);
}
Since this is base presenter we need to use generic for this interface. Next create anther java model class inside domain folder its call “user.java” . Paste the following code for it.
public final class User {
@Nullable
private final String mName; public User(@Nullable String name) {
mName = name;
}
}
I feel no need to explain about this class . :).
Now we are about to create fragment for show list of users. Lest’s start. First create folder for users on the presentation.
create UsersActivity inside that folder. Code should be as follows
public class UsersActivity extends AppCompatActivity { private UsersPresenter mUsersPresenter; protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
UsersFragment usersFragment =
(UsersFragment) getSupportFragmentManager().findFragmentById(R.id.contentFrame);
if (usersFragment == null) {
// Create the fragment
usersFragment = UsersFragment.newInstance();
ActivityUtils.addFragmentToActivity(
getSupportFragmentManager(), usersFragment, R.id.contentFrame);
} // Create the presenter
mUsersPresenter = new UsersPresenter(
usersFragment
);
}
}
When you see the above code you can see we are adding fragment to the UsersActivity. Let’s create that. It should be same level. (It means same users folder).
Before Go to the fragment code we need to create Contractor interface. Create a new file, name it as ‘UsersContract’. Code is below,
public interface UsersContract { interface View extends BaseView<Presenter> { } interface Presenter extends BasePresenter { }
}
For for the movement we don’t have method for view and presenter. So for now leave it as it is.
Now create Presenter class . Name it as “UsersPresenter”
public class UsersPresenter implements UsersContract.Presenter { private final UsersContract.View mUsersView;
@Override
public void start() {
loadUsers();
} public void loadUsers() {
} public UsersPresenter(@NonNull UsersContract.View usersView) {
mUsersView = checkNotNull(usersView, “usersview cannot be null!”);
mUsersView.setPresenter(this);
}
}
Now For the Fragment code
public class UsersFragment extends Fragment implements UsersContract.View { private UsersContract.Presenter mPresenter;
private UsersAdapter mListAdapter;
@Override
public void setPresenter(UsersContract.Presenter presenter) {
mPresenter = checkNotNull(presenter);
} @Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ArrayList<User> na = new ArrayList<User>();
na.add(new User(“saman”));
na.add(new User(“test name”)); mListAdapter = new UsersAdapter(na, mUserListener);
} @Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.tasks_frag, container, false); ListView listView = (ListView) root.findViewById(R.id.tasks_list);
listView.setAdapter(mListAdapter); return root;
} public static UsersFragment newInstance() {
return new UsersFragment();
} UserItemListener mUserListener = new UserItemListener() {
@Override
public void onUserClick(User clickedUser) { }
};
private static class UsersAdapter extends BaseAdapter { private List<User> mUsers;
private UserItemListener mUserListener; public UsersAdapter(List<User> tasks, UserItemListener userListener) {
setList(tasks);
mUserListener = userListener;
} public void replaceData(List<User> tasks) {
setList(tasks);
notifyDataSetChanged();
} private void setList(List<User> tasks) {
mUsers = checkNotNull(tasks);
} @Override
public int getCount() {
return mUsers.size();
} @Override
public User getItem(int i) {
return mUsers.get(i);
} @Override
public long getItemId(int i) {
return i;
} @Override
public View getView(int i, View view, ViewGroup viewGroup) {
View rowView = view;
if (rowView == null) {
LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
rowView = inflater.inflate(R.layout.user_item, viewGroup, false);
} final User user = getItem(i); TextView titleTV = (TextView) rowView.findViewById(R.id.title);
titleTV.setText(user.getName());
rowView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mUserListener.onUserClick(user);
}
}); return rowView;
}
} public interface UserItemListener { void onUserClick(User clickedUser);
}
}
setPresenter method will call automatically since it is override method and it will set UsersContract.Presenter
So you can presenter for that fragment.
On create for the movement you can initiate adapter . For that you need to create data Adapter. For this example I am using BaseAdapter class type.
onCreateView method body is familiar for all. Because its android related with your previous experience. So won’t tell anything about that.
eg : create list , adapters views and etc
Note : I have created this adapter class as nested class because I am using this adapter, only for this users fragment. If you want to implement it globally better to use different folders or so.
Okay .. Now you have basic idea about best folder structure and begin android development with MVP.In the next tutorial we will check advanced MPV with dragger2 (dependency injection).
Sample code is available on Github