A Simple movies application that is built with MVVM , Dagger2 , LiveData and Room.
In this project we will consume themoviedb APIs to build a simple app that have the following features
- Fetch Movies by categories (Popular, Top rated and upcoming ).
- Show every movie details in separate screen
- Cache data offline.
- Search for movies.
The following diagram shows how all the modules will interact with one another.
Each component depends only on the component one level below it. For example, activities and fragments depend only on a view model. The repository is the only class that depends on multiple other classes; on a persistent data model and a remote backend data source.
- Model Represents the data and business logic of the app.
- Our bussiness is represented with the following classes (Movie, Category and Video)
- Room db is used to cache the data locally and is our "single source of truth" in providing the data for the view.
- MoviesActivity: Displays list of movies depending on categories ( POPULAR , Top rated , upcoming )
- MovieDetailsActivity: Displays movie details and it's vidoes
- CategoryBottomSheet: Switch between different categories
- CategoryAdapter: inflates and displays filterList that is provided from CategoryBottomSheet
- MoviesAdapter: inflates and displays moviesList that is provided from MoviesActivity's fetch movies by filter/search result.
- VideoAdapter: inflates and displays videoList that is provided from MovieDetailsActivity.
- OnCategoryClickListener: responsible for interaction between CategoryAdapter and CategoryBottomSheet
- OnCategorySelectedListener: responsible for interaction between CategoryBottomSheet and MoviesActivity
- OnMovieClickListener: responsible for interaction between MoviesAdapter,SearchAdapter and MoviesActivity
- MoviesViewModel: MoviesActivity listens to movies changes that will happen when MoviesRepository is invoked to fetch the data from Remote service / Local DB
- MovieDetailViewModel: MovieDetailsActivity listens to videos changes that will happen when MovieDetailsRepository is invoked to fetch the data from Remote service / Local DB
- We are using the repository pattern to interact with the remote service and our local db
- The repository saves results into the database.
- The repository doesn't make unnecessary requests if the data is cached and up to date.
- MoviesRepository: is being used by MoviesViewModel to fetch the list of movies. and also it provides the search logic
- MovieDetailsRepository: is being used by MovieDetailViewModel to provide list of videos for specific movie.
A helper class that is used to take the decision of loading the data from the local db or from remote service.
The following diagram shows the decision tree for NetworkBoundResource:
NetworkBoundResource is using the local db as it's single source of truth.For example It starts by observing the database for list of movies resource. When the entry is loaded from the database for the first time, NetworkBoundResource checks whether the result is good enough to be dispatched or that it should be re-fetched from the network.
- We're using room database which is built over SQLITE as our local db.
- MovieDao: is used to insert/fetch our list of movies
- VideosDao: is used to insert/fetch list of videos for specific movie.
- VideoConverter: converts List
- MovieDatabase: is responsible to provide us one and only object to access our db.
- AppExecutors: is used to write and read from db.
- ApiResponse: a generic class for handling responses from retrofit
- RestApiService: provides and end point for our remote service
- BaseActivity: is extended by any activity in the app. it declares unified structure and contains common methods for our activities.
- BaseViewHolder: the same as BaseActivity but for ViewHolder.
- DataWrapper: Wrappes our data call back with status and message to be able to handle different status inside views.
- LiveDataCallAdapter and LiveDataCallAdapterFactory: is used to get LiveData as call back from retrofit.
- RefreshRateLimiter: is a factor in refreshing data decision.
Dependency injection allows classes to define their dependencies without constructing them. At runtime, another class is responsible for providing these dependencies
- For DI we are using Koin
- Retrofit for consuming REST APIs
- Koin for dependency injection
- Picasso for loading images from remote servers
- YouTubeAndroidPlayerApi to preview and play videos
- Facebook Shimmer library as loading animation
- Room as presistance library.
- Gson as data parser.