Android 面试技术点总结

作者: 肖丹晨 | 来源:发表于2017-10-23 19:35 被阅读264次

    前言
    本文是作者年初换工作是总结的一些面试知识点,从电脑的犄角旮旯找出来,给大家参考一下吧。
    感兴趣的朋友欢迎加入学习小组QQ群: 193765960

    版权归作者所有,如有转发,请注明文章出处:http://www.jianshu.com/u/d43d948bef39

    工具篇

    eclipse使用

    • MAT内存分析工具:防止内存泄漏,内存抖动等
    • LeakCanery

    Android Studio使用

    JAVA篇

    排序算法

    排序算法性能对比.png

    冒泡排序

    依次比较相邻两个元素的大小,符合比对条件则交换位置。

    public class SortUtil {
    
        /**
         * 冒泡排序:依次对比相邻的两个元素,大的话就交换位置;
         * @param source
         */
        public static void bubbleSort(int[] source){
            int tmp = 0;
            int len = source.length;
            if(len == 0){
                return;
            }
    
            for(int i=0; i<len-1; i++){
                for(int j=0; j<len-1-i; j++){
                    if(source[j]>source[j+1]){
                        tmp = source[j+1];
                        source[j+1] = source[j];
                        source[j] = tmp;
                        tmp = 0;
                    }
                }
            }
        }
    }
    

    快速排序

    以某个元素值作为分界基准值(一般选第一个元素),对数组元素从两侧进行收缩比对,大于基准值的元素在基准值元素的右侧,小于基准值元素的元素在左侧,通过递归的调用,对每次基准值排序后的左右两侧元素数组做同样的排序。

    public class SortUtil {
        /**
         * 快速排序
         * @param source
         */
        public static void quickSort(int[] source){
            if(source.length ==0){
                return;
            }
    
            quickSort(source,0,source.length-1);
        }
    
        /**
         * 快速排序:对数组根据第一个元素进行分治;
         * @param source
         */
        private static void quickSort(int[] source,int low, int high){
            if(source.length == 0){
                return;
            }
            if(low < high){
                int mid = getMiddle(source,low,high);
                quickSort(source,low,mid -1);
                quickSort(source,mid+1,high);
            }
        }
    
        /**
         * 获取source[low]的排序位置,并基于source[low]为分界值做划分
         * @param source
         * @param low
         * @param high
         * @return 基准值在数组中的排序位置
         */
        private static int getMiddle(int[] source,int low, int high){
            if(source.length == 0){
                throw new RuntimeException("length of source is 0");
            }
            //设置基准值为比较区间的第一个元素值
            int tmp = source[low];
    
            //当待排序的数组没有完全收拢时,说明排序没有完成
            while (low<high){
                //从高位向低位轮训找到第一个低于参考值的元素
                while (low<high && source[high]>=tmp){
                    high--;
                }
                //高位元素置换到低位
                source[low] = source[high];
    
                //从低位向高位轮询,找到第一个比参考值大的元素
                while (low<high && source[low]<=tmp){
                    low++;
                }
                //高位元素置换到低位
                source[high] = source[low];
            }
    
            source[low] = tmp;
            return low;
        }
    }
    

    归并排序

    对待排序的数组分为两部分,两部分均为已排序数组;对两个数组进行合并使其成为一个一个排序数组。
    归并排序的思想就是,迭代的进行拆分(拆分到数组只有一个元素)合并

    public class SortUtil {
    
        public static void mergeSort(int[] source){
            if(source.length == 0){
                throw new RuntimeException("empty array");
            }
    
            int[] tmp = new int[source.length];
            merge(source,0,source.length-1,tmp);
            tmp = null;
        }
    
        private static void merge(int[] source ,int first, int last, int[] tmp){
    
            if(first <last){
                int mid = (first+last)/2;
                merge(source,first,mid,tmp);//左边有序
                merge(source,mid+1,last,tmp);//右边有序
                merge(source,first,mid,last,tmp);//合并
            }
        }
    
        private static void merge(int[] source ,int first, int mid, int last, int[] tmp){
            int i = first, j = mid + 1;
            int m = mid,   n = last;
            int k = 0;
    
            //将两个有序数组合并为一个有序数组
            while (i <= m && j <= n){
                if (source[i] <= source[j]){
                    tmp[k++] = source[i++];
                }else{
                    tmp[k++] = source[j++];
                }
            }
    
            //如果左侧数组还剩有元素,则追加到合并数组最后
            while (i <= m){
                tmp[k++] = source[i++];
            }
    
            //如果右侧数组还有剩余元素,则追加到合并数组最后
            while (j <= n){
                tmp[k++] = source[j++];
            }
    
            //复写原数组相应的位置
            for (i = 0; i < k; i++){
                source[first + i] = tmp[i];
            }
        }
    }
    

    基础篇

    1. 面向对象的特性

    * 继承

    1)子承父业
    2)final的方法不可重载
    3)final的类不可继承
    

    * 封装

    1)类的设计:高度相关的数据和方法才可以封装在一个类里
    2)隐藏细节,暴露接口:更改细节对接口没有影响
    

    * 抽象(父类)

    1)虚基类
    2)接口类
    3)抽出公共的属性和方法
    

    * 多态(子类)

    1)向上转型
    2)依赖倒置
    

    2. 面向对象设计的六大原则(SOLID_L)

    Android 设计模式:(一)面向对象的六大原则

    • 单一职责原则(类的设计原则)
      类应该是一组“高度相关”的数据和操作的集合(高内聚)

    • 开闭原则(如何保证版本修改和迭代的安全性)
      对扩展是开放的,对修改是关闭的(新的需求和业务要通过接口和代码的新建实现,不允许修改老的接口和代码)

    • 里氏替换原则(如何实现灵活的系统架构)
      利用接口编程的思想,构建扩展灵活的系统架构

    • 依赖倒置原则(面向接口编程)
      模块间的依赖通过抽象实现,具体的实现类之间不能够相互的依赖。

    • 接口隔离原则(接口的设计原则)
      接口的功能尽量内聚和单一,以便可以灵活的复用接口,减少无用的方法暴露

    • 迪米特原则(最少知识原则)
      低耦合,一个类应该尽量只与自己有直接密切关系的类发生关系。

    3. Android系统的框架

    4. Android系统的启动流程

    5. 进程和线程

    * 进程种类
        * 前台进程
        * 可见进程
        * 服务进程
        * 后台进程
        * 空进程
    

    6. 进程间通信

    http://www.10tiao.com/html/227/201703/2650239000/1.html

    • Intent 单向
    • AIDL: 高并发量的通信
    • android.os.Messenger: 串行,简单的通信还可以,不适合大数据量并发
    • Socket

    7. 线程间通信

    需要明确的价格概念:UI线程,工作线程(普通线程),looper线程
    1)handler和message
    2)共享内存
    3)异步任务
    4)Rxjava

    8. Android的四大组件

    1)均工作于主线程,所以都不能执行耗时工作,否则容易ANR
    2)均需要在manifest文件中声明

    9. Android的启动模式

    10. activity加载过程

    11. activity和fragment的生命周期

    * 生命周期
    * activity的状态保存机制
    

    12. MVC

    13. MVP

    14. service

    * 生命周期
    * 启动模式
    * service杀不死的实现方式
    * service 和 Intentservice
        service既不是独立的进程,也不是独立的线程,而是依托于app主线程的组件,因此service不能够执行耗时的工作,否则会引起ANR.
        intentservice是为了执行耗时操作而来的,他继承与service,但是在oncreate的时候会开启子线程来执行耗时操作。
        intentservice有一个虚方法onHandlerIntent(Intent intent),这个方法需要子类去实现;
        intentservice在oncreat中开启线程HandlerThread,并使用HandlerThread的looper初始化一个serviceHandler,
        在onstart方法中serviceHandler发消息,serviceHandler收到消息后回调onHandlerIntent(Intent intent),然后结束service
    

    15. layout常见布局

    16. 广播的注册两种方式和区别

    17. 动画分哪几类,各有什么特点和区别

    * 补间动画(tween)
    * 帧动画(fram)
    * 属性动画
    

    18. 数据存储方式(扩展:安全存储)

    加强篇

    第一章:Material Design设计

    1. Android6.0 Material Design FAB动画设计
    2. Material Design Toolbar滑动与隐藏
    

    第二章:高级UI控件开发

    1. 自定义控件

    UI绘制流程 图解Android:View的绘制机制与源码解析

                  - viewtree的绘制机制
            1)viewTree:activity-> phoneWindow -> DecorView -> LinearLayout: title + content: our layout 
            2)绘制的入口:ViewRootImpl: performTranversals(): performMeasure() -> performLayout() -> performDraw()
                performMeasure: DecorView.measure(Match_parent,Match_parent) -> view.measure(Match_parent,Match_parent) -> override viewgroup.onMeasure()
    

    事件传递机制 图解Android:Touch事件传递机制

          - U型模式(事件捕获和事件的分发、传递、消费)
        * 事件冲突
        * 动画
        * 特效
    

    2. 主流UI架构设计

        * 抽屉导航
        * tab导航
    

    3. 仿QQ空间个性化可拉伸头部自定义空间

    4. 消息列表拖动排序

    5. 微信字母导航通讯录

    6. 属性动画(贝塞尔曲线)

    7. 视差动画引导页

    8. Android实现IOS Reveal特效

    9. 无限banner广告轮播

    10. viewpager滑动动画特效

    11. 3D菜单

    12. 自定义卫星菜单

    13. 自己实现Material Design超炫加载过度特效

    14. 沉浸式设计

    第三章:IM即时通讯

    1. XMPP协议

    2. 长连接心跳包方案

    第四章:移动架构师

    1. 插件式架构设计

        * 动态加载技术
    

    2. 缓存架构设计

        * 常见缓存算法:LRU,LFU,FIFO,Simple time-based,LargestLimitedMemoryCatch
    

    3. IOC架构设计

    4. GIF动画引擎

    5. 自定义动画框架

    6. 热补丁动态修补

    7. 设计模式 Android 设计模式:(一)面向对象的六大原则

        * 单例模式
    

    8. AOP框架

    9. 网络访问框架

    10. MVP架构

        MVC: Module层,View层,Controller层;
        MVP: Module层,View层,Presenter层;
        MVVM:Module层,View层,ViewModule层;
        
        1)MVC:
            View层是指xml layout;
            Controller层指Activity;
            Android的mvc不是一个纯粹的mvc模型,view层太弱,controller层太强,controller层兼具了view层的很多逻辑和处理;
            缺点:activity没有和module解耦;activity本身承载着controller的职责和view的很多职责,导致activity会非常的臃肿,代码逻辑会非常的复杂。
            有点:业务逻辑简单
            
            |---------|          |---------|          |---------|
            |         |  ---->   |         |          |         | 
            |   M     |          |   C     |  ---->   |   V     |
            |         |  <----   |         |          |         |
            |---------|          |---------|          |---------|
            
            
        2)MVP:
            View层是指Activity和xml layout;
            Presenter层绑定了view的接口逻辑和module的接口逻辑
            
                        
            |---------|          |---------|          |---------|
            |         |          |         |  ---> O--|         | 
            |   M     |  <----   |   P     |          |   V     |
            |         |          |         |  <----   |         |
            |---------|          |---------|          |---------|
            
            
        3)MVVM:
                    
            |---------|          |---------|          |---------|
            |         |          |         |          |         | 
            |   M     |  <---->  |   VM    |  <---->  |   V     |
            |         |          |         |          |         |
            |---------|          |---------|          |---------|
    

    11. RxJava响应式架构

    12. 图片加载框架

        * Glide框架源码分析
            缓存策略:
                lrumemorycatch 
                active resources(weakref map) 
                disckcatch -> bitmappool
                network catch -> bitmappool
            
            优点:
                * 请求队列具有生命周期,且与context的生命周期绑定:SupportRequestManagerFragment,RequestManagerFragment
                * 更加强大的多级缓存策略:更加节省内存,更快的加载速度,更高的命中率
                * 支持GIF,webp等格式
            
        * 自定义图片加载框架
    

    第五章:NDK开发

    1. NDK ffmpeg音频处理

    2. NDK实现360杀不死应用

    3. 增量更新

    第六章:React Native

    1. React Native实现原生开发+html5

    第七章:Android性能优化

    1. 内存优化

    1)内存泄漏

         内存机制:静态存储区;堆内存;栈内存
         生命周期:生命周期长的对象引用了生命周期短的对象,当生命周期短的对象生命周期结束后不会被释放而造成了内存的泄漏;
         关键点:单例;内部类;异步任务;子线程;handler;静态成员变量;
         优化策略:MAT工具查找内存泄漏的地方;代码走查;
    

    2)OOM错误

        扩展:错误和异常的关系
        Error和Exception都继承自Throwable; Exception 分为两大类:RuntimeException 和 IOException;
        Error和RuntimeException被称为unchecked,有系统抛出,不需要也不应该由程序员捕获和抛出;
        IOException被称为checked,需要有程序员捕获和抛出;
        
        遇到Error,程序一般是无能为力的;
        
        RuntimeException说明代码存在错误:
        NullPointerException - 空指针引用异常
        ClassCastException - 类型强制转换异常。
        IllegalArgumentException - 传递非法参数异常。
        ArithmeticException - 算术运算异常
        ArrayStoreException - 向数组中存放与声明类型不兼容对象异常
        IndexOutOfBoundsException - 下标越界异常
        NegativeArraySizeException - 创建一个大小为负数的数组错误异常
        NumberFormatException - 数字格式异常
        SecurityException - 安全异常
        UnsupportedOperationException - 不支持的操作异常
    

    3)ListView优化:

         复用convertView:
         viewholder的使用:findviewbyid
         onClickListener的使用
         图片的异步加载:Glide
         viewtype:多种类型的item
         ViewHolder基类的封装:简化代码
    

    2. UI绘制优化

        1)Over Draw: 过度绘制 GPU过度绘制检测
        2)布局文件:扁平化;merge标签,viewstub标签
        3)图片和背景色
    

    3. 网络请求优化

    1)架构:retroft+okhttp3+rxjava
    2)request和response的封装
    3)缓存
    4)生命周期
    5)防抖
    6)异常处理
    7)网络状态监听
    

    第八章:热修复技术:修复线上app的bug:

    1. QQZone:全量补丁patch.dex

        1)获取当前应用的BaseDexClassLoader
        2)通过反射得到应用的DexPathList属性对象pathlist
        3)通过反射调用pathlist的dexElements方法,把patch.dex转化为Element[]
        4)与原来的Element合并,把patch.dex放在最前面
        5)加载Element[]
        
        优点:
        1)没有合成整包,产物比较小,比较灵活。
        2)可以实现类替换,比较灵活
        
        缺点:
        1)不支持即时生效,必须重启才能生效
        2)应用中需要加入两个dex,若果patch.dex中的类达到了一定的数量,就需要花不少的时间进行加载。
        3)在ART模式下,如果类修改了结构,就会出现内存错乱问题。
           为了解决这个问题,就必须把所有的相关调用类,父类子类等都加入到patch.dex中,导致补丁包异常的大。
    

    2. 微信Tinker:差量补丁patch.dex

        1)对比待修复的apk和修复后的apk,生成差量补丁patch.dex
        2)开启新进程TinkerPatchService合并patch.dex和原来的dex
        3)获取当前应用的BaseDexClassLoader
        4)通过反射得到应用的DexPathList属性对象pathlist
        5)通过反射调用pathlist的makeDexElements方法,把合并后的dex直接替换到Element[]中去
        
        优点:
        1)合成整包,不用在构造函数中插入代码,防止verify和opt在编译期间就已完成,不会在运行期间进行。
        2)兼容性和稳定性比较高
        3)开发者透明,不需要对包进行额外处理。
        
        缺点: 
        1)不支持即时生效,需要重启才可以
        2)需要应用开启新的进程才能进行dex合并,并且很容易因为内存消耗等原因合并失败。
        3)合并时占用额外的磁盘空间,对于多dex的应用来说,
           如果修改了多dex时就要生成多个patch.dex与对应的classes.dex进行合并,此时占用的空间更多,因此合并过程的失败率也会更高。
    

    3. HotFix(AndiFix的优化版):通过运行时在Native修改Filed指针的方式,实现方法的替换。

        1)打开链接库得到操作句柄
        2)获取native层内部函数,得到ClassObject对象
        3)修改访问权限属性为public
        4)得到新旧方法的指针
        5)新方法指向目标方法,实现方法的替换
        
        优点:
        1)修复即使有效
        2)补丁包采用差量技术,生成的patch体积小
        3)对应用无侵入,几乎无性能损耗
        
        缺点:
        1)不支持新增字段,不支持类替换,不支持对资源的替换,不支持修改<init>方法
        2)由于厂商的自定义ROM,对少数机型暂不支持。
    

    4. Dexposed

    5. 美团Robust: 基于Instant Run

    第九章:组件化和模块化

    第十章:路由机制 Arouter

    第十一章:RxJava

    1.是什么?

        1.RxJava是一个库
        2.RxJava实现了由可观察序列来组织的代码逻辑:链式调用
        3.RxJava实现了基于异步的,基于事件的链式调用机制
    

    2.优点

        1.链式调用:代码逻辑简洁
        2.越来越多的框架采用了RxJava的框架
    

    3.基本概念

        被观察者(对象):Observable
        观察者(对象):Observer
        订阅(注册):Subscribe
        事件(观察者回调接口)
            onNext()
            onComplete()
                事件队列完毕(没有新的next())
            onError()
                事件队列异常:报出异常,并终止队列
    

    4.基本实现

    1.创建Observer:

      1)onNext()
      2)onComplete()
      3)onError()
      最终使用的是Subscriber:Observer的子抽象类:
            1)onNext()
              正常返回时业务处理:例如界面刷新显示
            2)onComplete()
              所有事件处理完毕时调用
              例如:在此位置可以隐藏进度条
            3)onError()
              当前调用链任何一个环节报错都将终止流程,并报错
              例如:在此位置可以弹出异常
            4)onStart():
              subscriber的方法,在订阅时(事件开始之前)调用,
              例如:在此位置可以显示进度条???注意主线程
            5)unsubscribe():
              subscriber实现的接口subscription的方法,\n用于取消订阅。
              例如:当退出当前界面时,\n可以取消数据的拉去和界面的刷新
              这个方法很重要,因为subscribe之后,\nobservable会保留对subscriber的引用,\n不调用该方法可能会内存泄露
    

    2.创建observable:

      observable决定什么时候触发事件,以及触发什么事件。
      被观察者需要制定事件触发规则,即调用事件序列
        oncreate(OnSubscribe?)
        just(T...)
        from(T[])
    

    3.Subscribe()

            Observable.subscribe(Subscriber)
            public Subscription subscribe(Subscriber subscriber) {
                  ......
                  subscriber.onStart();
                  ......
                  onSubscribe.call(subscriber);
                  ......
                  return subscriber;
          }
          Observable.subscribe(Observer)
    

    4.Scheduler

            调度器,用于实现异步机制\n即后台处理,前台回调
            在不指定线程的情况下,\nRxJava遵循在哪个线程subscribe(),\n就在哪个线程产生事件;\n在那个线程产生事件,就在哪个线程消耗事件。\n如果想要多线程异步处理,就要使用scheduler
            Scheduler API
                Scheduler.immediate()
                    运行在当前的线程
                Scheduler.newThread()
                    启用新线程,并在新线程执行事件
                Scheduler.io()
                    I/O操作的scheduler,相比newThread(),\n使用无数量上限的线程池,可线程重用,因此其更有效率
                Scheduler.computation()
                    计算所使用的scheduler,\n使用数量固定的线程池,\n用于CPU的高密度计算。\n不要把I/O操作放在该scheduler
                Androidscheduler.mainThread()
                    主线程
            subscribeon()
                指定事件发生的线程
            observeron()
                指定事件消费的线程
    

    5.Operater

        所谓变换,就是将事件序列中的对象或者整个事件序列进行处理,\n转换成新的事件序列或事件
        API
            map()
                事件对象的转换
            flatmap()
                事件序列转换成新的observable事件序列
            switchmap()
                相比flatmap,switchmap可以停止之前发出的事件
            filter()
                过滤:传入过滤条件
            take()
                截取数量
            doOnNext()
                在subscriber消费事件之前被调用
            throttleFirst()
                在每次时间触发后一定时间内丢弃新的事件,\n常用作去抖,比如按键去抖
        变换的原理
            lift()
                针对事件项和事件序列的转换
            compose()
                针对observable本身的整体转换
    

    第十二章 电量优化

    1.无线电波状态机

        1)FullPower
        2)LowPower
        3)StandBy
        
        FullPower ---5s---> LowerPower ---12s---> StandBy ---2s---> FullPower
                                |                                      ^
                                |                                      |
                                -------------------1.5s-----------------

    相关文章

      网友评论

        本文标题:Android 面试技术点总结

        本文链接:https://www.haomeiwen.com/subject/hezauxtx.html