Android 面试Android开发

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

2017-07-04  本文已影响367人  Oterman

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

内容为五到九章。

一到四章参见:

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

五.View相关的面试问题

5-1 View绘制面试问题

1.view树绘制流程

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

2.meaure

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

三种测量模式:

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

参加《Android开发艺术》 p182。

measure的具体流程

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

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

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

3.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章 性能优化 总结

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

性能优化主要包括:

性能优化小建议:

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

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类相互调用

环境搭建

实例

上一篇下一篇

猜你喜欢

热点阅读