Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to realize Android Modularization

2025-04-10 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article focuses on "how to achieve Android modularization", interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Next, let the editor take you to learn "how to achieve Android modularization"!

Modular scenario

Why do you need modularization?

When the number of App users increases and the business volume increases, there will be many development engineers involved in the same project, and the number of people will increase. The original small team development approach is no longer appropriate.

The original code now needs to be maintained by multiple people, and everyone's code quality is different, so it is difficult to Review the code. At the same time, it is easy to cause code conflicts.

At the same time, with the increase of business, the code becomes more and more complex, the code coupling between each module becomes more and more serious, the problem of decoupling needs to be solved urgently, and the compilation time will be longer and longer.

With the increase of personnel, each business has its own set of components, which leads to the different UI style and technical implementation of the same App, and the team technology can not be precipitated.

Architecture evolution

At the beginning, the project architecture uses the MVP pattern, which is also a popular architecture in recent years. Here is the original design of the project.

As the business grows, we add the concept of Domain, Domain fetches data from Data, Data may be Net,File,Cache, various IO, and so on, and then the project architecture becomes like this.

Then, with the increase of personnel, all kinds of basic components become more and more, the business is also very complex, and there is a strong coupling between the business and the business.

With the use of modular technology, the architecture becomes like this.

Technical key points

This paper briefly introduces the technology and technical difficulties that need to be used to realize the modularization of Android project.

Library module

Before starting to modularize, each business needs to be extracted separately into Android Library Module, which comes with a function of Android Studio, which can extract the less dependent as basic components into a separate module.

As shown in the figure, I divided each module into a separate project.

Use gradle to add code dependencies in the main project.

/ common compile project (': ModuleBase') compile project (': ModuleComponent') compile project (': ModuleService') / / biz compile project (': ModuleUser') compile project (': ModuleOrder') compile project (': ModuleShopping')

Library module development problems

You can encounter a variety of problems in extracting code into separate Library Module. The most common problem is the R file. In Android development, each resource file is placed in the res directory. During the compilation process, the R.java file will be generated. R file contains the id corresponding to each resource file, this id is a static constant, but in Library Module, this id is not a static constant, so you should avoid this problem during development.

As a common example, the same method handles click events for multiple view, sometimes using switch (view.getId ()), and then using case R.id.btnLogin to judge, which will lead to problems, because id is not a constant, so this method can not be used.

Similarly, when developing, the most frequently used third-party library is ButterKnife,ButterKnife. When using ButterKnife, you need to configure an id to find the corresponding view, or bind the corresponding event handling, but the assignment of each field in the note also requires static constants, so you cannot use ButterKnife.

There are several solutions:

Re-create a Gradle plug-in to generate a R2.java file in which each id is static constant so that it can be used normally.

Use the most primitive methods provided by the Android system, directly using findViewById and setOnClickListener.

Set up the project to support Databinding, and then use the objects in Binding, but it will increase the number of methods, at the same time, Databinding will also have compilation problems and learning costs, but these are also minor problems, personal feeling that the problem is not big.

The above is the mainstream solution, and the recommended priority is 3 > 2 > 1.

When the modules are separated, everyone can group the corresponding modules separately, but there will be resource conflicts. It is recommended to prefix the resource names of each module. For example, if the login interface layout in the user module is activity_login.xml, it can be written like this us_activity_login.xml. In this way, resource conflicts can be avoided. At the same time, Gradle also provides a field resourcePrefix to ensure that the names of each resource are correct. For specific usage, please refer to the official documentation.

Dependency management

When the Library module is completed, the code is basically clear, similar to the final architecture above, with the most basic skeleton, but it is still not completed, because multiple people still operate the same git warehouse, and various development partners still need to carry out various fork and pr on the same warehouse.

With the division of the code, but the dependence of the main project app becomes more and more, if you modify the code in lib, then the compilation time is very scary, about statistics, originally in the same module, compilation time is about 2-3min, but after separation about 5-6min, this is absolutely unbearable.

The above * problem can be solved by using a separate git repository for each sub-module, so that everyone only needs to pay attention to the git repository they need. The main warehouse uses git submodule and relies on each sub-module separately.

But this still can not solve the problem of too long compilation time, we also pack each module separately, after each sub-module development is completed, release to the maven repository, and then use the version in the main project to rely on.

For example, if you iterate over a certain version, this version is called 1.0.0, then the version of each module is also called the same version. When the version is tested and released, type the corresponding version of tag for each module, and then you will clearly understand the code distribution of each module.

Gradle relies on the following.

/ / common compile 'cn.mycommons:base:1.0.0' compile' cn.mycommons:component:1.0.0' compile 'cn.mycommons:service:1.0.0' / / biz compile' cn.mycommons:user:1.0.0' compile 'cn.mycommons:order:1.0.0' compile' cn.mycommons:shopping:1.0.0'

Some people may ask, since each module has been developed separately, then if you carry out joint development and adjustment, don't worry, this question will be reserved for the time being, and it will be listed later.

Data communication

When a large project is split into several small projects, the posture of the call changes a little. I have summarized several ways of data communication between the various modules of App.

The page jumps, for example, when placing an order on the order page, you need to determine whether the user is logged in, and if not, you need to jump to the login interface.

Take the initiative to obtain data, such as when the order is placed, the user is already logged in, and the basic information of the user needs to be transmitted to place the order.

Passively obtain data, such as when switching users, sometimes need to update the data, such as the order page, need to empty the previous user's shopping cart data.

Let's take a look at the architecture of App.

* in the original way, you can specify the ActivityClass of a page directly, and then jump through intent. However, in the new architecture, because the shopping module does not directly rely on user, then the original jump cannot be used, and we use Router route to jump.

The second problem is that the original method has a special business interest, such as UserManager, which can be called directly, but also cannot be called because the dependency has changed. The solution is all the required operations, defined as interfaces placed in the Service.

The third problem, the original way, can provide a callback interface for event changes, and when I need to listen for an event, I can set a callback.

Page routing jump

As analyzed above, the original code is as follows.

Intent intent = new Intent (this, UserActivity.class); startActivity (intent)

However, after using Router, the invocation mode has changed.

RouterHelper.dispatch (getContext (), "app://user")

What is the specific principle, very simple, do a simple mapping matching, "app://user" and UserActivity.class paired, specifically define a Map,key is the corresponding Router character, value is the class of Activity. Get the corresponding ActivityClass from the map when you jump, and then use the original method.

Some people may ask, how to pass parameters to another page? we can add parameters directly after router. If it is a complex object, you can serialize the object into a json string, and then get the corresponding object from the corresponding page by deserialization.

For example:

RouterHelper.dispatch (getContext (), "app://user?id=123&obj= {" name ":" admin "}")

Note: the json string in the above router needs to be encoded by url, otherwise there will be a problem, this is just an example.

In addition to using Router to jump, I thought that you can directly define the jump Java interface by referring to the Retrofit method. If you need to pass additional parameters, you can define it in the way of function parameters.

There is no implementation class for this Java interface, you can use a dynamic proxy, and then proceed in the same way as you use Router.

So what are the advantages and disadvantages of these two approaches?

Router mode:

A little bit: do not need difficult technical points, easy to use, directly use the string definition jump, can be good compatibility in the future

Disadvantages: because string configuration is used, it is difficult to find bug if characters are entered, and it is difficult to know the meaning of a parameter

Imitate Retrofit mode:

Because it is an Java interface definition, the corresponding jump method can be easily found, and the parameter definition is also very clear, which can be written directly in the interface definition for easy reference.

Similarly, because it is defined by the Java interface, if you need to extend the parameters, you can only redefine the new method, which will lead to multiple method overloads. If you modify it on the original interface, the corresponding original caller will also have to modify the response, which is troublesome.

There are two ways to achieve the above, if there are corresponding students to achieve modularization, you can make a choice according to the actual situation.

Interface and Implement

As analyzed above, if we need to get data from a business, we need to define the interface and the implementation class, respectively, but instantiate the object through reflection when getting it.

Here is a simple code example

Interface definition

Public interface IUserService {String getUserName ();}

Implementation class

Class UserServiceImpl implements IUserService {@ Override public String getUserName () {return "UserServiceImpl.getUserName";}}

Reflection generated object

Public class InjectHelper {@ NonNull public static AppContext getAppContext () {return AppContext.getAppContext ();} @ NonNull public static IModuleConfig getIModuleConfig () {return getAppContext () .getModuleConfig ();} @ Nullable public static T getInstance (Class tClass) {IModuleConfig config = getIModuleConfig (); Class, Class > serviceConfig; public Implement_$$_Database () {serviceConfig = new HashMap () ServiceConfig.put (IUserService.class, UserServiceImpl.class);} public Class

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report