2020 Android 大厂面试(五)插件化、模块化、组件化、热修复、增量更新、Gradle

2020年Android大厂面试必备:插件化、模块化、组件化、热修复、增量更新、Gradle 五、插件化、模块化、组件化、热修复、增量更新、Gradle 1.对热修复和插件化的理解 2.插件化原理分析 3.模块化实现(好处,原因) 4.热修复、插件化 5.项目组件化的理解 6.描述请点击 Android Studio 的 build 按钮后发生了什么 参考答案: 1.对热修复和插件化的理解 Android 类加载器 PathClassLoader.java DexClassLoader.java BaseDexClassLoader.java DexPathList.java 复制代码 (1)Pat 阅读详情

五、插件化、模块化、组件化、热修复、增量更新、Gradle

1.对热修复和插件化的理解
2.插件化原理分析
3.模块化实现(好处,原因)
4.热修复、插件化
5.项目组件化的理解
6.描述清点击 Android Studio 的 build 按钮后发生了什么 

参考答案:

1.对热修复和插件化的理解

Android 类加载器
PathClassLoader.java
DexClassLoader.java
BaseDexClassLoader.java
DexPathList.java 

(1)PathClassLoader:只能加载已经安装到Android系统中的apk文件(/data/app目录),是Android默认使用的类加载器。

(2)DexClassLoader:可以加载任意目录下的dex/jar/apk/zip文件,比PathClassLoader更灵活,是实现热修复的重点。

// PathClassLoader
public class PathClassLoader extends BaseDexClassLoader {
    public PathClassLoader(String dexPath, ClassLoader parent) {
        super(dexPath, null, null, parent);
    }
 
    public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) {
        super(dexPath, null, librarySearchPath, parent);
    }
}
 
 
// DexClassLoaderpublic 
class DexClassLoader extends BaseDexClassLoader {
    public DexClassLoader(String dexPath, String optimizedDirectory,
            String librarySearchPath, ClassLoader parent) {
        super(dexPath, new File(optimizedDirectory), librarySearchPath, parent);
    }
} 
```

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mQdrl5nh-1630047286048)(https://user-gold-cdn.xitu.io/2019/11/19/16e7f9a64f81a28b?imageView2/0/w/1280/h/960/ignore-error/1)]

BaseDexClassLoader

```
dexPath:要加载的程序文件(一般是dex文件,也可以是jar/apk/zip文件)所在目录。
optimizedDirectory:dex文件的输出目录(因为在加载jar/apk/zip等压缩格式的程序文件时会解压出其中的dex文件,该目录就是专门用于存放这些被解压出来的dex文件的)。
libraryPath:加载程序文件时需要用到的库路径。
parent:父加载器 
```

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-219ozv2Y-1630047286049)(https://user-gold-cdn.xitu.io/2019/11/19/16e7ffed57448064?imageView2/0/w/1280/h/960/ignore-error/1)]

```
阿里系:DeXposed、andfix:从底层二进制入手(c语言)。阿里andFix hook 方法在native的具体字段。
       art虚拟机上是一个叫ArtMethod的结构体。通过修改该结构体上有bug的字段来达到修复bug方法的目的,
       但这个artMethod是根据安卓原生的结构写死的,国内很多第三方厂家会改写ArtMethod结构,导致替换失效。
腾讯系:tinker:从java加载机制入手。qq的dex插装就类似上面分析的那种。通过将修复的dex文件插入到app的dexFileList的前面,达到更新bug的效果,但是不能及时生效,需要重启。
        但虚拟机在安装期间会为类打上CLASS_ISPREVERIFIED标志,是为了提高性能的,我们强制防止类被打上标志是否会有些影响性能
美团robust:是在编译器为每个方法插入了一段逻辑代码,并为每个类创建了一个ChangeQuickRedirect静态成员变量,当它不为空会转入新的代码逻辑达到修复bug的目的。
            优点是兼容性高,但是会增加应用体积 

PathClassLoader和DexClassLoader都继承自BaseDexClassLoader

1、Android使用PathClassLoader作为其类加载器,只能去加载已经安装到Android系统中的apk文件;

2、DexClassLoader可以从.jar和.apk类型的文件内部加载classes.dex文件就好了。热修复也用到这个类。

(1)动态改变BaseDexClassLoader对象间接引用的dexElements;
(2)在app打包的时候,阻止相关类去打上CLASS_ISPREVERIFIED标志。
(3)我们使用 hook 思想代理 startActivity 这个方法,使用占坑的方式。

1. startActivity 的时候最终会走到 AMS 的 startActivity 方法
2. 系统会检查一堆的信息验证这个 Activity 是否合法。
3. 然后会回调 ActivityThread 的 Handler 里的 handleLaunchActivity
4. 在这里走到了 performLaunchActivity 方法去创建 Activity 并回调一系列生命周期的方法
5. 创建 Activity 的时候会创建一个 LoaderApk对象,然后使用这个对象的 getClassLoader 来创建 Activity
6. 我们查看 getClassLoader() 方法发现返回的是 PathClassLoader,然后他继承自 BaseDexClassLoader
7. 然后我们查看 BaseDexClassLoader 发现他创建时创建了一个 DexPathList 类型的 pathList对象,然后在 findClass 时调用了 pathList.findClass 的方法
8. 然后我们查看 DexPathList类 中的 findClass 发现他内部维护了一个 Element[] dexElements的dex 数组,findClass 时是从数组中遍历查找的 
```

2.插件化原理分析
---------

[cloud.tencent.com/developer/a…](https://shimo.im/docs/7bBISzfnVjYfqFkR/)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uBDcMyx5-1630047286050)(https://user-gold-cdn.xitu.io/2019/11/19/16e82db92f6945fa?imageView2/0/w/1280/h/960/ignore-error/1)]

```
DexClassLoader和PathClassLoader,它们都继承于BaseDexClassLoader。
DexClassloader多传了一个optimizedDirectory 
```

DexPathList

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uOUBbwvm-1630047286051)(https://user-gold-cdn.xitu.io/2019/11/19/16e82ff2e9f684eb?imageView2/0/w/1280/h/960/ignore-error/1)]

多DexClassLoader

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Eil9QKZs-1630047286052)(https://user-gold-cdn.xitu.io/2019/11/19/16e83006fdeca2d9?imageView2/0/w/1280/h/960/ignore-error/1)]

```
每个插件单独一个DexClassLoader,相对隔离,RePlugin采用该方案 
```

单DexClassLoader

```
将插件的DexClassLoader中的pathList合并到主工程的DexClassLoader中。方便插件与宿主(插件)之间的调用,Small采用该方案 

插件调用主工程
主工程的ClassLoader作为插件ClassLoader的父加载器

主工程调用插件
若使用多ClassLoader机制,通过插件的ClassLoader先加载类,再通过反射调用
若使用单ClassLoader机制,直接通过类名去访问插件中的类,弊端是库的版本可能不一致,需要规范


资源加载

//创建AssetManager对象
AssetManager assets = new AssetManager();
//将apk路径添加到AssetManager中
if (assets.addAssetPath(resDir) == 0){
return null;
}
//创建Resource对象

r = new Resources(assets, metrics, getConfiguration(), compInfo);

插件apk的路径加入到AssetManager中
通过反射去创建,并且部分Rom对创建的Resource类进行了修改,所以需要考虑不同Rom的兼容性。


资源路径的处理

![](https://user-gold-cdn.xitu.io/2019/11/19/16e830a8e16ebe57?imageView2/0/w/1280/h/960/ignore-error/1)

Context的处理

// 第一步:创建Resource

if (Constants.COMBINE_RESOURCES) {
//插件和主工程资源合并时需要hook住主工程的资源
Resources resources = ResourcesManager.createResources(context, apk.getAbsolutePath());
ResourcesManager.hookResources(context, resources);
return resources;
} else {
//插件资源独立,该resource只能访问插件自己的资源
Resources hostResources = context.getResources();
AssetManager assetManager = createAssetManager(context, apk);
return new Resources(assetManager, hostResources.getDisplayMetrics(), hostResources.getConfiguration());
}

//第二步:hook主工程的Resource

//对于合并式的资源访问方式,需要替换主工程的Resource,下面是具体替换的代码。

public static void hookResources(Context base, Resources resources) { 
   try {
        ReflectUtil.setField(base.getClass(), base, "mResources", resources);
        Object loadedApk = ReflectUtil.getPackageInfo(base);
        ReflectUtil.setField(loadedApk.getClass(), loadedApk, "mResources", resources);

        Object activityThread = ReflectUtil.getActivityThread(base);
        Object resManager = ReflectUtil.getField(activityThread.getClass(), activityThread, "mResourcesManager");       
        if (Build.VERSION.SDK_INT < 24) {
            Map<Object, WeakReference<Resources>> map = (Map<Object, WeakReference<Resources>>) ReflectUtil.getField(resManager.getClass(), resManager, "mActiveResources");
            Object key = map.keySet().iterator().next();
            map.put(key, new WeakReference<>(resources));
        } else {                
            // still hook Android N Resources, even though it's unnecessary, then nobody will be strange.
            Map map = (Map) ReflectUtil.getFieldNoException(resManager.getClass(), resManager, "mResourceImpls");
            Object key = map.keySet().iterator().next();
            Object resourcesImpl = ReflectUtil.getFieldNoException(Resources.class, resources, "mResourcesImpl");
            map.put(key, new WeakReference<>(resourcesImpl));
        }
    } catch (Exception e) {
        e.printStackTrace();
    } 
```

替换了主工程context中LoadedApk的mResource对象

将新的Resource添加到主工程ActivityThread的mResourceManager中,并且根据Android版本做了不同处理

```
//第三步:关联resource和Activity

Activity activity = mBase.newActivity(plugin.getClassLoader(), targetClassName, intent);
activity.setIntent(intent);
//设置Activity的mResources属性,Activity中访问资源时都通过mResources

ReflectUtil.setField(ContextThemeWrapper.class, activity, "mResources", plugin.getResources()); 
```

资源冲突

资源id是由8位16进制数表示,表示为0xPPTTNNNN, 由三部分组成:PackageId+TypeId+EntryId

```
修改aapt源码,编译期修改PP段。
修改resources.arsc文件,该文件列出了资源id到具体资源路径的映射。 
```

[blog.youkuaiyun.com/jiangwei091…](https://shimo.im/docs/7bBISzfnVjYfqFkR/)

```
// Main.cpp
result = handleCommand(&bundle);
case kCommandPackage: return doPackage(bundle);

// Command.cpp
int doPackage(Bundle* bundle) {
    if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) {
        err = buildResources(bundle, assets, builder);
        if (err != 0) {
            goto bail;
        }
    }
}

Resource.cpp
buildResources

ResourceTable.cpp

switch(mPackageType) {
    case App:
    case AppFeature:
        packageId = 0x7f;
        break;
    case System:
        packageId = 0x01;
        break;
    case SharedLibrary:
        packageId = 0x00;
        break;    
} 

首先找到入口类:Main.cpp:main函数,解析参数,然后调用handleCommand函数处理参数对应的逻辑,我们看到了有一个函数doPackage。

然后就搜索到了Command.cpp:在他内部的doPackage函数中进行编译工具的一个函数:buildResources函数,在全局搜索,发现了Resource.cpp:发现这里就是处理编译工作,构建ResourceTable的逻辑,在ResourceTable.cpp中,也是获取PackageId的地方,下面我们就来看看如何修改呢?

其实最好的方法是,能够修改aapt源码,添加一个参数,把我们想要编译的PackageId作为输入值,传进来最好了,那就是Bundle类型,他是从Main.cpp中的main函数传递到了最后的buildResources函数中,那么我们就可以把这个参数用Bundle进行携带。


![](https://user-gold-cdn.xitu.io/2019/11/19/16e83e8a58f2bcbe?imageView2/0/w/1280/h/960/ignore-error/1)

[juejin.im/entry/68449…](https://shimo.im/docs/7bBISzfnVjYfqFkR/) [www.jianshu.com/p/8d691b6bf…](https://shimo.im/docs/7bBISzfnVjYfqFkR/)

————————————————————————————————————————————————

[cloud.tencent.com/developer/a…](https://shimo.im/docs/7bBISzfnVjYfqFkR/)

在整个过程中,需要修改到R文件、resources.arsc和二进制的xml文件

四大组件支持

ProxyActivity代理

![](https://user-gold-cdn.xitu.io/2019/11/19/16e841a667ade168?imageView2/0/w/1280/h/960/ignore-error/1)

代理方式的关键总结起来有下面两点:

ProxyActivity中需要重写getResouces,getAssets,getClassLoader方法返回插件的相应对象。生命周期函数以及和用户交互相关函数,如onResume,onStop,onBackPressedon,KeyUponWindow,FocusChanged等需要转发给插件。
PluginActivity中所有调用context的相关的方法,如setContentView,getLayoutInflater,getSystemService等都需要调用ProxyActivity的相应方法。

该方式有几个明显缺点:

插件中的Activity必须继承PluginActivity,开发侵入性强。
如果想支持Activity的singleTask,singleInstance等launchMode时,需要自己管理Activity栈,实现起来很繁琐。
插件中需要小心处理Context,容易出错。
如果想把之前的模块改造成插件需要很多额外的工作。


预埋StubActivity,hook系统启动Activity的过程

![](https://user-gold-cdn.xitu.io/2019/11/19/16e8421dab61ae6c?imageView2/0/w/1280/h/960/ignore-error/1)

VirtualAPK通过替换了系统的Instrumentation,hook了Activity的启动和创建,省去了手动管理插件Activity生命周期的繁琐,让插件Activity像正常的Activity一样被系统管理,并且插件Activity在开发时和常规一样,即能独立运行又能作为插件被主工程调用。

其他插件框架在处理Activity时思想大都差不多,无非是这两种方式之一或者两者的结合。在hook时,不同的框架可能会选择不同的hook点。如360的RePlugin框架选择hook了系统的ClassLoader,即构造Activity2的ClassLoader,在判断出待启动的Activity是插件中的时,会调用插件的ClassLoader构造相应对象。另外RePlugin为了系统稳定性,选择了尽量少的hook,因此它并没有选择hook系统的startActivity方法来替换intent,而是通过重写Activity的startActivity,因此其插件Activity是需要继承一个类似PluginActivity的基类的。不过RePlugin提供了一个Gradle插件将插件中的Activity的基类换成了PluginActivity,用户在开发插件Activity时也是没有感知的。


[www.jianshu.com/p/ac96420fc…](https://shimo.im/docs/7bBISzfnVjYfqFkR/)

[sanjay-f.github.io/2016/04/17/…](https://shimo.im/docs/7bBISzfnVjYfqFkR/)

[www.jianshu.com/p/d43e1fb42…](https://shimo.im/docs/7bBISzfnVjYfqFkR/)

Service插件化总结

初始化时通过ActivityManagerProxy Hook住了IActivityManager。
服务启动时通过ActivityManagerProxy拦截,判断是否为远程服务,如果为远程服务,启动RemoteService,如果为同进程服务则启动LocalService。
如果为LocalService,则通过DexClassLoader加载目标Service,然后反射调用attach方法绑定Context,然后执行Service的onCreate、onStartCommand方法
如果为RemoteService,则先加载插件的远程Service,后续跟LocalService一致。


3.模块化实现(好处,原因)
--------------

[www.cnblogs.com/Jackie-zhan…](https://shimo.im/docs/7bBISzfnVjYfqFkR/)

1、模块间解耦,复用。
(原因:对业务进行模块化拆分后,为了使各业务模块间解耦,因此各个都是独立的模块,它们之间是没有依赖关系。
每个模块负责的功能不同,业务逻辑不同,模块间业务解耦。模块功能比较单一,可在多个项目中使用。)

2、可单独编译某个模块,提升开发效率。
(原因:每个模块实际上也是一个完整的项目,可以进行单独编译,调试)

3、可以多团队并行开发,测试。
原因:每个团队负责不同的模块,提升开发,测试效率。


组件化与模块化

组件化是指以重用化为目的,将一个系统拆分为一个个单独的组件

避免重复造轮子,节省开发维护成本;
降低项目复杂性,提升开发效率;
多个团队公用同一个组件,在一定层度上确保了技术方案的统一性。


模块化业务分层:由下到上

基础组件层:
底层使用的库和封装的一些工具库(libs),比如okhttp,rxjava,rxandroid,glide等
业务组件层:
与业务相关,封装第三方sdk,比如封装后的支付,即时通行等
业务模块层:
按照业务划分模块,比如说IM模块,资讯模块等


Library Module开发问题

在把代码抽取到各个单独的Library Module中,会遇到各种问题。
最常见的就是R文件问题,Android开发中,各个资源文件都是放在res目录中,在编译过程中,会生成R.java文件。
R文件中包含有各个资源文件对应的id,这个id是静态常量,但是在Library Module中,这个id不是静态常量,那么在开发时候就要避开这样的问题。

举个常见的例子,同一个方法处理多个view的点击事件,有时候会使用switch(view.getId())这样的方式,
然后用case R.id.btnLogin这样进行判断,这时候就会出现问题,因为id不是经常常量,那么这种方式就用不了。


4.热修复、插件化
---------

[www.jianshu.com/p/704cac3eb…](https://shimo.im/docs/7bBISzfnVjYfqFkR/)

宿主: 就是当前运行的APP
插件: 相对于插件化技术来说,就是要加载运行的apk类文件
补丁: 相对于热修复技术来说,就是要加载运行的.patch,.dex,*.apk等一系列包含dex修复内容的文件。


![](https://user-gold-cdn.xitu.io/2019/11/20/16e849cc89a4e995?imageView2/0/w/1280/h/960/ignore-error/1)

QQ 空间超级补丁方案

Tinker

![](https://user-gold-cdn.xitu.io/2019/11/20/16e84f634828d930?imageView2/0/w/1280/h/960/ignore-error/1)

HotFix

![](https://user-gold-cdn.xitu.io/2019/11/20/16e84f656fd82b95?imageView2/0/w/1280/h/960/ignore-error/1)

当然就热修复的实现,各个大厂还有各自的实现,比如饿了吗的Amigo,美团的Robust,实现及优缺点各有差异,但总的来说就是两大类

ClassLoader 加载方案
Native层替换方案
或者是参考Android Studio Instant Run 的思路实现代码整体的增量更新。但这样势必会带来性能的影响。


Sophix

[www.jianshu.com/p/4d30ce3e5…](https://shimo.im/docs/7bBISzfnVjYfqFkR/)

底层替换方案
原理:在已经加载的类中直接替换掉原有方法,是在原有类的结构基础上进行修改的。在hook方法入口ArtMethod时,通过构造一个新的ArtMethod实现替换方法入口的跳转。
应用:能即时生效,Andfix采用此方案。
缺点:底层替换稳定性不好,适用范围存在限制,通过改造代码绕过限制既不优雅也不方便,并且还没提供资源及so的修复。
类加载方案
原理:让app重新启动后让ClassLoader去加载新的类。如果不重启,原来的类还在虚拟机中无法重复加载。

优点:修复范围广,限制少。

应用:腾讯系包括QQ空间,手QFix,Tinker采用此方案。
QQ空间会侵入打包流程。
QFix需要获取底层虚拟机的函数,不稳定。
Tinker是完整的全量dex加载。


![](https://user-gold-cdn.xitu.io/2019/11/20/16e850668846ac0e?imageView2/0/w/1280/h/960/ignore-error/1)

Tinker与Sophix方案不同之处
Tinker采用dex merge生成全量DEX方案。反编译为smali,然后新apk跟基线apk进行差异对比,最后得到补丁包。
Dalvik下Sophix和Tinker相同,在Art下,Sophix不需要做dex merge,因为Art下本质上虚拟机已经支持多dex的加载,要做的仅仅是把补丁dex作为主dex(classes.dex)加载而已:
将补丁dex命名为classes.dex,原apk中的dex依次命名为classes(2, 3, 4…).dex就好了,然后一起打包为一个压缩文件。然后DexFile.loadDex得到DexFile对象,最后把该DexFile对象整个替换旧的dexElements数组就好了。

资源修复方案
基本参考InstantRun的实现:构造一个包含所有新资源的新的AssetManager。并在所有之前引用到原来的AssetManager通过反射替换掉。
Sophix不修改AssetManager的引用,构造的补丁包中只包含有新增或有修改变动的资源,在原AssetManager中addAssetPath这个包就可以了。资源包不需要在运行时合成完整包。

so库修复方案
本质是对native方法的修复和替换。类似类修复反射注入方式,将补丁so库的路径插入到nativeLibraryDirectories数据最前面。


Method Hook

[www.jianshu.com/p/7dcb32f8a…](https://shimo.im/docs/7bBISzfnVjYfqFkR/) [pqpo.me/2017/07/07/…](https://shimo.im/docs/7bBISzfnVjYfqFkR/)

5.项目组件化的理解
----------

[juejin.im/post/684490…](https://shimo.im/docs/7bBISzfnVjYfqFkR/)

总结
组件化相较于单一工程,在组件模式下可以提高编译速度,方便单元测试,提高开发效率。
开发人员分工更加明确,基本上做到互不干扰。
业务组件的架构也可以自由选择,不影响同伴之间的协作。
降低维护成本,代码结构更加清晰。


6.描述清点击 Android Studio 的 build 按钮后发生了什么
---------------------------------------

[blog.youkuaiyun.com/u011026779/…](https://shimo.im/docs/7bBISzfnVjYfqFkR/) [blog.youkuaiyun.com/github\_3713…](https://shimo.im/docs/7bBISzfnVjYfqFkR/)

apply plugin : ‘com.android.application’
apply plugin : ‘com.android.library’

编译五阶段

1.准备依赖包 Preparation of dependecies
2.合并资源并处理清单 Merging resources and proccesssing Manifest
3.编译 Compiling
4.后期处理 Postprocessing
5.包装和出版 Packaging and publishing


![](https://user-gold-cdn.xitu.io/2019/11/20/16e87a39572814ef?imageView2/0/w/1280/h/960/ignore-error/1)

简单构建流程:

  1. Android编译器(5.0之前是Dalvik,之后是ART)将项目的源代码(包括一些第三方库、jar包和aar包)转换成DEX文件,将其他资源转换成已编译资源。

  2. APK打包器将DEX文件和已编译资源在使用秘钥签署后打包。

  3. 在生成最终 APK 之前,打包器会使用zipalign 等工具对应用进行优化,减少其在设备上运行时的内存占用。

构建流程结束后获得测试或发布用的apk。


![](https://user-gold-cdn.xitu.io/2019/11/20/16e87a64ed3e3bd7?imageView2/0/w/1280/h/960/ignore-error/1)

图中的矩形表示用到或者生成的文件,椭圆表示工具。

  1. 通过aapt打包res资源文件,生成R.java、resources.arsc和res文件
  2. 处理.aidl文件,生成对应的Java接口文件
  3. 通过Java Compiler编译R.java、Java接口文件、Java源文件,生成.class文件
  4. 通过dex命令,将.class文件和第三方库中的.class文件处理生成classes.dex
  5. 通过apkbuilder工具,将aapt生成的resources.arsc和res文件、assets文件和classes.dex一起打包生成apk
  6. 通过Jarsigner工具,对上面的apk进行debug或release签名
  7. 通过zipalign工具,将签名后的apk进行对齐处理。
    这样就得到了一个可以安装运行的Android程序。

![](https://user-gold-cdn.xitu.io/2019/11/20/16e87a72c1d38b6c?imageView2/0/w/1280/h/960/ignore-error/1)

7.彻底搞懂Gradle、Gradle Wrapper与Android Plugin for Gradle的区别和联系
-----------------------------------------------------------

[zhuanlan.zhihu.com/p/32714369](https://shimo.im/docs/7bBISzfnVjYfqFkR/) [blog.youkuaiyun.com/LVXIANGAN/a…](https://shimo.im/docs/7bBISzfnVjYfqFkR/)

Offline work时可能出现"No cached version of com.android.tools.build:gradle:xxx available for offline mode"问题

Gradle:   gradle-wrapper.properties中的distributionUrl=https/://services.gradle.org/distributions/gradle-2.10-all.zip
Gradle插件:build.gradle中依赖的classpath 'com.android.tools.build:gradle:2.1.2' 

Gradle:
一个构建系统,构建项目的工具,用来编译Android app,能够简化你的编译、打包、测试过程。

Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化建构工具。它使用一种基于Groovy的特定领域语言来声明项目设置,而不是传统的XML。当前其支持的语言限于Java、Groovy和Scala

Gradle插件:

我们在AS中用到的Gradle被叫做Android Plugin for Gradle,它本质就是一个AS的插件,它一边调用 Gradle本身的代码和批处理工具来构建项目,一边调用Android SDK的编译、打包功能。
Gradle插件跟 Android SDK BuildTool有关联,因为它还承接着AS里的编译相关的功能,在项目的 local.properties 文件里写明 Android SDK 路径、在build.gradle 里写明 buildToolsVersion 的原因。


| 插件版本 | Gradle 版本 |
| --- | --- |
| 1.0.0 - 1.1.3 | 2.2.1 - 2.3 |
| 1.2.0 - 1.3.1 | 2.2.1 - 2.9 |
| 1.5.0 | 2.2.1 - 2.13 |
| 2.0.0 - 2.1.2 | 2.10 - 2.13 |
| 2.1.3 - 2.2.3 | 2.14.1+ |
| 2.3.0+ | 3.3+ |
| 3.0.0+ | 4.1+ |
| 3.1.0+ | 4.4+ |
| 3.2.0 - 3.2.1 | 4.6+ |
| 3.3.0 - 3.3.2 | 4.10.1+ |
| 3.4.0+ | 5.1.1+ |

Done

  

# 最后

有小伙伴私信问Compose的问题,好不好用啊,现在要不要学啊?

其实答案很简单,自从谷歌2019年公布了声明式UI框架Jetpack Compose后,两年多的时间,各种大力宣传,和大量资源的倾斜,API功能都趋于稳定了。

至于好不好用,各种用过的同行都是持肯定态度的。优势大概就是这四点:

***强大的工具和直观的Kotlin API***
***简化并加速了Android上的UI开发***
***可以帮助开发者用更少更直观的代码创建View***
***有更强大的功能,以及还能提高开发速度***

这么大的优势,毋庸置疑,肯定是要学的嘛,而且越快掌握越好。别等刀架到脖子上了,才去练金钟罩。

至于怎么快速上手,可以给大家免费分享一份**《Jetpack Compose 完全开发手册》**,手把手教大家从入门到精通。

### 第一章 初识 Jetpack Compose

- 为什么我们需要一个新的UI 工具?

- Jetpack Compose的着重点

  加速开发
  强大的UI工具
  直观的Kotlin API

![图片](https://img-blog.csdnimg.cn/img_convert/2cb088d137d71e4b67185050c712cf3a.png)

- API 设计

![图片](https://img-blog.csdnimg.cn/img_convert/2cd1f94ccaf4b18fb4dbb9ce029a1148.png)

- Compose API 的原则
  一切都是函数
  顶层函数(Top-level function)
  组合优于继承
  信任单一来源

![图片](https://img-blog.csdnimg.cn/img_convert/502c72f3fe179b020224214d18529772.png)

- 深入了解Compose
  Core
  Foundation
  Material

![图片](https://img-blog.csdnimg.cn/img_convert/56e99422e3992305d30b1377f7cabfa7.png)

- 插槽API

### 第二章 Jetpack Compose构建Android UI

- Android Jetpack Compose 最全上手指南
  Jetpack Compose 环境准备和Hello World
  布局
  使用Material design 设计
  Compose 布局实时预览
  ……

![图片](https://img-blog.csdnimg.cn/img_convert/60bf7ff817f9005c1b0ed030eea8c202.png)

- 深入详解 Jetpack Compose | 优化 UI 构建
  Compose 所解决的问题
  Composable 函数剖析
  声明式 UI
  组合 vs 继承
  封装
  重组
  ……

![图片](https://img-blog.csdnimg.cn/img_convert/211f570514129c466fa4c6671595ac88.png)

- 深入详解 Jetpack Compose | 实现原理
  @Composable 注解意味着什么?
  执行模式
  Positional Memoization (位置记忆化)
  存储参数
  重组
  ……

![图片](https://img-blog.csdnimg.cn/img_convert/c64c0ddfbf4c8515b8c517675d01de43.png)

### 第三章 Jetpack Compose 项目实战演练(附Demo)

- Jetpack Compose应用1
  开始前的准备
  创建DEMO
  遇到的问题

![图片](https://img-blog.csdnimg.cn/img_convert/c833cd82669fce8335ccace204c4dbb6.png)

- Jetpack Compose应用2
- Jetpack Compose应用做一个倒计时器
  数据结构
  倒计时功能
  状态模式
  Compose 布局
  绘制时钟

![图片](https://img-blog.csdnimg.cn/img_convert/eff219c1b38cddf6d18f79cb7091dc42.png)

- 用Jetpack Compose写一个玩安卓App
  准备工作
  引入依赖
  新建 Activity
  创建 Compose
  PlayTheme
  画页面
  底部导航栏
  管理状态
  添加页面

![图片](https://img-blog.csdnimg.cn/img_convert/9d6a7aac49d5c1f7b7a5a1f403c53bab.png)

- 用Compose Android 写一个天气应用
  开篇
  画页面
  画背景
  画内容
  ……

![图片](https://img-blog.csdnimg.cn/img_convert/9090339dda5d6dc7f54dc70f94d1a85f.png)

- 用Compose快速打造一个“电影App”
  成品
  实现方案
  实战
  不足
  ……

![图片](https://img-blog.csdnimg.cn/img_convert/298bb1d7ac1cacf38941f05710bb46d3.png)



由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!

**有需要的小伙伴,可以微信扫下方二维码免费领取**

![img](https://img-blog.csdnimg.cn/230c1855332b4fb28f30b5fd20e2152e.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FlcmZhNzg5,size_16,color_FFFFFF,t_70#pic_center)
深入理解C++23的Deducing this特性(上):基础概念与语法详解 C++23标准中引入的"Deducing this"特性是一项重大革新,它不仅改变了我们编写成员函数的方式,还为模板元编程和设计模式实现带来了新的可能。 阅读详情

相关推荐

手把手教你搭建《黑色沙漠》单机版:从下载到联机的完整指南(含GM工具使用)

本文提供《黑色沙漠》单机版从下载安装到GM工具使用及局域网联机的完整教程。详细解析不同版本选择、系统配置要求、常见问题解决,并分享GM工具高级命令和局域网联机设置技巧,帮助玩家轻松搭建个性化游戏环境。

weixin_28738165的博客 469

Android如何组件化开发,组件可随时作为插件更新升级

开发之前先弄明白,何为组件化开发。 简单的说组件化开发就是分模块开发, 1, 可作为单独的应用来开发测试验证, 2, 可以作为模块来集成, 3, 设计的好,也可作为插件来动态更新或修复Bug. 这就是组件开发的好处。 现在移动互联网项目片地开花,业务需求也持续增加,组件化设计就是一种良好实践。 架构设计如下: 这样的设计就可以很好的按各自业务开发了,相对可以独立开发并验证。 通过配置isModule属性来决定是否集成还是开发。 组件与组件之间如果有交互呢,那如何处理此类交

txm6355754的专栏 3120

Nano Banana 2哪里使用?Nano Banana 2提示词合集和使用教程

收集最强的Nano Banana 2提示词合集,以及Nano Banana 2哪里使用的教程,并且有10个免费使用渠道。

qq_42927225的博客 1997

Android AGP8.1.0组件化初探

其实本文的目的不是在于如何使用,ARouter这个很简单,相信做过组件化的同学都会,只是需要遇到问题时学会分析和调试,要不然盲目猜测是不会有结果的。开发这条路任重而道远,希望大家都能上下求索,享受这个求索的过程,痛并快乐着,也很重要,新技术出来可以尝试,也可以根据自己需要调整,不一样说非得更新用这个新技术,只要能解决问题,咋好用咋来。

u012556114的博客 2059

DPO(Direct Preference Optimization)直接偏好优化

本文介绍了DPO(直接偏好优化)方法,该方法通过简化传统的RLHF(基于人类反馈的强化学习)流程,直接利用人类偏好数据进行模型优化。DPO的核心思想是跳过奖励模型训练和强化学习交互步骤,通过数学推导将优化目标转化为仅与策略概率分布相关的形式。推导表明最优策略与奖励模型之间存在显式关系,从而可以构建直接优化策略的损失函数。与RLHF相比,DPO简化了训练流程,提高了工程实现稳定性,同时保持了同等效果。

TeenLucifer的博客 1956

OpenGL计算着色器工作组设置测试

先看看不同的显卡上工作组的数量情况。 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, data); glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, data + 1); glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, data...

qq_26328385的博客 1485

Android热更新,android组件化通信

2.集成SDK gradle这个配置 在app module的“build.gradle”文件中添加(示例配置): android { defaultConfig { ndk { //设置支持的SO库架构 abiFilters ‘armeabi’ //, ‘x86’, ‘armeabi-v7a’, ‘x86_64’, ‘arm64-v8a’ } } } dependencies { compile “com.android.support:multidex:1.0.1” // 多dex配置 //注释掉原有

m0_64603776的博客 845

ESD防护设计宝典(十一):CE(传导发射)超标问题排查与解决

(Conducted Emission, CE),亦称为传导骚扰,是电子电气设备或系统内部的电压、电流通过信号线、电源线或地线向外传输,对其他电子电气设备或系统造成电磁干扰的物理现象。其。

m0_56451176的博客 857

重新编译生成R文件

在为游戏接入A站SDK时,发现接好的SDK,编译执行时,找不到资源Id。当时就很懵逼,搞不懂为什么R文件没有自动生成资源id,通过一天的研究,查找资料,终于搞定了!下面就是怎么重新编译生成R文件的步骤: 1.生成smali文件夹 使用打包脚本生成一个合并ACfunSDK后的无签名apk包,使用apktool d xx.apk解压apk,生成smali文件夹 2

DexLins的博客 5582

免费教你快速学会分析运算放大器电路(保证学会)

本文旨在学习如何快速简单地对运算放大器进行分析

一名热爱技术的工程师的博客。分享技术干货,记录美好生活。永远相信美好的事情即将发生。 1万+

解决Home Assistant中安装的Advanced SSH & Web Terminal插件打开提示“502 Bad Gateway” 且弹窗提示“加载项似乎尚未准备就绪,它可能仍在启动中“问题

  在HomeAssistant的应用商店安装了【AdvancedSSH&WebTerminal】插件,但是打开这个终端连接到HomeAssistant的时候却提示“502BadGateway”且弹窗提示“加载项似乎尚未准备就绪,它可能仍在启动中,您想重试吗?”一直无法进入HomeAssistant的系统中

提供C#相关开发 、云计算、运维测试、网络安全相关技术分享与服务,有意向可联系。 2840

2020 Android 大厂面试(五)插件化、模块化、组件化、热修复、增量更新、Gradle...

1.对热修复和插件化的理解 2.插件化原理分析 3.模块化实现(好处,原因) 4.热修复、插件化 5.项目组件化的理解 6.描述清点击 Android Studio 的 build 按钮...

Android技术之家 827

2024年03月CCF-GESP编程能力等级认证Python编程五级真题解析

下面流程图在yr输入2024时,可以判定yr代表闰年,并输出 2月是29天 ,则图中菱形框中应该填入( )。 A. (yr % 400 == 0) or (yr % 4 == 0) B. ( yr % 400 == 0) or (yr % 4 == 0 and yr %100 != 0) C. ( yr % 400 == 0) and ( yr % 4 == 0) D. (yr % 400 == 0) and (yr % 4 == 0 and yr % 100 != 0)

人生就是一个不断学习的过程 748

2020 Android 大厂面试(之)插件化、模块化、组件化、热修复、增量更新、Gradle

2020 Android 大厂面试(之)插件化、模块化、组件化、热修复、增量更新、Gradle

shiningdreamercaihua的博客 365

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

2020 Android 大厂面试-插件化、模块化、组件化、热修复、增量更新、Gradle

然后就搜索到了Command.cpp:在他内部的doPackage函数中进行编译工具的一个函数:buildResources函数,在全局搜索,发现了Resource.cpp:发现这里就是处理编译工作,构建ResourceTable的逻辑,在ResourceTable.cpp中,也是获取PackageId的地方,下面我们就来看看如何修改呢?Sophix不修改AssetManager的引用,构造的补丁包中只包含有新增或有修改变动的资源,在原AssetManager中addAssetPath这个包就可以了。

2401_86352893的博客 2257

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

2024-Android-大厂面试(五)插件化、模块化、组件化、热修复、增量更新、Gradle

文章会持续更新,请期待。五、插件化、模块化、组件化、热修复、增量更新、Gradle1.对热修复和插件化的理解2.插件化原理分析3.模块化实现(好处,原因)4.热修复、插件化5.项目组件化的理解6.描述清点击 Android Studio 的 build 按钮后发生了什么。

2401_89787802的博客 604

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

2024 Android 大厂面试-插件化、模块化、组件化、热修复、增量更新、Gradle

如360的RePlugin框架选择hook了系统的ClassLoader,即构造Activity2的ClassLoader,在判断出待启动的Activity是插件中的时,会调用插件的ClassLoader构造相应对象。其实最好的方法是,能够修改aapt源码,添加一个参数,把我们想要编译的PackageId作为输入值,传进来最好了,那就是Bundle类型,他是从Main.cpp中的main函数传递到了最后的buildResources函数中,那么我们就可以把这个参数用Bundle进行携带。

2401_87022199的博客 1382

2021 Android 大厂面试(五)插件化、模块化、组件化、热修复、增量更新、Gradle

作者:爱雨浮龙 链接:https://juejin.im/post/5dd274515188254c6443815eaq 前言 文章会持续更新,请期待。建议收藏 五、插件化、模块化、组件化、热修复、增量更新、Gradle 1.对热修复和插件化的理解 2.插件化原理分析 3.模块化实现(好处,原因) 4.热修复、插件化 5.项目组件化的理解 6.描述清点击 Android Studio 的 build 按钮后发生了什么 1.对热修复和插件化的理解 Android 类加载器 PathClassLoader.

wzh19950826的博客 558

2022大厂Android春招面试经历,Android插件化、模块化、组件化、热修复、增量更新、Gradle

自己项目中一直都是用的开源的xUtils框架,包括BitmapUtils、DbUtils、ViewUtils和HttpUtils四大模块,这四大模块都是项目中比较常用的。最近决定研究一下xUtils的源码,用了这么久总得知道它的实现原理吧。我是先从先从BitmapUtils模块开始的。BitmapUtils和大多数图片加载框架一样,都是基于内存-文件-网络三级缓存。也就是加载图片的时候首先从内存缓存中取,如果没有再从文件缓存中取,如果文件缓存没有取到,就从网络下载图片并且加入内存和文件缓存。 这篇帖子先分析

m0_68839021的博客 368

2020最新Android大厂面试真题大全(附答案)

四、插件化、模块化、组件化、热修复、增量更新、Gradle 1.对热修复和插件化的理解 2.插件化原理分析 3.模块化实现(好处,原因) 4.热修复、插件化 5.项目组件化的理解 6.描述清点击 Android Studio 的 build 按钮后发生了什么 五、架构设计和设计模式 1.谈谈你对Android设计模式的理解 2.MVC MVP MVVM原理和区别 3.你所知道的设计模式有哪些? 4.项目中常用的设计模式 5.手写生产者/消费者模式 6.写出观察者模式的代码 7.适配器模式,装饰者模式,外观

m0_67734975的博客 228

NET Framework 3(2),Android插件化、模块化、组件化、热修复、增量更新、Gradle

这时就需要大家安装该功能。这个是直接安装net3.5的软件,用管理员打开即可安装成功【但因为我系统是LTSC的,所以安装时候提示不兼容,我通过source安装完成再次打开, 就提示图片中的内容了】,尤其是非计算机专业的同学,面试官一上来肯定是问你基础,要是基础表现不好很容易被扣上基础不扎实的帽子,常见的就那些,只要你平时认真思考过基本上面试是没太大问题的。如果专业版的,很好弄,但我的系统比较特别,是LTSC版本的,所以不适用常规win10的方法。等一系列的方法,最后使用\sources\sxs才成功安装。

2301_79985012的博客 724

2024最新BAT Android高端技术面试145题详解,零基础入门android逆向视频课程

首先是感觉自己的基础还是不够吧,大厂好像都喜欢问这些底层原理。之前的准备只涉及了Java、Android、计网、数据结构与算法这些方面,面对面试官对其他基础课程的考察显得捉襟见肘。下一步还是要查漏补缺,进行针对性复习。最后的最后,那套资料这次一定要全部看完,是真的太全面了,各个知识点都涵盖了,几乎我面试遇到的所有问题的知识点这里面都有!希望大家不要犯和我一样的错误呀!!!一定要看完!一个人可以走的很快,但一群人才能走的更远。

2401_84103675的博客 1024
上一篇: 3 分钟理解完全二叉树、平衡二叉树、二叉查找树
CV大师啊
博客等级 码龄5年 5984粉丝 15原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值