2024年Android最新2024年尾 Android 面试之必问高级知识点(包含答案),2024年最新2024-2024历年阿里Android面试真题

面试复习笔记:

这份资料我从春招开始,就会将各博客、论坛。网站上等优质的Android开发中高级面试题收集起来,然后全网寻找最优的解答方案。每一道面试题都是百分百的大厂面经真题+最优解答。包知识脉络 + 诸多细节。
节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

《960页Android开发笔记》

《1307页Android开发面试宝典》

包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。

《507页Android开发相关源码解析》

只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

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

[成员]

}

我收录了更多Android开发面试题,可在这里获得,开源利好:


Android学习文档以及教学视频

4.3 混淆模版


ProGuard中有些公共的模版是可以复用的,比如压缩比、大小写混合和一些系统提供的Activity、Service不能混淆等。

代码混淆压缩比,在 0~7 之间,默认为 5,一般不做修改

-optimizationpasses 5

混合时不使用大小写混合,混合后的类名为小写

-dontusemixedcaseclassnames

指定不去忽略非公共库的类

-dontskipnonpubliclibraryclasses

这句话能够使我们的项目混淆后产生映射文件

包含有类名->混淆后类名的映射关系

-verbose

指定不去忽略非公共库的类成员

-dontskipnonpubliclibraryclassmembers

不做预校验,preverify 是 proguard 的四个步骤之一,Android 不需要 preverify,去掉这一步能够加快混淆速度。

-dontpreverify

保留 Annotation 不混淆

-keepattributes Annotation,InnerClasses

避免混淆泛型

-keepattributes Signature

抛出异常时保留代码行号

-keepattributes SourceFile,LineNumberTable

指定混淆是采用的算法,后面的参数是一个过滤器

这个过滤器是谷歌推荐的算法,一般不做更改

-optimizations !code/simplification/cast,!field/,!class/merging/

#############################################

Android开发中一些需要保留的公共部分

#############################################

保留我们使用的四大组件,自定义的 Application 等等这些类不被混淆

因为这些子类都有可能被外部调用

-keep public class * extends android.app.Activity

-keep public class * extends android.app.Appliction

-keep public class * extends android.app.Service

-keep public class * extends android.content.BroadcastReceiver

-keep public class * extends android.content.ContentProvider

-keep public class * extends android.app.backup.BackupAgentHelper

-keep public class * extends android.preference.Preference

-keep public class * extends android.view.View

-keep public class com.android.vending.licensing.ILicensingService

保留 support 下的所有类及其内部类

-keep class android.support.** { *; }

保留继承的

-keep public class * extends android.support.v4.**

-keep public class * extends android.support.v7.**

-keep public class * extends android.support.annotation.**

保留 R 下面的资源

-keep class *.R$ { *; }

保留本地 native 方法不被混淆

-keepclasseswithmembernames class * {

native ;

}

保留在 Activity 中的方法参数是view的方法,

这样以来我们在 layout 中写的 onClick 就不会被影响

-keepclassmembers class * extends android.app.Activity {

public void *(android.view.View);

}

保留枚举类不被混淆

-keepclassmembers enum * {

public static **[] values();

public static ** valueOf(java.lang.String);

}

保留我们自定义控件(继承自 View)不被混淆

-keep public class * extends android.view.View {

*** get*();

void set*(***);

public (android.content.Context);

public (android.content.Context, android.util.AttributeSet);

public (android.content.Context, android.util.AttributeSet, int);

}

保留 Parcelable 序列化类不被混淆

-keep class * implements android.os.Parcelable {

public static final android.os.Parcelable$Creator *;

}

保留 Serializable 序列化的类不被混淆

-keepnames class * implements java.io.Serializable

-keepclassmembers class * implements java.io.Serializable {

static final long serialVersionUID;

private static final java.io.ObjectStreamField[] serialPersistentFields;

!static !transient ;

!private ;

!private ;

private void writeObject(java.io.ObjectOutputStream);

private void readObject(java.io.ObjectInputStream);

java.lang.Object writeReplace();

java.lang.Object readResolve();

}

对于带有回调函数的 onXXEvent、**On*Listener 的,不能被混淆

-keepclassmembers class * {

void (**OnEvent);

void (**OnListener);

}

webView 处理,项目中没有使用到 webView 忽略即可

-keepclassmembers class fqcn.of.javascript.interface.for.webview {

public *;

}

-keepclassmembers class * extends android.webkit.webViewClient {

public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);

public boolean *(android.webkit.WebView, java.lang.String);

}

-keepclassmembers class * extends android.webkit.webViewClient {

public void *(android.webkit.webView, java.lang.String);

}

js

-keepattributes JavascriptInterface

-keep class android.webkit.JavascriptInterface { *; }

-keepclassmembers class * {

@android.webkit.JavascriptInterface ;

}

@Keep

-keep,allowobfuscation @interface android.support.annotation.Keep

-keep @android.support.annotation.Keep class *

-keepclassmembers class * {

@android.support.annotation.Keep *;

}

如果是aar这种插件,可以在aar的build.gralde中添加如下混淆配置。

android {

···

defaultConfig {

···

consumerProguardFile ‘proguard-rules.pro’

}

···

}

5,NDK


如果要问Android的高级开发知识,那么NDK肯定是必问的。那么什么的NDK,NDK 全称是 Native Development Kit,是一组可以让开发者在 Android 应用中使用C/C++ 的工具。通常,NDK可以用在如下的场景中:

  • 从设备获取更好的性能以用于计算密集型应用,例如游戏或物理模拟。

  • 重复使用自己或其他开发者的 C/C++ 库,便利于跨平台。

  • NDK 集成了譬如 OpenSL、Vulkan 等 API 规范的特定实现,以实现在 Java 层无法做到的功能,如音视频开发、渲染。

  • 增加反编译难度。

5.1, JNI基础


JNI即java native interface,是Java和Native代码进行交互的接口。

5.1.1 JNI 访问 Java 对象方法

假如,有如下一个Java类,代码如下。

package com.xzh.jni;

public class MyJob {

public static String JOB_STRING = “my_job”;

private int jobId;

public MyJob(int jobId) {

this.jobId = jobId;

}

public int getJobId() {

return jobId;

}

}

然后,在cpp目录下,新建native_lib.cpp,添加对应的native实现。

#include <jni.h>

extern “C”

JNIEXPORT jint JNICALL

Java_com_xzh_jni_MainActivity_getJobId(JNIEnv *env, jobject thiz, jobject job) {

// 根据实例获取 class 对象

jclass jobClz = env->GetObjectClass(job);

// 根据类名获取 class 对象

jclass jobClz = env->FindClass(“com/xzh/jni/MyJob”);

// 获取属性 id

jfieldID fieldId = env->GetFieldID(jobClz, “jobId”, “I”);

// 获取静态属性 id

jfieldID sFieldId = env->GetStaticFieldID(jobClz, “JOB_STRING”, “Ljava/lang/String;”);

// 获取方法 id

jmethodID methodId = env->GetMethodID(jobClz, “getJobId”, “()I”);

// 获取构造方法 id

jmethodID initMethodId = env->GetMethodID(jobClz, “”, “(I)V”);

// 根据对象属性 id 获取该属性值

jint id = env->GetIntField(job, fieldId);

// 根据对象方法 id 调用该方法

jint id = env->CallIntMethod(job, methodId);

// 创建新的对象

jobject newJob = env->NewObject(jobClz, initMethodId, 10);

return id;

}

5.2 NDK开发


5.2.1 基本流程

首先,在 Java代码中声明 Native 方法,如下所示。

public class MainActivity extends AppCompatActivity {

// Used to load the ‘native-lib’ library on application startup.

static {

System.loadLibrary(“native-lib”);

}

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

Log.d(“MainActivity”, stringFromJNI());

}

private native String stringFromJNI();

}

然后,新建一个 cpp 目录,并且新建一个名为native-lib.cpp的cpp 文件,实现相关方法。

#include <jni.h>

extern “C” JNIEXPORT jstring JNICALL

Java_com_xzh_jni_MainActivity_stringFromJNI(

JNIEnv *env,

jobject /* this */) {

std::string hello = “Hello from C++”;

return env->NewStringUTF(hello.c_str());

}

cpp文件遵循如下的规则:

  • 函数名的格式遵循遵循如下规则:Java_包名_类名_方法名。

  • extern “C” 指定采用 C 语言的命名风格来编译,否则由于 C 与 C++ 风格不同,导致链接时无法找到具体的函数

  • JNIEnv*:表示一个指向 JNI 环境的指针,可以通过他来访问 JNI 提供的接口方法

  • jobject:表示 java 对象中的 this

  • JNIEXPORT 和 JNICALL:JNI 所定义的宏,可以在 jni.h 头文件中查找到

System.loadLibrary()的代码位于java/lang/System.java文件中,源码如下:

@CallerSensitive

public static void load(String filename) {

Runtime.getRuntime().load0(Reflection.getCallerClass(), filename);

}

5.3 CMake 构建 NDK


CMake 是一个开源的跨平台工具系列,旨在构建、测试和打包软件,从 Android Studio 2.2 开始,Android Sudio 默认地使用 CMake 与 Gradle 搭配使用来构建原生库。具体来说,我们可以使用 Gradle 将 C \ C++ 代码 编译到原生库中,然后将这些代码打包到我们的应用中, Java 代码随后可以通过 Java 原生接口 ( JNI ) 调用 我们原生库中的函数。

使用CMake开发NDK项目需要下载如下一些套件:

  • Android 原生开发工具包 (NDK):这套工具集允许我们 开发 Android 使用 C 和 C++ 代码,并提供众多平台库,让我们可以管理原生 Activity 和访问物理设备组件,例如传感器和触摸输入。

  • CMake:一款外部构建工具,可与 Gradle 搭配使用来构建原生库。如果你只计划使用 ndk-build,则不需要此组件。

  • LLDB:一种调试程序,Android Studio 使用它来调试原生代码。

我们可以打开Android Studio,依次选择 【Tools】 > 【Android】> 【SDK Manager】> 【SDK Tools】选中LLDB、CMake 和 NDK即可。

启用CMake还需要在 app/build.gradle 中添加如下代码。

android {

···

defaultConfig {

···

externalNativeBuild {

cmake {

cppFlags “”

}

}

ndk {

abiFilters ‘arm64-v8a’, ‘armeabi-v7a’

}

}

···

externalNativeBuild {

cmake {

path “CMakeLists.txt”

}

}

}

然后,在对应目录新建一个 CMakeLists.txt 文件,添加代码。

定义了所需 CMake 的最低版本

cmake_minimum_required(VERSION 3.4.1)

add_library() 命令用来添加库

native-lib 对应着生成的库的名字

SHARED 代表为分享库

src/main/cpp/native-lib.cpp 则是指明了源文件的路径。

add_library( # Sets the name of the library.

native-lib

Sets the library as a shared library.

SHARED

Provides a relative path to your source file(s).

src/main/cpp/native-lib.cpp)

find_library 命令添加到 CMake 构建脚本中以定位 NDK 库,并将其路径存储为一个变量。

可以使用此变量在构建脚本的其他部分引用 NDK 库

find_library( # Sets the name of the path variable.

log-lib

Specifies the name of the NDK library that

you want CMake to locate.

log)

预构建的 NDK 库已经存在于 Android 平台上,因此,无需再构建或将其打包到 APK 中。

由于 NDK 库已经是 CMake 搜索路径的一部分,只需要向 CMake 提供希望使用的库的名称,并将其关联到自己的原生库中

要将预构建库关联到自己的原生库

target_link_libraries( # Specifies the target library.

native-lib

Links the target library to the log library

included in the NDK.

${log-lib})

···

6,动态加载


6.1 基本概念


动态加载技术在Web中很常见,对于Android项目来说,动态加载的目的是让用户不用重新安装APK就能升级应用的功能,主要的应用场景是插件化和热修复。

首先需要明确的一点,插件化和热修复不是同一个概念,虽然站在技术实现的角度来说,他们都是从系统加载器的角度出发,无论是采用hook方式,亦或是代理方式或者是其他底层实现,都是通过“欺骗”Android 系统的方式来让宿主正常的加载和运行插件(补丁)中的内容;但是二者的出发点是不同的。

插件化,本质上是把需要实现的模块或功能当做一个独立的功能提取出来,减少宿主的规模,当需要使用到相应的功能时再去加载相应的模块。而热修复则往往是从修复bug的角度出发,强调的是在不需要二次安装应用的前提下修复已知的bug。

为了方便说明,我们先理清几个概念:

  • 宿主: 当前运行的APP。

  • 插件: 相对于插件化技术来说,就是要加载运行的apk类文件。

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

下图展示了Android动态化开发框架的整体的架构。

6.2 插件化


关于插件化技术,最早可以追溯到2012年的 AndroidDynamicLoader ,其原理是动态加载不同的Fragment实现UI替换,不过随着15,16年更好的方案,这个方案渐渐的被淘汰了。后面的方案大多基于Hook和动态代理两个方向进行。

目前,插件化的开发并没有一个官方的插件化方案,它是国内提出的一种技术实现,利用虚拟机的类的加载机制实现的一种技术手段,往往需要hook一些系统api,而Google从Android9.0开始限制对系统私有api的使用,也就造成了插件化的兼容性问题,现在几个流行的插件化技术框架,都是大厂根据自己的需求,开源出来的,如滴滴的VirtualAPK,360的RePlugin等,大家可以根据需要自行了解技术的实现原理。

6.3 热修复


6.3.1 热修复原理

说到热修复的原理,就不得不提到类的加载机制,和常规的JVM类似,在Android中类的加载也是通过ClassLoader来完成,具体来说就是PathClassLoader 和 DexClassLoader 这两个Android专用的类加载器,这两个类的区别如下。

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

  • DexClassLoader:可以加载任意目录下的dex/jar/apk/zip文件,也就是我们一开始提到的补丁。

这两个类都是继承自BaseDexClassLoader,BaseDexClassLoader的构造函数如下。

public BaseDexClassLoader(String dexPath, File optimizedDirectory,

String libraryPath, ClassLoader parent) {

super(parent);

this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);

}

最后

我的面试经验分享可能不会去罗列太多的具体题目,因为我依然认为面试经验中最宝贵的不是那一个个具体的题目或者具体的答案,而是结束面试时,那一刻你的感受以及多天之后你的回味~

很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习,对此我整理了一些资料,需要的可以免费分享给大家

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

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

【算法合集】

【延伸Android必备知识点】

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

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

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

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

这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习,对此我整理了一些资料,需要的可以免费分享给大家**

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

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

[外链图片转存中…(img-BUkxbo3a-1714889790590)]

【算法合集】

[外链图片转存中…(img-y6WCQRF9-1714889790591)]

【延伸Android必备知识点】

[外链图片转存中…(img-7etDllpz-1714889790591)]

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

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

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

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

  • 10
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值