When isModuleRun is false, both Application and AndroidManifest participate in the compilation as Libraries, which do not require Activation to be started and custom Applications to be inverted.
isModuleRun=false
Unordered modification
<application android:allowBackup="true" android:supportsRtl="true" android:theme="@style/AppTheme"> </application>
isModuleRun=false
Create a new AndroidManifest.xml file in the main/debug directory
<application android:name=".debug.GoodsApplication" android:allowBackup="true" android:label="@string/goods_name" android:supportsRtl="true" tools:replace="android:label" android:theme="@style/AppTheme"> <activity android:name=".GoodsActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>
Reference Method
References in the gradle directory of Modele
Modify Plugin
if (isModuleRun.toBoolean()) { apply plugin: 'com.android.application' } else { apply plugin: 'com.android.library' }
New applicationId
if (isModuleRun.toBoolean()) { applicationId "com.wustor.cartmoudle" }
Toggle AndroidManifest Files
sourceSets { main { if (isModuleRun.toBoolean()) { manifest.srcFile 'src/main/debug/AndroidManifest.xml' } else { manifest.srcFile 'src/main/AndroidManifest.xml' java { //Remove debug directory when compiling all modules together exclude '**/debug/**' } } } }
Resource Conflict
Suppose we defined an Application in CartModule and then defined app_in strings.xml in the current ModuleName, which is also defined in strings.xml in OrderModule Name, there will be a conflict when you merge, we can only change the above fields to cart_name and order_name solves this problem, which can be solved by this kind of differential naming under strict development specifications, because different Modules basically have different names for resource files, and instant conflicts are small and easy to resolve.
Of course, in addition to this, you can prefix the resource file name in build.gradle
resourcePrefix "cart_"
It can be checked forcefully and price prefix is required for naming, which violates the original intention of componentization and makes the operation more difficult. However, it does not feel necessary to do this. Of course, sometimes pictures with the same name may appear. This can actually be restored to the analysis in the project before componentization, which is not possible.So after all, there is still no good development specification and development habits, there is no need to make some modifications for this kind of, after all, the agreement is larger than the configuration.
Dependent Configuration
From the initial overall architecture diagram, it can be seen that any Module that can switch between Library and Application undoubtedly relies on two of our Base's modules, which can be merged into one. I have two, one is BaseModule and the other is LibraryModule.Here's a look at their dependencies through the configuration in build.gradle:
MainModule
dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') compile project(':routermodule') }
Components are isolated during compilation, so MainModule only depends on RouterModule, and what you just said is on-demand dependency at runtime, which is controlled by gradle's script
//Compile-time component isolation, runtime components depend on demand //mainModule needs to interact with cartModule,goodsModule,usersModule, so dependencies are added at runtime def tasks = project.gradle.startParameter.taskNames for (String task : tasks) { def upperName = task.toUpperCase() if (upperName.contains("ASSEMBLE") || upperName.contains("INSTALL")) { dependencies.add("compile", project.project(':' + 'cartmodule')) dependencies.add("compile", project.project(':' + 'goodsmodule')) dependencies.add("compile", project.project(':' + 'usermodule')) dependencies.add("compile", project.project(':' + 'ordermodule')) } }
BusinessModule
This refers to Goods/Cart/User/OrderModule, which is actually parallel
dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') compile project(':routermodule') }
Business Module depends on RouterModule
RouterModule
dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') compile project(':modulelib') compile 'com.alibaba:arouter-api:1.2.1.1' }
RouterModule depends on LibraryModule
BaseModule
dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') testCompile 'junit:junit:4.12' compile project(':librarymodule') }
BaseModule, as a base library, relies on LibraryModule
LibraryModule
As the lowest working people, it actually provides a dependency, so there is no dependency and they can only play with themselves.
So here, the basic dependencies are already clear, the entire architecture is known, and it is easy to proceed with the construction.
Component Communication
In fact, when we initially divided the modules, it came from business, so when we entered a Module, most of the logic should still be handled in this Module, but occasionally we would deal with other modules to see an interface
[External chain picture transfer failed, source station may have anti-theft chain mechanism, it is recommended to save the picture and upload it directly (img-DD1Ri1On-1630513155378). (https://user-gold-cdn.xitu.io/2018/1/21/161189f8e008ae32?ImageView2/0/w/1280/h/960/ignore-error/1)]
In the case of GoodsModule and CartModule, these two modules can jump to each other. Clicking on the shopping cart icon on the list page of GoodsModule will lead you to the shopping cart list of CartModule, and clicking on the goods will also lead you to the commodity details page of GoodsModule.In addition to this jump, there are actually variables to get, such as HomeFragment, SortFragment in GoodsModule, CartFragment in CartModule, and MineFragment in UserModule on the first page.I am directly dependent on four business modules in the MainModule, but I can actually do otherwise. We can also use Arouter to get instances of Fragments.
Get Instances
In fact, the examples here mostly refer to Fragments, so let's take Fragments as an example. Others can be processed just as they are.
- Reflection Acquisition
Because modules are isolated, we can't create instances of Fragment s directly. It's easy to think of reflection at this time. Launching is omnipotent. Paste the code below.
//Get Fragment Instance public static Fragment getFragment(String className) { Fragment fragment; try { Class fragmentClass = Class.forName(className); fragment = (Fragment) fragmentClass.newInstance(); } catch (Exception e) { throw new RuntimeException(e); } return fragment; }
- Arouter
Arouter It is a routing framework that Alibaba exits. It is convenient to use routing tables in components, as illustrated below.
Add annotations to target fragments
@Route(path = "cart/fragment") public class CartFragement extends BaseFragment{ }
Get instances anywhere
Fragmetn fragment = (Fragment) ARouter.getInstance().build("/cart/fragment").navigation();
Method Call
There are method calls between different Modules, and we can define an interface within each Module, implement it, get it where we need to call, and make a method call.For unified management, we define the interface of each module inside the RouterModule, and since each business module relies on the RouteModule, we simply need to get the interface through reflection and make a method call.
[External chain picture transfer failed, source station may have anti-theft chain mechanism, it is recommended to save the picture and upload it directly (img-6Nghm5lH-1630513155380). (https://user-gold-cdn.xitu.io/2018/1/21/161189f8e03411d1?ImageView2/0/w/1280/h/960/ignore-error/1)]
ModuleCall
Interface Callback Between Module s
public interface ModuleCall { //Initit method is called to pass Context parameter void initContext(Context context); }
Service Interface inherits from ModuleCall to define some callback methods for Modules other than itself to invoke
public interface AppService extends ModuleCall { //TODO Call Method Customization void showHome(); void finish(); }
Impl implementation classes are specific callbacks corresponding to each Module and are direct subclasses that implement the Service interface
public class AppServiceImpl implements AppService { @Override public void showHome() { } @Override public void finish() { } @Override public void initContext(Context context) { } }
The following is also illustrated by reflection and Arouter
-
Reflection Call
public static Object getModuleCall(String name) { T t; try { Class aClass = Class.forName(name); t = (T) aClass.newInstance(); } catch (Exception e) { throw new RuntimeException(e); } return t; }
Get Interface
AppService appService = (AppService) ReflectUtils.getModuleCall(Path.APP_SERVICE);
In fact, just like getting an instance of a Fragment, it is OK to get the corresponding interface by its class name and then call the corresponding method. One thing to note is that if the method invoked after the acquired interface needs to pass in the Context parameter, the initContext method must be called before calling the interface method to use the incoming Context, otherwise a null pointer exception will be reported.
- Arouter
There is an IProvider interface in Arouter, as follows
public interface IProvider { void init(Context var1); }
IProvider is the same as the ModuleCall above, except that once he gets an interface instance, he calls the initContext method, where the Context comes from the parameter passed in from ARouter.init(this), and we don't need to call the initContext manually anymore.
Injection Path in Target Class
@Route(path = Path.APP_SERVICE) public class AppServiceImpl implements AppService { private Context mContext; @Override public void showHome() { Log.d("go--->", "home--->"); } @Override public void finish() { } @Override public void init(Context context) { mContext = context; } }
Get the target class anywhere
AppService appService = (AppService) RouterUtils.navigation(Path.APP_SERVICE);
Then call the method
UI Jump
Jump basically refers to a jump between activities, not to mention a lot, but still an Arouter and a reflex
-
reflex
//Convert class name to target class public static void startActivityWithName(Context context, String name) { try { Class clazz = Class.forName(name); startActivity(context, clazz); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } //Get Intent public static Intent getIntent(Context context, Class clazz) { return new Intent(context, clazz); } //Start Activity public static void startActivity(Context context, Class clazz) { context.startActivity(getIntent(context, clazz)); }
-
Arouter
Register the target Activity with Arouter
@Route(path = Path.CART_MOUDLE_CART) public class CartActivity extends BaseActivity<UselessPresenter, UselessBean> { }
Start Target Activity
ARouter.getInstance().build(Path.CART_MOUDLE_CART).navigation()
summary
Finally, in order to help you deeply understand the principles of Android-related knowledge points and interview-related knowledge, here are the 14 sets of Tencent, byte bouncing, Ali, Baidu and other 2021 interviews that I collected and sorted out, I sorted out the technical points into videos and PDF (actually spend a lot more effort than expected), including the knowledge context + many details.
Guan's collection of 14 sets of Tencent, byte bouncing, Ali, Baidu and so on 2021 latest interview true topic analysis, I organized the technical points into videos and PDF (actually spent a lot more energy than expected), including knowledge context + many details.
[img-hsqQq8Kw-1630513155381)]
[img-oKuaDbwm-1630513155383)]
[img-2XFAvnXk-1630513155384)]
[img-4u3mGwIp-1630513155385)]
There is a lot of information about learning Android online, but if the knowledge is not systematic, you just have a taste when you encounter problems and don't go into further research, it will be difficult to achieve real technology improvement.