Android面试-高端技术题

本系列出于AWeiLoveAndroid的分享,在此感谢,再结合自身经验查漏补缺,完善答案。以成系统。


图片

  • 图片库对比,1280*720的图片占用内存情况
图片占用内存.jpeg
  • ImageLoader原理+源码
  • Picasso基本使用与源码解析

http://www.cnblogs.com/guanmanman/p/6922678.html

  • Glide源码/原理解析(用的什么缓存,如何控制缓存大小)

Glide源码解析一
Glide源码解析二

  • Picasso 与 Glide比较?

https://blog.csdn.net/abrazen_zz/article/details/52562153
Glide ARGB565 Picasso ARGB8888
Glide 之加载ImageView大小的 Picasso 加载整张
Glide asGif Picasso 没有gif功能
Glide 源码 > Picasso
Glide 是纯HttpUrlConnection Picasso 如果有Okhttp会用Okhttp

  • 自己实现图片库思路

接口-加载 显示
加载 内存--本地--网络--本地--内存
显示 显示规则,是否压缩 显示后回收

android 滚动 拖拽

  • 手写ScrollView/ScrollView源码分析

Scroller源码
VelocityTracker分析
ScrollView源码

  • ViewDragHelper

https://www.jianshu.com/p/07d717ef0b28

  • Material design

MD学习资料大全

网络和安全机制

  • 网络框架对比和源码分析
  • 自己去设计网络请求框架,怎么做?

网络引擎+自由切换网络请求框架

  • 从网络加载一个10M的图片,说下注意事项

oom

  • 六大设计原则

http://www.cnblogs.com/dolphin0520/p/3919839.html
单一职责,开闭,理式替换,依赖倒置,接口隔离,迪米特法则

  • 设计模式

https://github.com/jigongdajiang/DesinMode

  • TCP的3次握手和四次挥手

https://blog.csdn.net/qzcsu/article/details/72861891

  • TCP与UDP的区别与应用

https://blog.csdn.net/leewccc/article/details/70225610

  • HTTP协议

https://www.cnblogs.com/ranyonsue/p/5984001.html

报文格式.jpeg

  • HTTP1.0 1. 2.0 Https

https://www.jianshu.com/p/52d86558ca57
1.1 长连接,多站点,断电续传,

  • HTTP与HTTPS的区别以及如何实现安全性
image
  • 如何验证证书的合法性?

https://www.cnblogs.com/alisecurity/p/5939336.html

  • https中哪里用了对称加密,哪里用了非对称加密,对加密算法(如RSA)等是否有了解?

https://www.cnblogs.com/chengdabelief/p/6883569.html

  • client如何确定自己发送的消息被server收到?

  • 谈谈你对WebSocket的理解

是HTML5一种新的协议。它实现了浏览器与服务器全双工通信

  • WebSocket与socket的区别

https://blog.csdn.net/wwd0501/article/details/54582912
Socket其实并不是一个协议,而是为了方便使用TCP或UDP而抽象出来的一层,是位于应用层和传输控制层之间的一组接口。
WebSocket

  • 谈谈你对安卓签名的理解。

  • 请解释安卓为啥要加签名机制?

1.防止恶意替换
2.系统强制要求

  • 视频加密传输

  • App 是如何沙箱化,为什么要这么做?

https://blog.csdn.net/ljheee/article/details/53191397

  • 权限管理系统(底层的权限是如何进行 grant 的)?

https://blog.csdn.net/gan303/article/details/50669035
https://blog.csdn.net/zy00000000001/article/details/51956883
安装应用启动应用会解析apk(parsePackage),这时候会解析清单配置文件中的<uses-permission>标签,解析完后会调用updatePermissionsLPw进行权限设定,然后进行grantPermissionsLPw授权,授权的本质是为应用程序授予权限名对应的组id,拥有组id的应用就拥有了相应的权限。

数据库

  • sqlite升级,增加字段的语句
/**
 * 方法1:检查某表列是否存在
 * @param db
 * @param tableName 表名
 * @param columnName 列名
 * @return
 */
private static boolean checkColumnExist1(SQLiteDatabase db, String tableName
        , String columnName) {
    boolean result = false ;
    Cursor cursor = null ;
    try{
        //查询一行
        cursor = db.rawQuery( "SELECT * FROM " + tableName + " LIMIT 0", null );
        result = cursor != null && cursor.getColumnIndex(columnName) != -1 ;
    }catch (Exception e){
        LogUtil.logErrorMessage("checkColumnExists1..." + e.getMessage());
    }finally{
        if(null != cursor && !cursor.isClosed()){
            cursor.close() ;
        }
    }

    return result ;
}
//如果不存在再执行修改表的语句
alert table ‘tableName’ add ‘clumName’ clumType 
  • 数据库框架对比和源码分析

https://www.jianshu.com/p/8287873d97cd

  • 数据库的优化

https://blog.csdn.net/u014608640/article/details/52511310
索引 事务 单线程池 其它(StringBulider,记录cloumIndex,少字段查询)

  • 数据库数据迁移问题

https://blog.csdn.net/it_talk/article/details/47124645
利用事务的原子特性,保证所有的SQL能全部执行完成。主要思路是:首先将原来的表进行改名称rename table(临时表),接着创建新的表create table,再者将旧表内的数据迁移到新表内,最后drop table删除临时表。

算法

  • 排序算法有哪些?

https://blog.csdn.net/happy_wu/article/details/51841244

  • 最快的排序算法是哪个?

平均时间复杂度是快速排序最快

  • 手写一个冒泡排序
private static void bubleSort(int[] a){
        int n = a.length;
        int j,k;
        int flag = n;//记录最后交换的位置
        while (flag > 0){//排序未结束标志
            k = flag;// 来记录遍历的尾界
            flag = 0;
            for(j=1;j<k;j++){
                if(a[j-1] > a[j]){
                    //交换
                    int temp;
                    temp = a[j -1];
                    a[j-1] = a[j];
                    a[j] = temp;
                    flag = j;
                }
            }
        }
    }
  • 手写快速排序代码
//算出中轴
    private static int partition(int[] num,int left,int right){
        if(num==null || num.length<=0 || left<0 || right>=num.length){
            return 0;
        }
        int prio=num[left];   //获取数组中间元素的下标
        while (left<right){                 //从两端交替向中间扫描
            //从右往左扫
            while (left<right && num[right]>=prio)
                right--;
            swap(num,left,right);
            //从左往右扫
            while (left<right && num[left]<=prio)
                left++;
            swap(num,left,right);
        }
        return left;
    }
    //交换
    private static void swap(int[] num,int left,int right){
        int temp = num[left];
        num[left] = num[right];
        num[right] = temp;
    }
    //快速排序
    private static void  sort(int num[],int left,int right){
        if (left<right){
            int index=partition(num,left,right); //算出枢轴值
            sort(num,left,index-1);       //对低子表递归排序
            sort(num,index+1,right);        //对高子表递归排序
        }
    }
  • 快速排序的过程、时间复杂度、空间复杂度

http://my.csdn.net/uploads/201207/19/1342700879_2982.jpg

  • 二分查找

https://blog.csdn.net/u014430697/article/details/49968495

  • 手写堆排序

  • 堆排序过程、时间复杂度及空间复杂度

  • 写出你所知道的排序算法及时空复杂度,稳定性

  • 二叉树给出根节点和目标节点,找出从根节点到目标节点的路径

  • 给阿里2万多名员工按年龄排序应该选择哪个算法?

  • GC算法(各种算法的优缺点以及应用场景)

  • 蚁群算法与蒙特卡洛算法

  • 子串包含问题(KMP 算法)写代码实现

  • 一个无序,不重复数组,输出N个元素,使得N个元素的和相加为M,给出时间复杂度、空间复杂度。手写算法

  • 万亿级别的两个URL文件A和B,如何求出A和B的差集C(提示:Bit映射->hash分组->多文件读写效率->磁盘寻址以及应用层面对寻址的优化)

  • 百度POI中如何试下查找最近的商家功能(提示:坐标镜像+R树)。

  • 两个不重复的数组集合中,求共同的元素。

  • 两个不重复的数组集合中,这两个集合都是海量数据,内存中放不下,怎么求共同的元素?

  • 一个文件中有100万个整数,由空格分开,在程序中判断用户输入的整数是否在此文件中。说出最优的方法

  • 一张Bitmap所占内存以及内存占用的计算

  • 2000万个整数,找出第五十大的数字?

  • 烧一根不均匀的绳,从头烧到尾总共需要1个小时。现在有若干条材质相同的绳子,问如何用烧绳的方法来计时一个小时十五分钟呢?

  • 求1000以内的水仙花数以及40亿以内的水仙花数

  • 5枚硬币,2正3反如何划分为两堆然后通过翻转让两堆中正面向上的硬8币和反面向上的硬币个数相同

  • 时针走一圈,时针分针重合几次

  • N*N的方格纸,里面有多少个正方形

  • x个苹果,一天只能吃一个、两个、或者三个,问多少天可以吃完?

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

  • 对插件化的理解

https://blog.csdn.net/jiangwei0910410003/article/details/48104581

  1. 在android的Dalivk的definClass方法被阉割
  2. DexClassLoader 和 PathClassLoader都是双亲委派模型的本质是没有重写loadclass方法,里面有这么一行
    clazz = parent.loadClass(className, false);
    
  3. 动态加载的本质是使用DexClassLoader和PathClassLoader的loadClass方法进行加载。两者的区别是构造函数所体现的,DexCLassLoader能将源路径文件(可能是apk,jar,zip)进行解压得到dex文件,然后进行进行加载,而PathClassLoader只能直接通过dex文件进行加载,在android中默认的是PathClassLoader,因为apk在安装后会自动解压出我们要用的dex文件存放在/data/dalvik-cache中。
  4. 插件化一般由三个工程 插件接口工程,插件工程和宿主工程。这三的关系如下图


    image

    这里要注意一点就是宿主工程通过libs的方式集成接口工程,而插件工程一定不能通过libs的方式集成接口工程

  5. 资源的动态加载,关键是反射操控AssetManager的addAssetPath将资源的路径改为插件的,然后用这个AssetManager对象去创建自己的Resources对象,我们代码中就是用这个自己的Resources对象去加载资源。
  6. Activity的动态加载,一个重要的问题是保证能正常走生命周期,主要有三种种思路
    a. 通过反射得到ActivityThread中的mPackages,然后通过mPackages得到应用的LoadApk对象,然后将LoadApk对象中的mClassLoader对象替换成我们自己定义的关联了系统PathClassLoader的且加载了插件的DexClassLoader对象。但是这种方式必须要预先在清单配置文件中生命好要加载的插件中的Activity。
    b. 通过反射去将DexClassLoader中的class合并到应用PathClassLoader中的elements数组中
    b. 静态代理的方式,应用中提供一个ProxActivity,插件工程中提供一个只有生命周期壳子的Activity,这个Activity持有一个我们的代理Activity,在代理Activity通过反射去获取插件工程的Activity,然后将此代理给插件Activity,并在代理的各个方法中取调用插件的Activity的方法。
  • 热修复

https://www.jianshu.com/p/e61a4d10e122
《深入探索Android热修复技术原理7.3Q.pdf》
主要分两种级别,一种是方法修复,代表Andfix,原理是改变虚拟机中方法的索引指向。一种是类级别修复,利用的是类的动态加载中改变应用BootClassLoader中的elements数组,代表是Tinker

  • Sophix 修复方法
    本质是native层整体替换ArtMethod。这个方法的局限是修改不能有方法和字段的增减,以及不能修复反射调用的非静态方法。局限场景如下
    1. 外部类访问内部类的private,或者内部类访问外部类的private,本质是编译时会为private增加一个access**方法。导致方法数增加,解决方法,就是有内部类是双方不使用private修饰属性和方法
    2. 匿名内部类的前插入和删除。原因是匿名内部类编译会按顺序生成一个带有外部类名和序号的名字。
    3. 不支持<clinit>修复,注意 final static 的 基本类型和 String不会被收集到<clinit>方法中
    4. 混淆导致的方法内联(没用的,简单的,只有一个地方用的会被内联)和裁剪(声明了参数,但是没有用该参数会被裁剪)。会影响最终的方法数。解决方案是在配置混淆文件是加上-dontoptimize参数
    5. switch case 连续为packed_switch 不连续 spare_switch ,资源id为packed_switch 这样会导致不完全,所以解决方案就是反编译将packed_switch指令改为spare_switch指令。
    6. 泛型的桥接(重写泛型父类方法时编译器自动生成的一个桥接方法,以此来解决泛型的类型擦除而导致与多态冲突的问题)会导致方法数增加
    7. Lambda 会引起方法数的增加和减少,原因是Lambda会将函数式接口编译成一个静态内部方法,同时还会生成一个新的辅助类
  • Sophix冷启动修复方案:
    davlik虚拟机全量Dex方法(去掉原来变动的class,这里不是真删而是移除定义的入口)
    art虚拟机 补丁为classes.dex 改原来的为classes1.dex...
  • Sophix资源修复方案:
    增加一个packageId为0x66的纯补丁资源包,配合代码层id的引用实现资源的修复。在AssetManager上则是通过析构,重新初始化,重新增加path的方式保证不用到处替换原有的AssetManager
  • Sophix的so库修复方案


    so修复方案.jpeg
  • Thinker的原理与源码

https://www.cnblogs.com/yyangblog/p/6249715.html

  • Android中dex文件的加载与优化流程

https://blog.csdn.net/jsqfengbao/article/details/52103439

  • 模块化实现(好处,原因)

https://www.cnblogs.com/baronzhang/p/6861258.html

  • 项目组件化的理解

https://blog.csdn.net/guiying712/article/details/55213884

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

https://blog.csdn.net/zheng548/article/details/54864765

build.jpeg

image

架构设计和设计模式

  • 谈谈你对Android设计模式的理解

https://segmentfault.com/p/1210000008721369/read

  • 六大设计原则
    1. 一个类只负责一个职责-单一职责
    2. 基类引用可以透明的换为子类对象-理式替换
    3. 抽象不依赖细节,细节依赖抽象-依赖倒置
    4. 客户端不应该依赖其不需要的接口-接口隔离
    5. 最少知道-迪米特法则
    6. 对扩展开发,对修改关闭-开闭原则
  • MVC MVP MVVM原理和区别
框架模式.jpeg
  • 手写生产者/消费者模式

https://www.cnblogs.com/chentingk/p/6497107.html

    //核心属性定义
    private volatile boolean isRunning = true;
    private BlockingQueue<PCData> queue;// 内存缓冲区
    private static AtomicInteger count = new AtomicInteger();// 总数 原子操作
  • 写出观察者模式的代码

https://blog.csdn.net/u012401711/article/details/52475327

  • 适配器模式,装饰者模式,外观模式的异同?

https://blog.csdn.net/zhang31jian/article/details/50538000

  • 用到的一些开源框架,介绍一个看过源码的,内部实现过程。

  • 谈谈对RxJava的理解

https://blog.csdn.net/zxt0601/article/details/61614799

  • RxJava的功能与原理实现

  • RxJava的作用,与平时使用的异步操作来比的优缺点

  • 说说EventBus作用,实现方式,代替EventBus的方式

  • 从0设计一款App整体架构,如何去做?

  • 说一款你认为当前比较火的应用并设计(比如:直播APP,P2P金融,小视频等)

  • 谈谈对java状态机理解

  • Fragment如果在Adapter中使用应该如何解耦?

  • Binder机制及底层实现

  • 对于应用更新这块是如何做的?(解答:灰度,强制更新,分区域更新)?

  • 实现一个Json解析器(可以通过正则提高速度)

  • 统计启动时长,标准

https://blog.csdn.net/beyond_liyy/article/details/52273740

  • 本地
    abd shell am start -W com.gjg/com.gjg.SplashActivity
    totaltime 进程 和 Activity的时间 不包含pause时间
  • 线上
    Application attachBaseContext 起点 Activity的onWindowFocusChanged终点
  • 谈谈对Kotlin的理解

性能优化

  • 如何对Android 应用进行性能分析以及优化?

https://www.cnblogs.com/tester-l/p/6045524.html

  • ddms 和 traceView

https://blog.csdn.net/u011240877/article/details/54347396

  • 性能优化如何分析systrace?

  • 用IDE如何分析内存泄漏?

  • Java多线程引发的性能问题,怎么解决?

  • 启动页白屏及黑屏解决,启动太慢怎么解决,怎么保证应用启动不卡顿?

https://juejin.im/post/5874bff0128fe1006b443fa0

  • App启动崩溃异常捕捉

UncaughtExceptionHandler

  • 自定义View注意事项

  • 现在下载速度很慢,试从网络协议的角度分析原因,并优化(提示:网络的5层都可以涉及)。

  • Https请求慢的解决办法(提示:DNS,携带数据,直接访问IP)

  • 如何保持应用的稳定性

  • RecyclerView和ListView的性能对比

  • ListView的优化

  • RecycleView优化

  • View渲染

  • Bitmap如何处理大图,如一张30M的大图,如何预防OOM

  • java中的四种引用的区别以及使用场景

  • 强引用置为null,会不会被回收?

NDK、jni、Binder、AIDL、进程通信有关

  • 请介绍一下NDK

  • 什么是NDK库?

  • jni用过吗?

  • 如何在jni中注册native函数,有几种注册方式?

  • Java如何调用c、c++语言?

  • jni如何调用java层代码?

  • 进程间通信的方式?

  • Binder机制

  • 简述IPC?

  • 什么是AIDL?

  • AIDL解决了什么问题?

  • AIDL如何使用?

  • Android 上的 Inter-Process-Communication 跨进程通信时如何工作的?

  • 多进程场景遇见过么?

  • Android进程分类?

  • 进程和 Application 的生命周期?

  • 进程调度

  • 谈谈对进程共享和线程安全的认识

  • 谈谈对多进程开发的理解以及多进程应用场景

  • 什么是协程?

framework层、ROM定制、Ubuntu、Linux之类的问题

  • java虚拟机的特性

  • 谈谈对jvm的理解

  • JVM内存区域,开线程影响哪块内存

  • 对Dalvik、ART虚拟机有什么了解?

  • Art和Dalvik对比

  • 虚拟机原理,如何自己设计一个虚拟机(内存管理,类加载,双亲委派)

  • 谈谈你对双亲委派模型理解

  • JVM内存模型,内存区域

  • 类加载机制

  • 谈谈对ClassLoader(类加载器)的理解

  • 谈谈对动态加载(OSGI)的理解

  • 内存对象的循环引用及避免

  • 内存回收机制、GC回收策略、GC原理时机以及GC对象

  • 垃圾回收机制与调用System.gc()区别

  • Ubuntu编译安卓系统

  • 系统启动流程是什么?(提示:Zygote进程 –> SystemServer进程 –> 各种系统服务 –> 应用进程)

  • 大体说清一个应用程序安装到手机上时发生了什么

  • 简述Activity启动全部过程

  • App启动流程,从点击桌面开始

  • 逻辑地址与物理地址,为什么使用逻辑地址?

  • Android为每个应用程序分配的内存大小是多少?

  • Android中进程内存的分配,能不能自己分配定额内存?

  • 进程保活的方式

  • 如何保证一个后台服务不被杀死?(相同问题:如何保证service在后台不被kill?)比较省电的方式是什么?

  • App中唤醒其他进程的实现方式

推荐阅读更多精彩内容