Vinod k Morya http://www.vinodmorya.com Android Developer | Mobile Architect Sat, 21 Jul 2018 09:53:22 +0000 en hourly 1 https://wordpress.org/?v=5.4.1 http://www.vinodmorya.com/wp-content/uploads/2019/11/cropped-vinodmorya_favicon-32x32.png Vinod k Morya http://www.vinodmorya.com 32 32 A perfect Android Base app. http://www.vinodmorya.com/blogs/perfect-android-base/ http://www.vinodmorya.com/blogs/perfect-android-base/#respond Sat, 21 Jul 2018 09:38:47 +0000 http://www.vinodmorya.com/?p=363 I am sharing a Android base project(Download Link) build on Kotlin which is empowered with a lot of boiler plate code, libraries and with the easy to use MVP-i architecture. Following are the enlisted features in the project.

1. Kotlin language is used with kotlin extensions
2. MVP-i architecture. To know know more about MVP-i architecture follow link.
3. Room framework with all CRUD operations and queries to work with sqlite database.
4. LiveData with data binding with room for persistence.
5. Retrofit 2 with Rx2 library with caching support, will provide the previous cached response in case of no network. It will be beneficial if you want to provide an offline support to the app without using the database.
6. Lottie loader with lots of sample animations.
7. Advanced logger(link).
8. A fully customisable No internet dialog.

 

clone the project from https://github.com/vinod-morya/AndroidBase

]]>
http://www.vinodmorya.com/blogs/perfect-android-base/feed/ 0
Android – MVP with Interactor | VIPER architecture http://www.vinodmorya.com/blogs/android-architecture-mvp/ http://www.vinodmorya.com/blogs/android-architecture-mvp/#comments Mon, 25 Sep 2017 17:10:06 +0000 http://sility.weblusive-themes.com/?p=77 Earlier we used to develop the application using design like patterns MVC but these pattern cause some problems to meet the customers requirement. The apps are having a very less life time and the customers understand that app need frequent changes to cope up with user engagement and incorporate the upcoming technologies into the app. So, developers need to understand that they have to go with frequent changes in the application on any layer of development. So here comes the new design patterns and most promising are MVP & MVVM pattern.

MVP pattern
As the name suggest that this design pattern is having a Model, View layer and Presenter layer. In MVP pattern our model holds the data as like in any other design pattern. The View layer represents the UI part for most of the part and shows the data which is being hold by the model and View handles the user actions on an activity. Now, Presenter layer – To make our code more readable and maintainable a new concept comes here which is being implemented by the presenter layer. Presenter layer is responsible for all the logic implementation and complex calculations in sort of all the logic code which we do in our activity thus providing a good abstraction of the code. An activity can have multiple presenters if there is a lot which is going on in the activity and can be distinguished independently. Presenter acts as a communication channel between our model and view. It’s the responsibility of the presenter that if data changes in either View and Model it should maintain the singularity of the Model and View. So if there is change in View, let’s say you have a EditText and you gave it some input then Model should also change and if Model changes due to any external reason like an API call our View should be able to reflect the same.

Adding a Interactor

Since we know that in Presenter we make all of our logics and is the communicator layer between View interface and the model, now going further if need to do any I/O operation like database callbacks, ¬†webservices implementation etc then it is a lot to take by the ¬†presenter’s code as it will become more complicated and lengthy, to handle this the concept of Interactor interface is born whose job is to provide any data required by the presenter, the interactor is again loosely and only coupled with the presentor same way the later is coupled with the activity, to know more we will see the implementation in codes below.

Show me code – sample app
To understand MVP pattern, I am going to demonstrate that through an example so that developers can have the concrete understanding of this design pattern. In this example we will populate the data on a recyclerview in an Activity from an API call.

Model
Model is the class in our project which holds the data, as in any other design patterns. For example

public class RecepieModel {
  
    private String title;
    private Double version;
    private String href;
    private List<Result> results = new ArrayList<Result>() {};

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Double getVersion() {
        return version;
    }

    public void setVersion(Double version) {
        this.version = version;
    }

    public String getHref() {
        return href;
    }

    public void setHref(String href) {
        this.href = href;
    }

    public List<Result> getResults() {
        return results;
    }

    public void setResults(List<Result> results) {
        this.results = results;
    }

    public static class Result {


        private String title;
        private String href;
        private String ingredients;
        private String thumbnail;

        public Result(String title, String href, String ingredients, String thumbnail){
            this.title = title;
            this.href = href;
            this.ingredients = ingredients;
            this.thumbnail = thumbnail;
        }

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public String getHref() {
            return href;
        }

        public void setHref(String href) {
            this.href = href;
        }

        public String getIngredients() {
            return ingredients;
        }

        public void setIngredients(String ingredients) {
            this.ingredients = ingredients;
        }

        public String getThumbnail() {
            return thumbnail;
        }

        public void setThumbnail(String thumbnail) {
            this.thumbnail = thumbnail;
        }
    }

}

View

The View is implemented by an Activity and it contains the reference to the presenter. View’s job is to call a method from the Presenter every time there is a user interface action. So let’s see how our View class looks like.

public interface IRecepieView {

    void showProgress();

    void hideProgress();

    void hideDefaultText();

    void setItems(List<RecepieModel.Result> items, int pageNumber);

}

Also, In this example we are having two layouts, one for activity and other for recycler item view.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.wildnettechnologies.recepieonmvp.Recepie.RecepieActivity">

    <TextView
        android:id="@+id/tvWelcomeText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="@string/search_for_recepies_to_load_data" />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerViewRecepie"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipToPadding="false"
        android:scrollbarStyle="outsideOverlay"
        android:visibility="gone"
        tools:layout_editor_absoluteX="168dp"
        tools:layout_editor_absoluteY="240dp" />

    <ProgressBar
        android:id="@+id/progressbarRecepie"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_gravity="center"
        android:visibility="gone" />

</RelativeLayout>

And the below layout is for our recycler view item.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v7.widget.CardView
        android:id = "@+id/cardViewRecepieItem"
        android:layout_width = "fill_parent"
        android:layout_margin="@dimen/_3sdp"
        android:elevation="@dimen/_4sdp"
        android:layout_height = "wrap_content" >

        <RelativeLayout
            android:layout_width = "match_parent"
            android:layout_height = "match_parent"
            android:background = "?attr/selectableItemBackgroundBorderless" >

            <ImageView
                android:id = "@+id/ivPicture"
                android:layout_width = "60dp"
                android:layout_height = "60dp"
                android:layout_margin = "5dp"
                android:fitsSystemWindows = "true"
                android:scaleType = "centerCrop"/>

            <LinearLayout
                android:layout_width = "wrap_content"
                android:layout_height = "wrap_content"
                android:layout_centerVertical = "true"
                android:layout_toRightOf = "@+id/ivPicture"
                android:orientation = "vertical" >
                <TextView
                    android:id = "@+id/tvRecepie"
                    android:layout_width = "fill_parent"
                    android:layout_height = "wrap_content"
                    android:paddingLeft = "4dp"
                    android:paddingRight = "4dp"
                    android:textStyle = "bold" />

                <TextView
                    android:id = "@+id/tvRecepieDetails"
                    android:layout_width = "fill_parent"
                    android:layout_height = "wrap_content"
                    android:paddingLeft = "4dp"
                    android:paddingRight = "4dp"
                    android:maxLines="2"
                    android:textStyle = "normal" />
            </LinearLayout >

        </RelativeLayout >
    </android.support.v7.widget.CardView >
</RelativeLayout>

Now, we have our two layouts let’s see how our presenter works with both the Model layer and View layer.

Presenter

To implement the presenter we use two classes, the first in which we define our presenter interface and the other in which we implement the presenter class. See the code below.

public interface RecepiePresenter {

    void onSearchStarted(RecepieRequestModel mRecepieRequestModel);
}

In this interface class we define our methods and the implementation will be done in RecepiePresenterImpl.java class. Have a look to below class.

public class RecepiePresenterImpl implements RecepiePresenter, RecepieInteractor.OnFinishedListener {

    private IRecepieView IRecepieView;
    private RecepieInteractor recepieInteractor;

    public RecepiePresenterImpl(IRecepieView IRecepieView) {
        this.IRecepieView = IRecepieView;
        this.recepieInteractor = new RecepieInteractorImpl();
    }

    @Override
    public void onSearchStarted(RecepieRequestModel mRecepieRequestModel) {
        IRecepieView.showProgress();
        recepieInteractor.getRecepies(this, mRecepieRequestModel);
    }

    @Override
    public void onRecepieReady(List<RecepieModel.Result> items, int pageNumber) {
        if (IRecepieView != null) {
            IRecepieView.setItems(items, pageNumber);
            IRecepieView.hideProgress();
            IRecepieView.hideDefaultText();
        }
    }

    @Override
    public void onRecepieFailed(String errorMessage)
        {
            IRecepieView.hideProgress();
        }
}

You can see from the code that the constructor is having the reference of our View class i.e. IRecepieView.java. I have also implemented an RecepieInteractor, which is basically an interactor class, I will explain this in next blog but for now understand that Interactor is used to handle the API call or the database queries and then it returns the required data to the presenter. Now see how our Activity class looks like.

public class RecepieActivity extends AppCompatActivity implements IRecepieView {


    @BindView(R.id.tvWelcomeText)
    TextView mTvWelcomeText;
    @BindView(R.id.recyclerViewRecepie)
    RecyclerView mRecyclerViewRecepie;
    @BindView(R.id.progressbarRecepie)
    ProgressBar mProgressbarRecepie;
    private RecepieAdapter mRecepieAdapter;
    private ArrayList<RecepieModel.Result> mRecepieModel = new ArrayList<>();
    private SearchView mSearchView;
    private RecepiePresenter mRecepiePresenter;
    private RecepieRequestModel mRecepieRequestModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recepie);
        ButterKnife.bind(this);
        initializeViews();
    }

    private void initializeViews() {
        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
        mRecyclerViewRecepie.setLayoutManager(layoutManager);
        mRecepieAdapter = new RecepieAdapter(this, mRecepieModel);
        mRecyclerViewRecepie.setAdapter(mRecepieAdapter);
        mRecepiePresenter = new RecepiePresenterImpl(this);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu_search, menu);
        mSearchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.action_search));
        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        mSearchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        initSearch();
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_search:
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }


    @Override
    public void showProgress() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mProgressbarRecepie.setVisibility(View.VISIBLE);
                mRecyclerViewRecepie.setVisibility(View.INVISIBLE);
            }
        });
    }

    @Override
    public void hideProgress() {
        mProgressbarRecepie.setVisibility(View.INVISIBLE);
        mRecyclerViewRecepie.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideDefaultText() {
        mTvWelcomeText.setVisibility(View.INVISIBLE);
    }

    @Override
    public void setItems(List<RecepieModel.Result> items, int pageNumber) {
        if (pageNumber == AppConstants.DEFAULT_PAGE) {
            mRecepieModel.clear();
        }
        mRecepieModel.addAll(items);
    }

    private void initSearch() {
        if (mSearchView != null) {
            mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {

                Timer timer = new Timer();
                final long DELAY = 1000; // milliseconds


                @Override
                public boolean onQueryTextSubmit(String query) {
                    if (query.length() > 0) {
                        mRecepieRequestModel = new RecepieRequestModel();
                        mRecepieRequestModel.setRecepie(query);
                        mRecepieRequestModel.setPage(1);
                        mRecepiePresenter.onSearchStarted(mRecepieRequestModel);
                    }
                    return false;
                }

                @Override
                public boolean onQueryTextChange(final String newText) {
                    if (newText.length() > 0) {
                        Log.e("Search text", "Search Text : " + newText);
                        timer.cancel();
                        timer = new Timer();
                        timer.schedule(
                                new TimerTask() {
                                    @Override
                                    public void run() {
                                        mRecepieRequestModel = new RecepieRequestModel();
                                        mRecepieRequestModel.setRecepie(newText);
                                        mRecepieRequestModel.setPage(1);
                                        mRecepiePresenter.onSearchStarted(mRecepieRequestModel);
                                    }
                                },
                                DELAY
                        );

                    }
                    return false;
                }
            });

            mSearchView.setOnCloseListener(new SearchView.OnCloseListener() {
                @Override
                public boolean onClose() {
                    return false;
                }
            });
        }
    }

    @OnClick(R.id.tvWelcomeText)
    public void onViewClicked() {

    }

    @OnClick({R.id.tvWelcomeText, R.id.progressbarRecepie})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.tvWelcomeText:
                Log.e("welcome Text Clicked", "Welcome clicked");
                break;
            case R.id.recyclerViewRecepie:
                break;
            case R.id.progressbarRecepie:
                break;
        }
    }
}

Notice that our RecepieActivity.java implements the IRecepieView and implements it’s methods now note that we have created our presenter object at line 29

mRecepiePresenter = new RecepiePresenterImpl(this);

And when you see it’s implementation in the RecepiePresenterImpl.java class you can find that we are gettting the reference of IRecepieView from there, a simple example of implementing the interfaces.

public RecepiePresenterImpl(IRecepieView IRecepieView) {
        this.IRecepieView = IRecepieView;
        this.recepieInteractor = new RecepieInteractorImpl();
    }

So, till now we have implemented our Models, Views and Presenter. Now as the user will start giving it’s input in the SearchView of our RecepieActivity.java the presenter object will send that data to the Presenter Implementation class i.e RecepiePresenterImpl.java and in presenter class our interactor object handles the data get the list of recepies from server and again share it’s callback to presenter class.

@Override
    public void onSearchStarted(RecepieRequestModel mRecepieRequestModel) {
        IRecepieView.showProgress();
        recepieInteractor.getRecepies(this, mRecepieRequestModel);
    }

Here is our interactor class is sharing the data to the presentor class via onRecepieReady callback.

@Override
    public void onRecepieReady(List<RecepieModel.Result> items, int pageNumber) {
        if (IRecepieView != null) {
            IRecepieView.setItems(items, pageNumber);
            IRecepieView.hideProgress();
            IRecepieView.hideDefaultText();
        }
    }

Interactor
Interactor is the class which helps our presenter to get the data from database or API call, it helps to segregate the network calls, database query calls from our main logic which we are implementing in our presentor class. The implementation of interaction between interactor and presentor depicts the same relationship between our activity and presentor, here is how our interactor class looks like.

public interface RecepieInteractor
  {

	 void getRecepies(OnFinishedListener listener, RecepieRequestModel model);

	 interface OnFinishedListener
		{
		  void onRecepieReady(List<RecepieModel.Result> items, int pageNumber);
                  void onRecepieFailed(String errorMessage);
		}
  }

And below is it’s implementation class.

public RecepieInteractorImpl() {
    }

    public void getRecepies(final OnFinishedListener finishedListener, final RecepieRequestModel model) {

        ApiFactory.getRecepieClient().getSearchedRecepies(model.getIngredients(), model.getRecepie(), model.getPage())
                .enqueue(new Callback<RecepieModel>() {
                    @Override
                    public void onResponse(Call<RecepieModel> call, Response<RecepieModel> response) {
                        RecepieModel result = response.body();
                        if (result != null)
                            finishedListener.onRecepieReady(result.getResults(), model.getPage());
                        }
                    }

                    @Override
                    public void onFailure(Call<RecepieModel> call, Throwable t) {
                        try {
                            throw new InterruptedException("Error occured!");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        finally{
                           finishedListener.onRecepieFailed(t.getMessage());
                    }
                });
    }

Conclusion

MVP design pattern is widely used by most of the developer community around the world these days as it increases the scalability, readability thus providing more maintainable code. I hope you liked the session.

Happy coding

Vinod K Morya

Download the source code of sample from Github link.

]]>
http://www.vinodmorya.com/blogs/android-architecture-mvp/feed/ 4
Hello world! http://www.vinodmorya.com/blogs/hello-world/ http://www.vinodmorya.com/blogs/hello-world/#comments Fri, 08 Jul 2016 02:49:10 +0000 http://www.vinodmorya.com/?p=1 Welcome to WordPress. This is your first post. Edit or delete it, then start

blogging

]]>
http://www.vinodmorya.com/blogs/hello-world/feed/ 1