Android Gradle基础介绍,2024年最新阿里三面面经

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

这些都是基本的命令,在实际项目中会根据不同的配置,会对这些task 设置不同的依赖。比如 默认的 assmeble 会依赖 assembleDebug 和assembleRelease,如果直接执行assmeble,最后会编译debug,和release 的所有版本出来。如果我们只需要编译debug 版本,我们可以运行assembleDebug。

除此之外还有一些常用的新增的其他命令,比如 install命令,会将编译后的apk 安装到连接的设备。

lint 检测


  • 忽略编译器的 lint 检查

android { lintOptions { abortOnError false } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

buildTypes 定义了编译类型


android{ buildTypes { release { minifyEnabled true //打开混淆 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { minifyEnabled false //关闭混淆 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

productFlavors 多渠道打包


AndroidManifest.xml 里设置动态渠道变量

<meta-data android:name="UMENG_CHANNEL" android:value="${UMENG_CHANNEL_VALUE}" />

  • 1

  • 2

  • 3

在 build.gradle 设置 productFlavors , 这里假定我们需要打包的渠道为酷安市场、360、小米、百度、豌豆荚。

android { productFlavors { kuan { manifestPlaceholders = [UMENG_CHANNEL_VALUE: "kuan"] } xiaomi { manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"] } qh360 { manifestPlaceholders = [UMENG_CHANNEL_VALUE: "qh360"] } baidu { manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"] } wandoujia { manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"] } } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

或者批量修改

android { productFlavors { kuan {} xiaomi {} qh360 {} baidu {} wandoujia {} } productFlavors.all { flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name] } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

这样在打包的时候就可以选择渠道了

这里写图片描述

或者用命令打包 ,比如:

gradlew assembleWandoujiaRelease //豌豆荚 release 包 gradlew assembleWandoujiaDebug //豌豆荚 debug 包

  • 1

  • 2

  • 3

  • 4

多渠道设置包名


有时候我们需要分渠道设置 applicationId 、友盟的 appkey 、友盟渠道号。

productFlavors { google { applicationId "com.wifi.cool" manifestPlaceholders = [ UMENG_APPKEY_VALUE : "456789456789", UMENG_CHANNEL_VALUE: "google", ] } baidu{ applicationId 'com.wifi.hacker' manifestPlaceholders = [ UMENG_APPKEY_VALUE : "123456789789", UMENG_CHANNEL_VALUE : "baidu", ] } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

Signing 签名


在 android 标签下添加 signingConfigs 标签,如下:

android { signingConfigs { config { keyAlias 'yiba' keyPassword '123456' storeFile file('C:/work/Key.jks') storePassword '1234567' } } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

可以在 release 和 debug 包中定义签名,如下:

android { signingConfigs { config { keyAlias 'yiba' keyPassword '123456' storeFile file('C:/work/Key.jks') storePassword '1234567' } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.config } debug { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.config } } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

依赖管理


1、依赖 jcenter 包

每个库名称包含三个元素:组名:库名称:版本号

compile 'com.android.support:appcompat-v7:25.0.0'

  • 1

2、依赖本地 module

compile project(':YibaAnalytics')

  • 1

  • 2

3、依赖 jar 包

  • 1、把 jar 包放在 libs 目录下

  • 2、在 build.gradle 中添加依赖

dependencies { compile files('libs/YibaAnalytics5.jar') }

  • 1

  • 2

  • 3

这里写图片描述

4、依赖 aar 包

  • 1、把 aar 包放到 libs 目录下

  • 2、在 build.gradle 中添加依赖

repositories { flatDir { dirs 'libs' } } dependencies { compile(name:'YibaAnalytics-release', ext:'aar') }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

如图所示:

这里写图片描述

5、自定义依赖包目录

当我们的 aar 包需要被多个 module 依赖时,我们就不能把 aar 包放在单一的 module 中,我们可以在项目的根目录创建一个目录,比如叫 aar 目录,然后把我们的 aar 包放进去,如图所示:

这里写图片描述

在项目的根目录的 build.gradle 的 allprojects 标签下的 repositories 添加 :

flatDir { dirs '../aar' }

  • 1

  • 2

  • 3

../aar 表示根目录下的 aar 文件夹。

如图所示:

这里写图片描述

然后就可以添加依赖了,如下所示:

compile(name:'YibaAnalytics-release', ext:'aar')

  • 1

6、依赖配置

有些时候,你可能需要和sdk协调工作。为了能顺利编译你的代码,你需要添加SDK到你的编译环境。你不需要将sdk包含在你的APK中,因为它早已经存在于设备中,所以配置来啦,我们会有5个不同的配置:

  • compile

  • apk

  • provided

  • testCompile

  • androidTestCompile

compile是默认的那个,其含义是包含所有的依赖包,即在APK里,compile的依赖会存在。

apk的意思是apk中存在,但是不会加入编译中,这个貌似用的比较少。

provided的意思是提供编译支持,但是不会写入apk。

7、排除依赖兼容包

有时候我们在引入依赖包的时候,会额外的引入 v7, v4 的包,对我们的项目造成额外的负担,我们需要把这个兼容包排除,可以使用 exclude 就能做到。

compile('com.google.firebase:firebase-ads:11.0.4', { exclude group: 'com.android.support' //排除v7 , v4 包 })

  • 1

  • 2

  • 3

native包(so包)


用c或者c++写的library会被叫做so包,Android插件默认情况下支持native包,你需要把.so文件放在对应的文件夹中:

这里写图片描述

注意

jniLibs 目录应该和 Java 目录在同一级

defaultConfig 详解


defaultConfig 对应的是 ProductFlavor 类。

resConfigs : 过滤语言

如果你的app中仅支持1,2种语言,但是可能引用的lib库包含多种其他语言的strings资源,这个时候我们可以通过resConfig指定我们需要的strings资源。

android { defaultConfig { applicationId "com.yiba.sharewe.lite.activity" minSdkVersion 14 targetSdkVersion 24 versionCode 46 versionName "1.74" resConfigs 'en', 'zh-rCN' ,'es' //本次打包,只把 en(英文)、zh-rCN(中文简体)、es(西班牙语)打进保内,其他语言忽略 } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

resConfigs : 过滤 drawable文件夹的资源

一般情况下,我们打完包,res 下面的资源如图所示:

这里写图片描述

现在加上资源过滤规则:

android { defaultConfig { applicationId "com.wifi.analytics" minSdkVersion 9 targetSdkVersion 25 versionCode 1 versionName "1.0" resConfigs "hdpi" //打包的时候只保留 drawable-xhdpi 文件夹里面的资源 } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

这次我们打包效果如下:

这里写图片描述

buildTypes 详解


官方文档

buildTypes{}对应的是 BuildType 类

继承关系

BuildType 继承 DefaultBuildType ; DefaultBuildType 继承 BaseConfigImpl ;

BaseConfigImpl --- DefaultBuildType --- BuildType

  • 1

  • 2

  • 3

buildTypes的属性:

name:build type的名字 applicationIdSuffix:应用id后缀 versionNameSuffix:版本名称后缀 debuggable:是否生成一个debug的apk minifyEnabled:是否混淆 proguardFiles:混淆文件 signingConfig:签名配置 manifestPlaceholders:清单占位符 shrinkResources:是否去除未利用的资源,默认false,表示不去除。 zipAlignEnable:是否使用zipalign工具压缩。 multiDexEnabled:是否拆成多个Dex multiDexKeepFile:指定文本文件编译进主Dex文件中 multiDexKeepProguard:指定混淆文件编译进主Dex文件中

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

buildType的方法:

1.buildConfigField(type,name,value):添加一个变量生成BuildConfig类。 2.consumeProguardFile(proguardFile):添加一个混淆文件进arr包。 3.consumeProguardFile(proguardFiles):添加混淆文件进arr包。 4.externalNativeBuild(action):配置本地的build选项。 5.initWith:复制这个build类型的所有属性。 6.proguardFile(proguardFile):添加一个新的混淆配置文件。 7.proguradFiles(files):添加新的混淆文件 8.resValue(type,name,value):添加一个新的生成资源 9.setProguardFiles(proguardFileIterable):设置一个混淆配置文件。

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

initWith :复制属性

android { compileSdkVersion 25 buildToolsVersion "25.0.2" defaultConfig { applicationId "com.wifi.analytics" minSdkVersion 9 targetSdkVersion 25 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } myType { initWith debug //完全复制 debug 的所有属性‘ minifyEnabled true //自定义打开混淆 } } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

applicationIdSuffix 、versionNameSuffix :添加后缀

android { compileSdkVersion 25 buildToolsVersion "25.0.2" defaultConfig { applicationId "com.wifi.analytics" minSdkVersion 9 targetSdkVersion 25 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' applicationIdSuffix "zhao" //applicationId 追加后缀名 zhao versionNameSuffix "debug" //versionName 追加后缀名 debug1.0 } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

效果图,如下:

这里写图片描述

buildConfigField: 自定义属性

在 build.gradle 文件中定义 buildConfigField 属性

android { buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' buildConfigField "String", "API_ENV", "\"http://yiba.com\"" //自定义String属性 } debug { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' buildConfigField "String", "API_ENV", "\"http://yiba.com\"" //自定义String属性 } } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

然后点击同步按钮,然后就可以在 build 目录看到 debug 和 release 信息。

debug 环境下的 BuildConfig 如下:

这里写图片描述

release 环境下的 BuildConfig 如下:

这里写图片描述

当然我们也可以在代码中获取自定义的值:

//获取变量值 String API = BuildConfig.API_ENV ;

  • 1

  • 2

  • 3

上面演示了自定义 String 变量,也可以 自定义 int 、boolean

android { buildTypes { debug { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' buildConfigField "String", "API_ENV", "\"http://www.baidu.com\"" //自定义 String 值 buildConfigField "Boolean", "openLog", "true" //自定义 boolean 值 buildConfigField "int", "age", "10" //自定义 int 值 } } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

Gradle 实现差异化构建


情景1

LeakCanary 是 square 公司出品的一个检测内存泄漏的开源库。

GitHub : https://github.com/square/leakcanary

我们一般这样集成

dependencies { compile 'com.squareup.leakcanary:leakcanary-android:1.5.2' }

  • 1

  • 2

  • 3

然后我们在 Application 类中初始化:

public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); LeakCanary.install(this); } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

但是这样集成有一个弊端,就是 debug 和 release 包都会把 LeakCanary 的源码打进去,如果我们在 release 包中不把 LeakCanary 源码打进去,怎么办? 还好 LeakCanary 给我们提供了一个方法,方法如下:

dependencies { //打 debug 包 debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1' //打 release 包 releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1' }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

leakcanary-android-no-op 是一个空壳,里面有2个空类,所以就可以避免把 LeakCanary 源码打进 release 包。但是这种方式有个缺陷,如果一些开源库没有提供 releaseCompile 库,那我们改怎么办了?下面的情景2 就会讲到解决方案。

情景2

Stetho 是 Faceboo k开源的Andorid调试工具。当你的应用集成Stetho时,开发者可以访问Chrome,在Chrome Developer Tools中查看应用布局,网络请求,sqlite,preference 等等。

官网:http://facebook.github.io/stetho/

从官网可以看到 stetho 没有提供 releaseCompile 包 , 情景1 的方案就不能用了。新的思路集成方案如下:

dependencies { debugCompile 'com.facebook.stetho:stetho:1.5.0' }

  • 1

  • 2

  • 3

在 src 目录下创建 debug 目录、release 目录 ,然后分别在 debug 目录 和 release 目录 创建 java 目录 , 在 java 目录中创建包名,比如: com.app , 如下图所示:

这里写图片描述

debug 目录下创建 SDKManage 类 ,如下 :

public class SDKManager { public static void init(Context context) { //初始化 Stetho Stetho.initializeWithDefaults(context); } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

release 目录下创建 SDKManage 类 ,如下 :

public class SDKManager { public static void init(Context context) { //这是一个空方法,目的是不引入 Stetho 源码 } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

在住项目中的 MyApplication 类,并且完成 Stetho 的初始化,如下:

public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); SDKManager.init(this); } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

这样我们便完成了简单的差异化构建, 打出来的 release 包就没有 Stetho 源码。

SourceSet


SourceSet 简介

SourceSet 可以定义项目结构,也可以修改项目结构。Java插件默认实现了两个SourceSet,main 和 test。每个 SourceSet 都提供了一系列的属性,通过这些属性,可以定义该 SourceSet 所包含的源文件。比如,java.srcDirs,resources.srcDirs 。Java 插件中定义的其他任务,就根据 main 和 test 的这两个 SourceSet 的定义来寻找产品代码和测试代码等。

SourceSet 定义源码目录

在 Android 项目中,我们可以在 src/main/java 目录新建 Java 文件,如下图所示:

这里写图片描述

现在我们在 src 目录下,新建 test1 目录 ,发现不能在 test1 目录中新建 Java 文件,如下图所示:

这里写图片描述

为什么在 test1 目录不能新建 Java 文件,因为 Gradle 中 SourceSet 默认定义的源码文件路径是src/main/java , 其他的文件下下面的源码我们自然无法访问。解决这个问题也很简单,我们需要在 SourceSet 中增加一个源码路径即可。如下所示:

android { sourceSets { main { java { srcDir 'src/test1' //指定源码目录 } } } }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

最后

今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。

最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

【算法合集】

【延伸Android必备知识点】

【Android部分高级架构视频学习资源】

**Android精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img
6

  • 7

  • 8

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-wKq4j4WH-1712603451552)]
[外链图片转存中…(img-oywtYvC1-1712603451553)]
[外链图片转存中…(img-GPykU1Qx-1712603451553)]
[外链图片转存中…(img-TXpY2LTd-1712603451553)]
[外链图片转存中…(img-rPX48xUT-1712603451554)]
[外链图片转存中…(img-e7ddoPRq-1712603451554)]
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-kqM9Xh5z-1712603451554)]

最后

今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。

最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

[外链图片转存中…(img-efP2TNuW-1712603451555)]

【算法合集】

[外链图片转存中…(img-MkMZX3Km-1712603451555)]

【延伸Android必备知识点】

[外链图片转存中…(img-cSP6PJk8-1712603451555)]

【Android部分高级架构视频学习资源】

**Android精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-coZCJWKQ-1712603451556)]

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值