You know the importance of architecture and design pattern if you have worked on any intermediate and high-level projects. It is essential to keep our project loosely coupled; which means keeping all the components in our project separate, meaning each component has little or no knowledge about the others. This is especially important in big projects because things get messy quite quickly, and the end-result is unmaintainable. These spaghetti codes (Tightly coupled) is also difficult to test because many different parts depend on each other. That’s why we have architecture patterns to make our project modular, where each component have a specific responsibility and modifications are possible without modifying other modules.
如果您从事任何中级和高级项目,您就会知道架构和设计模式的重要性。 使我们的项目保持松散耦合是至关重要的; 这意味着将我们项目中的所有组件都分开,这意味着每个组件对其他组件几乎一无所知。 这在大型项目中尤其重要,因为事情很快就会变得混乱,最终结果无法维持。 这些意大利面条代码(紧密耦合)也很难测试,因为许多不同部分相互依赖。 这就是为什么我们拥有使我们的项目模块化的架构模式的原因,其中每个组件都有特定的职责,并且无需修改其他模块就可以进行修改。
There are several different architectural patterns to choose from, here are some of the popular ones you may have heard about,
有几种不同的建筑模式可供选择,以下是您可能听说过的一些流行模式,
MVC MVC MVP 最有价值球员 MVVM MVVMIn android, we can use any one of the above as each has their own advantages and disadvantages (which we are not going to discuss here). But it is highly recommended by google and android developers team to use MVVM architecture.
在android中,我们可以使用以上任何一种方法,因为每种方法都有其自身的优缺点(在此不再赘述)。 但是Google和android开发人员团队强烈建议使用MVVM体系结构。
MVVM stands for Model-View-ViewModel architecture. There are several advantages of using MVVM in your projects, such as:
MVVM代表Model-View-ViewModel体系结构。 在项目中使用MVVM有几个优点,例如:
Makes the project loosely coupled. 使项目松散耦合。 Easier to maintain. 易于维护。 Simple to add a new feature or remove existing. 轻松添加新功能或删除现有功能。 Very testable code. 可测试的代码。 It gives great structure to your project and makes it easier to navigate and understand our code. 它为您的项目提供了良好的结构,并使浏览和理解我们的代码更加容易。Now, there are quite a few frameworks that can help us implement MVVM. Which one should you use in case you don’t want to make your own?
现在,有很多框架可以帮助我们实现MVVM。 如果您不想自己做,应该使用哪一个?
DevExpress interpretation of XKCD漫画的 XKCD Comics DevExpress解释Google provides its framework comprised of several different components that you can use and build upon to make your job simpler.
Google提供了由几个不同组件组成的框架,您可以使用这些框架并以此为基础来简化您的工作。
This is how Google’s implementation of MVVM architecture looks like:
这就是Google的MVVM架构实现的样子:
This part of our architecture help us build our user interface and the only part our users can interact directly. I consist of Fragment object defined in “src” and a layout resource. There is a two-way binding between them, which allows easy data sharing.
我们架构的这一部分有助于我们构建用户界面,并且用户只能直接进行交互。 我由“ src”中定义的Fragment对象和布局资源组成。 它们之间有双向绑定,可以轻松共享数据。
Here’s an example, you don’t need to understand each line, only go through their implementations.
这是一个示例,您不需要了解每一行,只需了解它们的实现即可。
Fragment :view/MovieFragment.javapublic class MovieFragment extends Fragment { OnPosterClickListener mCallback; GridView moviesLayout; List<Movie> movies; public MovieFragment() { } public MovieFragment(List<Movie> movies) { this.movies = movies; } public interface OnPosterClickListener { void onImageClick(Movie movie); } @Override public void onAttach(@NonNull Context context) { super.onAttach(context); try { mCallback = (OnPosterClickListener) context; } catch (ClassCastException e) { throw new ClassCastException(); } } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { final View rootView = inflater.inflate( //Inflating fragment with the layout R.layout.fragment_movie_list, container, false); moviesLayout = rootView.findViewById(R.id.images_grid_view); MovieRecyclerViewAdapter mMovieAdapter = new MovieRecyclerViewAdapter(getContext(), movies); moviesLayout.setAdapter(mMovieAdapter); moviesLayout.setOnItemClickListener(( (parent, view, position, id) -> mCallback.onImageClick(movies.get(position)) )); return rootView; }}Layout:res/fragment_movie_list.xml<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayout 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"><androidx.recyclerview.widget.RecyclerView android:id="@+id/movie_recycler_view" android:name="com.example.moviereviewer.MovieFragment" android:layout_width="match_parent" android:layout_height="0dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/toolbar" /></androidx.constraintlayout.widget.ConstraintLayout>ViewModel object acts as an intermediate between View and the Model, meaning it provides data for the UI components like fragments or activities. It also includes an observable data holder called LiveData that allows ViewModel to inform or update the View whenever the data get updated. It is very crucial, mainly to keep our app from reloading on orientation changes. Which ultimately provides a great user experience.
ViewModel对象充当View和Model之间的中介,这意味着它为UI组件(例如片段或活动)提供数据。 它还包括一个称为LiveData的可观察数据保存器,该保存器允许ViewModel在数据更新时通知或更新View。 这非常关键,主要是防止我们的应用程序在方向变化时重新加载。 最终提供了出色的用户体验。
Here’s an example,
这是一个例子
// viewmodel/MovieModelView.javapublic class MovieViewModel extends AndroidViewModel { private static final String DEFAULT_FILTER = "popular"; private MovieRepository movieRepository; private LiveData<TMDB_Response> movieList = new MutableLiveData<>(); private MutableLiveData<TrailerResponse> trailerList = new MutableLiveData<>(); private MutableLiveData<ReviewResponse> reviewList = new MutableLiveData<>(); private MutableLiveData<String> filter = new MutableLiveData<>(); public MovieViewModel(@NonNull Application application) { super(application); filter.setValue(DEFAULT_FILTER); movieRepository = new MovieRepository(application); } public void setFilter(String value) { filter.setValue(value); } public String getFilter() { return filter.getValue(); } public LiveData<MovieResponse> getMovieList(int pageNo) { movieList = Transformations.switchMap(filter, (v) -> movieRepository.getMovieList(v, pageNo)); return movieList; } public LiveData<TrailerResponse> getTrailerList(int movieId) { trailerList = movieRepository.getTrailerList(movieId); return trailerList; } public LiveData<ReviewResponse> getReviewList(int movieId) { reviewList = movieRepository.getReviewList(movieId); return reviewList; }}Model is responsible for fetching the data either from the local SQLite database or from a web service. So it is further divided into various components.
模型负责从本地SQLite数据库或Web服务中获取数据。 因此,它进一步分为各种组件。
Repository — It is responsible for handling the data information that includes where to get the data from either a web service or the persisted data models.
存储库-它负责处理数据信息,其中包括从Web服务或持久性数据模型中获取数据的位置。
Room — It is an ORM provided by Google, which provides an abstraction layer between the SQLite database and our data in the form of objects. It gives us errors in compile-time, which is much better than run-time error which difficult to track and debug.
Room —由Google提供的ORM,它以对象的形式在SQLite数据库和我们的数据之间提供一个抽象层。 它给我们带来了编译时的错误,这比难以跟踪和调试的运行时错误要好得多。
In order to use the room, it’s very important to define our schema. We do that by creating a data model class and add an
为了使用房间,定义我们的模式非常重要。 我们通过创建数据模型类并添加一个
@entity annotation. We also must add a @PrimaryKey annotation to our entity’s id.
@entity批注。 我们还必须在实体的ID中添加@PrimaryKey批注。
After that, we must create our database class extending RoomDatabase, and we must define it as abstract so that room can take care of its implementations.
之后,我们必须创建扩展RoomDatabase的数据库类,并且必须将其定义为抽象的,以便Room可以处理其实现。
@Database(entities = Movie.class, version = 1)public abstract class MovieDatabase extends RoomDatabase { private static MovieDatabase instance; public abstract MovieDao movieDao(); public static synchronized MovieDatabase getInstance(Context context) { if (instance == null) {instance = Room.databaseBuilder( context.getApplicationContext(), MovieDatabase.class, "movie_database" ).fallbackToDestructiveMigration() .build(); } return instance; }}Finally, define all the necessary operation we require from the database. For that, we create an interface to access database, also known as “data access object (DAO)”.
最后,定义我们需要从数据库中进行的所有必要操作。 为此,我们创建了一个访问数据库的接口,也称为“数据访问对象(DAO)”。
@Daopublic interface MovieDao { @Insert void insert(Movie movie); @Query("SELECT * FROM favorites") public LiveData<List<Movie>> getFavMovies(); @Query("SELECT * FROM favorites WHERE id=:movieId") public LiveData<List<Movie>> getCurrentMovie(int movieId); @Delete void delete(Movie movie);}Web Service — Now if we wish to access data from a REST API, we have a library called “Retrofit” at our disposal. And it helps us make our network calls. In short, it feeds us the JSON string; we convert that JSON response to java object and add as an entity to our app.
Web服务—现在,如果我们希望从REST API访问数据,我们可以使用一个名为“ Retrofit”的库。 它可以帮助我们进行网络通话。 简而言之,它为我们提供了JSON字符串; 我们将该JSON响应转换为java对象,并作为一个实体添加到我们的应用程序中。
One an easily make android apps without following this architecture, but if we want to make apps that are robust, testable, maintainable and easy to read, then we must use this to our advantage. I will be writing more on MVVM architecture and how to follow the best practices.
一个无需遵循这种架构即可轻松制作的android应用程序,但是如果我们要使应用程序健壮,可测试,可维护且易于阅读,那么我们就必须利用这一优势。 我将写更多关于MVVM架构以及如何遵循最佳实践的文章。
翻译自: https://medium.com/swlh/understanding-mvvm-architecture-in-android-aa66f7e1a70b
相关资源:Android MVVM架构源码