美文网首页Android 面试Android开发
慕课网【Android面试】听课笔记(二)

慕课网【Android面试】听课笔记(二)

作者: Oterman | 来源:发表于2017-07-04 17:14 被阅读367次

    以下内容为慕课网【Android面试】课程的视频整理笔记的第二部分,整理较为粗糙,同时加上了一下自己的理解,以及一些参考的文章,可以根据这个框架再去细致的了解。

    内容为五到九章。

    一到四章参见:

    慕课网【Android面试】听课笔记(一)

    五.View相关的面试问题

    5-1 View绘制面试问题

    1.view树绘制流程

    measure->layout->draw;树的递归遍历;

    2.meaure

    MeasureSpec:测量的说明书,测量要求,它是一个32位的整数,前两位为测量模式SpecMode,后30位为在这种测量模式下得到的大小SpecSize;

    三种测量模式:

    • UNSPECIFIED:

         The parent has not imposed any constraint on the child.  
         It can be whatever size  it wants.  
         这种模式父类没有指定大小,view想要多大就给多大,较少用;  
      
    • EXACTLY

         The parent has determined an exact size for the child.  
         The child is going to be  given those bounds regardless of how big it wants to be. 
         精确模式。  
         父类已经检查出view所需的精确大小,此时View的最终大小就是SpecSize的值。
         它对应于LayoutParams的match_parent和指定具体数值这两种模式;  
      
    • AT_MOST

        The child can be as large as it wants up to the specified size.  
        最大模式。  
        父类指定了view可用的最大值specSize,view的大小不能大于这个值。  
        它对应LayoutParams的wrap_content模式。  
      

    普通view的MeasureSpec是由父类的MeasureSpec以及它自身的LayoutParams共同决定的。具体来说:

    • 如果view宽高是match_parent:
      (1)父容器为精确模式,view也是精确模式,并且大小是父容器剩余空间;
      (2)父容器为最大模式,view也是最大模式,并且大小不会超过父容器剩余空间;

    • 如果view宽高为wrap_content:
      不管父容器是精确模式还是最大模式,view总是最大模式,并且大小不会超过父容器剩余空间的最大值。

    参加《Android开发艺术》 p182。

    measure的具体流程

    • 普通View的measure过程:
      由measuer方法完成,measure调用onMeasure,自定义控件时,只需要实现onMeasure方法,在onMeasure方法中确定大小后,必须调用setMeasureDimension方法使生效。

    • ViewGroup的绘制过程:
      viewgroup onMeasure方法是抽象的,因为有各种viewgroup,他们的实现各不相同。viewgroup大小测量主要思想是,先测量递归遍历出孩子view的大小,然后调用getMeauredWidth获取测量的值,然后再决定自己的宽度如何。不同的viewgroup各不相同。

    Q:在Activity启动时,如何获取某个view的大小?

    view的测量和Activity的生命周期没有直接关系,因此不能在Activity的生命周期调用
    getMesauredWidth来获取值。有以下四种解决方法:

    • Activity/View:onWindowFocusChanged
    • view.post(runnable)
    • ViewTreeObserver
    • view.measue

    具体参见《Android艺术开发》 p190

    3.layout

    布局,作用是确定元素及子元素位置。布局过程主要有两个方法:

    • layout:确定自己的位置,对于viewgroup,会在layout方法调用onLayout方法,layout方法不应被重写;
    • onLayout: 被layout方法调用,确定所有子元素的位置,子类应该重写这个方法并且调用每个子元素的layout方法;

    主要思想:先确定自己的位置(不然子元素如何确定其位置),确定自己位置后,然后确定子元素的位置,如果子元素是viewgroup,再如此递归下去,直到确定所有的元素的位置;

    自己定义的控件是一个View不是ViewGroup,则没有必要重写onLayout(都没有子元素,重写个毛?)。

    Q:View的getMeasuredWidth和getWidth这两个方法有什么区别?

    在View得默认实现中,view的测量宽高和最终宽高是相等的,只不过测量宽高发生在measure过程,而最终宽高形成于layout过程,两者的赋值时机不同,测量的宽高要稍早一些,因此,通常我们认为测量宽高等于最终宽高,但是也有特殊的例外,比如重写了view的layout方法,这种情况没什么意义。

    4.draw

    将view绘制到屏幕上;
    绘制步骤:

    1. 绘制背景;
    2. 绘制自己 (onDraw);
    3. 绘制子元素(dispatchDraw);
    4. 绘制装饰

    两个方法的区别:
    invalidate():请求系统重新绘制;不会测量和布局;
    requestLayout():请求重新布局,触发measure和layout;

    5.自定义控件

    Android自定义控件之基本原理

    分类:

    1. 继承普通View重写onDraw方法:主要用于实现一些不规则动画;
    2. 继承ViewGroup派生的特殊layout:实现自定义布局,几种view的组合;

      Android自定义控件之自定义组合控件

    3. 继承特定的View比如TextView:用于拓展功能;
    4. 继承特定的ViewGroup: 需要处理测量和布局两个过程;

    5-2 事件分发面试问题

    1.为什么有事件分发机制

    多个控件重叠区在一起,View是树形结构,View可能会重叠在一起,当我们点击一个地方时,可能会有多个view都去响应,这个响应的事件到底该给谁呢?为了解决这个问题,然后就有了事件分发机制;

    shijianfenfa.PNG

    PhoneWindow:事件管理容器
    DecorView:是phoneWindow的内部类;

    2.三个重要方法

    dispatchTouchEvent:分发事件,返回结果受当前view的onTouchEven和下级的dispatchTouchEvent影响,表示是否消耗掉事件;
    onInteceptTouchEvent:拦截事件,如果当前view一旦拦截了某个事件(返回true),那么同一个事件序列中,不会再调用此方法;
    onTouchEvent:处理事件,返回true表示消耗掉事件,返回false,不消耗,会继续往上传递,如果不消耗,在同一个事件序列中,当前view无法再接收到事件。

    当一个view设置了OnTouchListener,那么onTouch方法会被调用,如果该方法返回false,onTouchEvent会被调用;如果返回true,onTouchEvent方法不会被调用!

    可见OnTouchListener的优先级要高于onTouchEvent;在onTouchEvent中,如果设置了OnclickListener,那么onclick方法会被调用。如果设置了OnTouchListenr并在onTouch中返回了true,那么onClick方法会失效,因为此时onTouchEvent不会被调用!

    三者之间的关系可以用如下伪代码表示:

    public boolean dispatchTouchEvent(MotionEvent ev){
        boolean consume=false; 
        if(onInterceptTouchEvent(ev)){
            comsume=onTouchEvent(ev);
        }else{
            consume=child.dispatchTouchEvent(ev);
        }
        return consume;
    }
    

    3.事件分发流程

    Activity->PhoneWindow->DectorView->ViewGroup-...>View
    最后的view没处理,不处理则回传交给上级onTouchEvent处理;

    事件分发流程:

    sjfflc.PNG

    参考文章:

    一文读懂Android View事件分发机制
    Android事件分发机制详解:史上最全面、最易懂

    5-2 ListView缓存

    1. 什么是listview

    是一个能数据集合以动态滚动的方式展现给用户界面的view

    2. listview的适配器模式

    不用关心数据来源,只关心显示,他和数据是分开的,通过适配器来加载数据,是数据源和lv的桥梁;

    lvadapter.PNG

    3.recyleBin机制

    AbsListView 内部类

    RecyleBin
    重要方法:
    setViewTypeCount():设置item样式的类型,默认只有一种;

    lvrecylebin.PNG

    4.listview的优化

    convertView/viewholder
    三级缓存:图片加载时
    getview():不要做耗时
    滑动监听:停止时再加载;

    Android性能优化之提高ListView性能的技巧
    Android性能优化之------Listview优化

    --

    六.Android项目构建相关面试问题

    6-1 android studio目录结构

    project 包含module

    .gradle
    .idea
    app 模块

    build 
    libs
    src
    builde.gradle 模块的配置
    proguard-rules.pro 混淆
    

    build 编译生成在此目录
    gradle wrapper

    .gitignore
    build.gradle 配置文件
    gradle.properties 全局配置文件
    loacl.propeties
    setting.gradle 设置相关

    文件

    6-2 android项目构建

    构建流程

    java->字节码->dex->apk->sign->signed apk
    appt-> R.java
    aidl

    buildliucheng.PNG

    jenkins持续集成构建

    自动构建

    6-3 git版本控制

    易混淆概念

    工作区
    gitignore 不想上传的文件

    常用命令

    Git使用总结

    Terminal

    git init
    git status 查看状态
    git diff filename 这次和上次的不同
    git add file
    git commit
    git clone
    git branch
    git --help
    git checkout

    主要工作流

    fork clone

    6-4 gradle

    自己建立一个项目进行查看

    6-5 proguard代码混淆

    是什么

    打包压缩代码,优化,混淆我们代码,移除无用的类,字段,方法,同时可以混淆,防止反编译

    技术功能

    压缩 移除无用类
    优化 字节码优化,移除无用字节码
    混淆 有意义的名词变成无意义名词
    预检测

    工作原理

    EntryPoint

    为什么要混淆

    跨平台 源代码信息 无用的,容易被反编译成源代码,对发布的程序进行重新组织和处理

    --

    七.开源框架

    7-1 okhttp网络框架

    简单使用

    创建okhttpclient
    request
    execute 同步
    enqueue 异步

    源码分析

    拦截器思想

    7-2 retrofit网络框架

    如何使用

    基于okhttp

    源码分析

    retrofit对象
    .create()
    okhttp.call();
    动态代理设计模式

    7-3 volley网络框架

    使用简介

    google推出,加载图片
    数据量小,通信频繁;

    RequestQueue
    StringRequest
    queue.add(request);

    源码分析

    volley.PNG

    7-4 butterknife注解框架 研究源码

    使用简介

    解决findViewById
    依托注解机制实现代码辅助生成。
    绑定view
    点击事件
    listviewitem点击事件。

    原理

    注解解释器
    并不是反射!!
    注解处理技术。
    编译好之前就已经处理好。
    注解是在编译之前处理好的。

    属性不能为private和static

    1.扫描注解
    2.ButterKnifeProcessor-><className>$$ViewBinder
    3.ViewBinder

    7-6 glide图片框架

    with().load().into

    结合组件的生命周期。

    7-7 EventBus

    --

    八.Android异常和性能优化

    Android开发艺术探索 15章 性能优化 总结

    这段不是听课内容,是我的读书总结

    性能优化主要包括:

    • 布局优化

      1.减少布局的层级;
      2.其次使用性能较高的viewgroup,如相比LinearLayout,RelativeLayout布局过程要耗费更多时间;
      3.使用include和Merge标签;
      4.使用ViewStub代替view,ViewStub是一个宽高都为0的特殊View,不参与布局和绘制过程下面是ViewStub的典型用法:

      一个网络异常界面,初始时不需要加载,需要时才加载:

        <ViewStub android:layout_width="match_parent"
              android:id="@+id/stub_import"
              android:layout="@layout/activity_network_error"
              android:layout_height="wrap_content"/>
      

      需要加载ViewStub的布局时,使用以下两种方式:

        findViewById(R.id.stub_import).setVisibility(View.VISIBLE);
        或者
        ((ViewStub)findViewById(R.id.stub_import)).inflate();
      
    • 绘制优化

      主要是在View的onDraw方法中避免大量的操作;
      一是不要在onDraw中创建临时对象,onDraw可能会调用多次,临时对象容易一起垃圾回收器频繁工作;

      二是不要再onDraw方法中做耗时任务;

    • 内存泄漏优化

      使用MAT工具来分析内存;

      一是静态变量引起内存泄漏,如在Activity中有静态的成员变量,而且静态变量的赋值时会引用当前的对象;

      二是 单例模式引起内存泄漏;

      三是属性动画无限执行引起内存泄漏,解决方法为在onDestroy中使用animator.cancel()来停止动画;

    • 相应速度优化

      发生anr时,会在/data/anr/traces.txt中有日志记录,分析该文件;

    • bitmap优化

      主要通过BitmapFactory.Options对图片采样,采样主要用到BitmapFactory.Options的inSampleSize

    • ListView优化

      一是使用convertView及viewholder;
      二是根据列表滑动状态控制任务执行情况,比如在快速滑动的时候,不要加载图片;
      三是开启硬件加速;

    • 线程优化

      使用线程池;

    性能优化小建议:

    • 避免创建过多对象
    • 减少使用枚举,枚举占用空间大
    • 产量使用staic final 来修饰
    • 使用Andorid特有的数据结构SparseArray和Pair
    • 适当使用软引用和弱引用
    • 采用内存缓存和磁盘缓存
    • 尽量使用静态内部类,避免内存泄漏

    听课笔记正式开始....

    8-1 ANR异常

    什么是anr

    appliaction not responding 无响应
    5秒
    广播接收者10s

    主线程做了耗时操作;

    产生的主要原因

    ActivityManager WindowManager来监视
    主线程做了耗时的io操作;
    主线程存在耗时操作
    4.0之后主线程不能进行网络请求;

    哪些操作在主线程中发生?

    Activity生命周期都是执行在主线程
    Service 默认执行在主线程
    子线程 IntentService
    BroadReceiver onReceive在主线程

    没有关联子线程looper的handler的handleMessage方法,post(runnable)是执行在主线程;

    AsyncTask除了doInbackground方法执行在子线程,其他方法都是执行在主线程;

    解决anr

    asynctask处理耗时io操作;

    使用thread或者handlerThread提高优先级

    使用handler来处理耗时任务

    Activity onCreate onResume不要做耗时操作;

    8-2 OOM异常

    什么是oom

    内存不够,内存超过了虚拟机的最大内存限制。
    bitmap加载有关。

    容易混淆的概念

    内存溢出 内存不够用
    内存抖动 短时间大量对象创建,然后回收,触发gc

    内存泄漏 对象不能被回收;无用对象引导有用对象;

    解决oom

    bitmap优化

    图片显示     
    及时释放内存    
    加载是有jni来完成的    
    图片压缩   
    大小控制    
    缩放比例   
    inBitmap属性   
    捕获异常  
    

    listview convertView复用
    lru机制
    避免onDraw方法执行对象的创建
    谨慎使用多进程

    8-3 bitmap

    1.recyle

    内存回收 源码
    不是可逆的
    存储在java内存和native c内存
    不建议主动调用

    2.LRU

    三级缓存
    最近最少使用算法
    LruCache

    3.inSampleSize

    合适大小的图片
    inJustDecodeInBounds

    4.缩略图

    5.三级缓存

    和网络交互
    网络
    本地
    内存

    8-4 ui卡顿

    1.原理

    60fps-> 16ms
    渲染
    16毫秒内完成一帧的渲染 1秒60帧
    overdraw 多次绘制 大量重叠 非必要重叠背景
    GPU

    渲染作了太多耗时操作

    2.原因分析

    人为在ui线程做轻微耗时操作,导致卡顿
    卡顿是轻量级的anr
    布局layout太过于复杂 ,无法在16ms内完成渲染
    统一时间动画执行次数太多,导致gpu和cpu负载过重
    view过度绘制,多次绘制
    频繁出发measure layout
    频繁的gc过多
    冗余资源导致加载和执行缓慢
    anr

    3.总结及优化

    布局优化,不要深层次嵌套
    gone替换invisiable
    列表及adapter优化 滑动时不要加载
    背景和图片内存分配
    避免anr 不要在主线程做耗时操作

    8-5 内存泄漏

    1.java内存泄漏基础知识

    1.Java 内存分配策略
    静态存储区
    栈区:局部变量
    堆内存:new 对象 数据 垃圾器负责回收

    2.Java是如何管理内存的

    3.内存泄漏

    无用对象持续占有内存,得不到及时释放,从而造成内存空间浪费。

    2.Android 内存中的泄露

    单例导致:单例的生命周期较长,如果引用了需要回收的对象(context传入Activity),那么就会导致需要回收的对象得不到及时的回收,造成内存泄漏。

    ncxl_singliton.PNG

    非静态内部类:非静态的匿名内部类会持有外部类的引用,如果说在内部类中有一些静态的对象,这些静态的对象生命周期很长,当外部类的对象需要回收的时候,内部类却引用了它,使得外部类无法被回收,造成内存泄漏。解决方法是把内部类变成静态内部类,这样就不会持有外部类的引用了。 (这一点我认为有问题,内部类不能有静态的成员,所以不会存在所说的情况!!)

    handler:写成匿名内部类时,会持有外部类的引用,当activity退出时,如果此时消息队列中还有未处理的消息,就会导致activity无法回收,造成内存泄漏。解决方法:不要写成内部类的形式,写成静态内部类,传入外部类的弱引用。

    以下是容易造成内存泄漏的写法:

    handler1.PNG

    以下是正确写法:

    handler2.PNG

    避免使用static成员变量:static类型的变量生命周期很长。

    资源未关闭导致内存泄漏:io,cursor等未关闭。

    AsyncTask造成内存泄漏:原理与handler类似,注意要在Activity的onDestroy中带调用异步任务的cancle方法取消任务。

    8-6 内存管理

    1. 内存管理机制概述

    内存:数据存储区域,操作系统来调度;
    分配机制:为进程分配合理内存大小,

    回收机制:内存不足时,回收再分配

    2. Android 内存管理机制

    分配机制:弹性分配,分配的大小根据实际来分配,不够时再分配额外的大小,分配是有限制的。尽最大限度地使用。

    回收机制:五大进程(前台,可见,服务,后台,空),优先级越低,被回收概率越大,

    3. 内存管理机制的特点(目标)

    更少的占用内存
    合适的时候,合理释放系统的资源
    在内存紧张的情况下,能释放掉大部分不重要的资源
    在合理的生命周期中,保存还原重要数据,重启时能恢复

    4. 内存优化方法

    service完成后,尽量停止它
    ui不可见时,释放ui使用的资源
    内存紧张时,释放不重要的资源
    避免滥用bitmap导致内存浪费
    使用针对内存优化过的数据容器,lru
    避免使用依赖注入框架
    使用zip对齐的apk
    使用多进程

    5.内存溢出vs内存泄漏

    内存溢出:oom
    内存泄漏:本该回收未被回收

    8-7 冷启动优化

    1.什么是冷启动

    定义 :在应用启动前,系统中没有该应用的任何进程信息;

    冷启动/热启动区别:热启动,返回建退出,重新启动,系统中有该应用的进程信息,应用保留在后台。只需要创建mainAvitity,不用创建Appliaction。
    冷启动:会创建appliaction类

    冷启动时间计算:应用启动到完成视图第一次绘制为止。

    2.冷启动的流程

    统进程 zygote(一)—— 概述

    Zygote进程中 fork一个新进程
    创建和初始化Appliaction类,创建MainActivity类
    inflate布局,onCreate,onStart,onResume
    contentView的measure,layout,draw显示在界面上

    总结:

    Application的构造方方法->attachBaseContext()->onCreate()->Activity的构造方法->onCreate()->配置主题中的背景等属性->onStart()->onResume()->测量布局绘制显示在界面上。

    3.冷启动时间的优化

    减少onCreate方法的工作量
    懒加载

    不要让Appliaction参与业务操作
    不要在Appliaction中进行耗时操作
    不要以静态变量的形式保存数据于application中
    减少布局的层级

    8-8 其他优化

    不要用静态变量存储核心数据

    静态变量由于进程被杀死会被初始化,数据不安全

    其他文件传输方式:文件/sp/contentProvider

    有关sp问题

    不能跨进程同步
    每个进程会维护自己的副本,结束时才提交

    存储时文件过大问题 过大的key,value会导致卡顿

    内存对象的序列化

    序列化:对象转化为可传递
    Serializeable: java序列化方式 序列化是产生大量临时变量 引起频繁GC
    Parceable:自带的序列化方式,性能更好,不能存于磁盘,用于进程间通信

    避免在UI线程中做繁重耗时的操作

    --

    九.热门前沿知识相关

    9-1 MVC架构设计模式

    定义

    Modle,View,Controller
    业务逻辑,显示分离
    M:业务逻辑处理
    V:显示 view充当
    C:Activity充当,桥梁作用

    特点

    1.耦合性低:模块之间相互影响

    2.可拓展性好

    3.模块职责划分明确

    实例讲解

    特点

    可拓展性,维护性
    controller是桥梁

    什么时候适合mvc:较大的项目中,业务比较复杂;

    9-2 MVP架构设计模式

    定义

    Model:业务逻辑和实体模型
    View:activity充当
    Presenter:负责完成view和model的交互

    activity的复杂的业务逻辑抽取到presenter中
    view和model不能交互

    mvc_mvp.PNG

    实例讲解

    代码结构:

    mvp1.PNG

    总结

    耦合性更低

    9-3 MVVM架构设计模式

    ViewModel和View同步更新
    数据绑定和依赖

    viewmodel.PNG

    View:对应Activity和xml,负责view的绘制及用户交互,没有业务逻辑代码 ,提供ui接口
    Model:数据模型 提供数据操作接口
    ViewModel: 负责View和Model的交互 ,负责业务逻辑

    总结:

    mvc:xml view功能太弱了
    mvp:presenter做业务逻辑,持有view接口
    mvvm :

    9-4 android插件化

    插件化来由

    Android插件化研究

    apk越来越大
    方法数量超过65536时,无法再操作

    解决问题

    动态加载apk
    DexClassLoader

    资源加载
    AssetManager

    代码加载
    通过反射获取生命周期方法

    9-5 android热更新

    热更新流程

    发生崩溃 在线热修复,不用重新发布版本
    1.线上检查到严重的crash
    2.拉出bugfix分支 并在分支上修复问题
    3.jenkins构建和补丁生成
    4.通过推送或者主动拉去补丁文件
    5.bugfix分支合并到master分支上

    热门热更新框架

    1.Dexposed
    aop xposed
    动态加载技术 不需要重启app,实现修改app
    2.andfix

    纯粹的热修复

    3.nuwa
    classloader

    热更新原理

    Android热更新机制

    1.类加载机制
    PathClassLoader

    DexClassLoader

    2.热修复加载机制

    dexElements数组
    classLoader遍历数组

    9-6 进程保活

    进程优先级

    进程杀不死,常驻进程,为用户提供服务

    前台进程:当前操作所在的进程,数量不多,前台service startForground
    可见进程:
    服务进程:
    后台进程:lru
    空进程:做缓存,缩短启动时间 不包含任何组件

    进程回收策略

    Low memory killer:通过复杂的评分机制,对进程打分,然后将分数高的进程判定为bad进程,杀死并释放内存。

    oom_odj:判别进程优先级

    进程保活方案

    利用系统广播拉活:开机,网络变化,有缺陷,被禁用自启动后无法响应,系统广播事件没法控制
    利用系统service机制拉活:service 返回值 start_sticky
    利用Native进程拉活:进程机制 fork进程监控主进程,5.0版本后加强管理 失效

    利用JobScheduler拉活:监听主进程

    利用账号同步机制拉活:

    9-7 UIL

    univerimageloader
    查看源码

    图片加载框架

    9-8 lint检查

    什么是lint检查

    静态代码分析工具,对潜在的bug,可优化代码,性能,可用性,可访问性,国际化等检查

    工作流程

    lint.PNG

    配置lint

    lint.xml 根目录

    lintxml.PNG

    JAVA 代码 xml布局
    @supressLint

    xml:tools:ignore="unuseresource"

    自定义lint

    原因:默认不能满足需求

    原理:detector

    总结

    9-9 kotlin

    是什么

    基于jvm
    java的拓展
    函数是编程
    能与Java类相互调用

    环境搭建

    实例

    相关文章

      网友评论

        本文标题:慕课网【Android面试】听课笔记(二)

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