知识点总结

一.Activity面试详解

1.activity生命周期

4种状态
running/paused/stopped/killed
activity生命周期
android进程优先级: 前台/可见/服务/后台/空

2.Android任务栈

3.activity启动模式

onNewIntent何时调用:在singleTop和singleTask模式下,某个acitivity已经启动。当再次调用的时候,才会调用

4.scheme跳转协议

二. Fragment面试详解

1.Fragment为什么被称为第五大组件

为什么会成为第五大组件
使用频率,有自己声明周期,动态灵活加载到activity,更节省内存
加载到Activity的两种方式
FragmentPagerAdpter和FragmentStatePagerAdapter的区别
前者使用于页面较少的,后者适用于页面较多的情况。

2.Fragment的声明周期

3.Fragment之间的通信

fragment调用activity中方法 getActivity

4.FragmentManager

三. Service面试详解

1.service应用场景,与Thread的区别

service基础 是什么?区别?

2.启动的两种方式

startService
使用:
生命周期
onCreate->onStartCommand->onDestroy
多次调用startService,会多次调用onStartCommand函数,但不会调用onCreate
特点:与开始服务的组件没有关系,开启服务的组件销毁,服务仍旧会继续运行。
bindService
使用:
生命周期
onCreate->onBind->onUnBind->onDestroy
特点:与绑定服务的组件强绑定,绑定服务的组件如果销毁,该服务也会销毁。

四. Broadcast Receiver面试详解

1.广播

定义
场景 同一app的多个进程 不同app之间的组件之间的通信
种类 普通广播,有序广播,本地广播

2.实现广播 receiver

3.广播实现机制

4.LocalBroadcastManager详解

五. Binder机制

1.Linux内核基础知识

进程隔离/虚拟地址空间
系统调用:内核空间,用户空间

2.Binder通信机制介绍

为什么使用binder
binder通信模型
通信的两个用户进程:手机
binder驱动:基站
serviceManager:通讯录
binder通信原理

3.AIDL

使用步骤

六.Android多线程

1.Handler面试详解

1.1 什么是Handler

1.2 使用方法

1.3 机制原理

1.4 handler引起的内存泄露和解决方法

原因

静态内部类持有外部类的应用,导致外部类activity无法被释放

解决方法

handler内部持有外部acitvity的弱引用,并把handler改为静态内部类,在activity的ondestroy中加入mHandler.removeCallback()

2.asynctask面试详解

2.1.什么是asynctask 封装了线程池和handler的异步框架

2.2.使用方法

2.3.内部原理

2.4.AsyncTask的注意事项

AsyncTask的对象必须在主线程中创建
execute方法必须在UI线程中加载
一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报一场
不适合做长时间耗时的操作,如果要执行长时间操作,最好使用线程池Excutor
避免内存泄露,解决内存泄露的方法跟handler一样。

3.handlerThread面试详解

3.1.是什么

产生的背景:为了解决 多次创建和销毁线程是很消耗系统资源的。

3.2.源码解析

4.intentService面试详解

4.1.是什么

一个封装了HandlerThread和handler的异步框架。每次任务完成会自动关闭service。普通service是运行在主线程的,无法处理耗时操作,intentService提供了这种机制。

4.2.使用方法

继承intentService,覆写onhandleIntent方法,在里面处理耗时操作。

4.3.源码解析

可以启动多个intentService,会将任务存储在队列中依次执行。
内部是利用handlerThread实现的。

七.view

1.绘制问题面试

1.1.view树的绘制流程

1.2.measure

测量是从viewgroup从上到下依次递归测量的。viewgroup是抽象类,里面没有重写onMeasure,如果要自定义viewgroup类的时候必须重写onMeasure,里面定义如何通过遍历子类最后计算出viewgroup的大小。
onMeasure中有两个参数,分别是widthMeasureSpec, heightMeasureSpec,每个measurespec包含两个值,一个是specmode,一个是specsize。每个view的measurespec是由父控件的measurespec和当前view的layoutparam共同决定的。
如果为EXACTLY,说明view的layoutparam是具体的size,或者match_parent,此时specsize就是最后的size。
如果是AT_MOST,说明view的layoutparam是wrap_content,此时specsize需要子view根据自己的情况获取最后的size。
也就是说当我们自定义view的时候,如果在布局文件中只需要设置具体size或者match_parent两种属性,那么就不需要重写onMeasure。如果需要设置wrap_content,就需要重写onMeasure,计算这种情况下的 控件的大小。
参考:https://www.jianshu.com/p/d07f633c37e7

1.3 layout

onLayout()都是由ViewGroup的子类实现的,他的作用就是确定容器中每个子控件的位置,由于不同的容器有不容的布局策略,所以每个容器对onLayout()方法的实现都不同,onLayout()方法会遍历容器中所有的子控件,然后计算他们左上右下的坐标值,最后调用child.layout()方法为子控件设置坐标

首先我们要明确布局的本质是什么,布局就是为 View 设置四个坐标值,这四个坐标值保存在View的成员变量 mLeft、mTop、mRight、mBottom 中,方便 View 在绘制(onDraw)的时候知道应该在那个区域内绘制控件。
自定义viewgroup必须实现onLayout,对子控件进行摆放。
参考:https://www.jianshu.com/p/0b444c4c5cf6

1.4 draw

1.5 getWidth和getMeasureWidth区别

getMeasureWidth是在onMeasure执行完成后获得的,而getWidth是在onLayout执行完成后获得的
getMeasureWidth是onMeasure最后通过setMeasuredDimension设置大小后获取的宽度。getWidth是onLayout后,mRight-mLeft获得的。也就是说在onMeasure后可以通过onLayout改变控件的显示宽度。

2.view的事件分发机制面试

2.1.为什么会有事件分发机制

由于view是树形结构,点击屏幕可能引起多个响应,为了确定哪个view进行响应,引入了事件分发机制。

2.2.三个重要的方法

dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent
三者之间的伪代码如下

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

viewgroup接收到TouchEvent后会将事件通过dispatchTouchEvent分发。如果onInterceptTouchEvent返回true,则事件交由viewgroup的onTouchEvent来处理;如果返回false,则会交给子View的dispatchTouchEvent来处理。
默认情况下,viewgroup的onterinceptTouchEvent返回false,及不拦截事件。view没有onterinceptTouchEvent,所以view只要已接收到事件,就会传递给自身的onTouchEvent。

滑动冲突解决

八.优化

1.内存溢出oom

当前占用的内存加上我们申请的内存资源超过了Davik虚拟机的最大内存限制就会抛出out of memory异常。
主要原因就是bitmap

1.1 有关bitmap

(1)图片的存储优化

图片占用内存计算:图片宽度 x 图片高度 x 一个像素占用的内存大小

尺寸压缩

(1)设置inJustDecodeBound=true,,使图片能够没加载进内存就能够获取图片的狂傲。
(2)设置imSampleSize,只要大于2,就能够压缩图片占用内存。
(3)单纯改变ImageView不会对图片占用内存有任何的改变,必须针对bitmap本身的优化才起作用。

质量压缩

(1)常见的PNG,JPG,WEBP等格式的图片在设置到UI上之前需要经过解码过程;
使用tinyPNG网站压缩PNG
使用Webp
(2)使用RGB_565替代ARGB_8888可以降低图片占用内存;
RGB_565一个像素占用两个字节,而ARGB_8888一个像素占用四个字节

内存重用

使用inBitmap属性,对内存进行重用。
4.cache
使用lru算法。
内部利用linkedHashMap实现,提供了get,put操作,缓存满了之后提供trimToSize方法,移除较早的缓存对象,添加最新的对象

listview convertview/lru

1.2 避免在onDraw方法里面执行对象的创建

容易造成内存抖动,内存抖动积累到一定程度也会造成oom。因为频繁内存抖动会将内存碎片化,从而当需要分配内存的时候,虽然总体上还有内存分配,但是由于这些内存不是连 续的,导致无法分配,系统就直接返回OOM了

1.3 使用多进程,需非常谨慎

2.内存抖动

短时间内创建大量对象,内存达到阈值后,触发gc。内存抖动积累到一定程度也会造成oom。因为
频繁内存抖动会将内存碎片化,从而当需要分配内存的时候,虽然总体上还有内存分配,但是由于这些内存不是连续的,导致无法分配,系统就直接返回OOM了

3.内存泄露:

3.1 java内存泄露基础知识

指的是无用对象持续占有内存或无用对象的内存得不到及时释放,造成的内存空间的浪费称为内存泄露。

1.java内存分配策略

静态存储区(方法区)

存储静态变量,全局变量。编译的时候已经分配好了,并且该区域存储的变量在整个程序运行的过程中都存在。

栈区

方法中的局部变量,一些基本类型的变量,对象的引用变量。方法结束后自动释放。

堆区

动态内存分配。存储new出来的对象和数组,由java的垃圾回收器来管理

2.java如何管理内存

3.java中的内存泄露

3.2 android内存泄露

1.单例.

因为静态变量存在与app的整个生命周期。如果静态变量持有了某个activity的context,就会造成activity无法释放。

2.非静态内部类:

包括成员内部类,局部内部类和匿名内部类。因为非静态内部类会持有外部类的引用

3.handler

4.避免使用static

5.资源未关闭造成的内存泄漏

6.AsyncTask造成的内存泄漏

android内存管理
    内存管理机制概述
    分配机制:为每个进程分配机制
    回收机制:
android内存管理机制
    分配机制:
    回收机制:根据进程优先级回收进程
内存管理机制的特点
    更少的占用内存
    在合适的时候,合理的释放系统资源(不是说对象不需要了就立刻回收掉就是最好的内存管理,频繁的释放内存

会造成内存抖动,这样会造成anr,oom,卡顿)
在系统内存紧张的时候,尽可能的释放掉一些非重要资源

内存优化方法
    service完成任务后,尽量停止它
    在UI不可见的时候,尽可能的释放掉一些非重要资源
    在系统内存紧张的时候,尽可能多的释放掉一些非重要资源 onTrimMerory
    避免滥用Bitmap导致的内存浪费
    使用针对内存优化过的数据容器,避免使用枚举
    避免使用依赖注入的框架
    使用zip对齐的apk
    使用多进程 例如开启一个进程 定位,webview,推送    
内存溢出vs内存泄露
    内存溢出oom:
    内存泄漏:

4.UI卡顿

4.1 UI卡顿原理

60fps->16ms
Android系统每隔16ms触发对android进行渲染,如果每次都能渲染成功,就能够达到流畅的画面,也就是每秒60帧画面。

4.2 UI卡顿原因分析

1. 人为在UI线程中做轻微耗时操作,导致UI线程卡顿

2. 布局Layout过于复杂,或者过度绘制,无法在16ms内完成渲染。

3. 同一时间动画执行的次数过多,导致CPU或GPU负载过重。

4. View频繁的触发measure、layout,导致measure、layout累计耗时过多及整个View频繁的重新渲染。

5. 内存频繁触发GC过多,导致暂时阻塞渲染操作。gc过程会暂停所有线程的工作。

4.3 UI卡顿总结

(1)布局优化

消除冗余嵌套和过复杂的布局

Gong替换invisible
尽量使用weight代替长宽
如果存在非常复杂的嵌套,可以考虑使用自定义的view。减少measure和layout的次数

(2) 列表及adpter优化

在滑动过程中,只加载缺省图片,停止的时候才加载图片和数据

(3) 背景和图片等内存分配优化

去掉不必要的背景
图片要进行压缩

(4) 避免ANR

5. 冷启动优化

5.1什么是冷启动

(1)冷启动的定义

第一次启动应用或者被进程杀死后重新启动。
启动之前,系统中没有该应用的任何进程信息。

(2)冷启动热启动的区别

a.启动之前有没有该应用的进程
b.要不要启动Application的类

(3)冷启动的时间的计算

这个时间值从应用启动(创建进程开始计算),到完成视图的第一次绘制(即Activity内容对用户可见)为止。

5.2 冷启动流程

Zygote进程汇总fock创建出一个新的进程
创建和初始化Application类,创建MainActivity类。
Inflate布局、当onCreate、onStart、onResume方法都走完
contentView的measure、layout、draw显示在界面上

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

5.3 启动优化

(1) 减少onCreate方法的工作量

(2) 不要让Application参与业务操作

(3) 不要在Application进行耗时操作

如果耗时操作过多,应用冷启动后会出现白屏现象。
解决方法:https://www.jianshu.com/p/436b91175826

(4) 不要以静态变量的方式在application中保存数据

(5) 布局/mainThread

6 其他优化

6.1 android中不要用静态变量存储数据

App转入后台,由于内存过低,系统可能会将app进程杀死。但是系统为了用户体验,会将最后的Activity恢复,而此时app的进程使重新开启的,静态变量会重新初始化。该Activity如果应用了静态变量,会造成nullpointer的错误

6.2 有关Sharepreference的问题

(1)不能跨进程同步

每个进程都有sharepreference的副本,只有在进程结束的时候才会同步。

(2)Sharepreference的文件过大的问题

如果文件过大,在获取Sharepreference值的时候,会阻塞主线程,造成卡顿
如果文件过大,在解析Sharepreference的时候,会产生大量的临时对象,造成频繁GC,造成内存抖动,也会造成界面卡顿,甚至会发生oom

(3)内存对象序列化

序列化

将对象的状态信息转换为可以存储活传输的形式的过程

Serializeble

产生大量临时变量,引起频繁gc,造成内存抖动,页面卡顿,严重的会产生oom

Parcelable

android独有的序列化方式。不能适用将数据存储在磁盘的情况。适用的场合使进程间通信。使用内存的时候Parcelable性能更高。

java的垃圾回收机制

Java的一个重要有点就是通过垃圾收集器GC自动管理内存回收,程序员不需要通过调用函数释放内存。但是并不是说java就不存在内存泄露。虽然简化了程序员的工作,但同时也加重了jvm的工作,这也是Java程序运行速度较慢的原因之一。因为,gc为了能够正确释放对象,gc必须监控每一个对象的运行状态,包括对象的申请、被引用、引用、赋值等,gc都需要进行监控。
从几个方面来说:

1.什么时候回收?

a.在cpu空闲的时候
b.在堆内存满了的时候
c.system.gc()调用的时候尝试回收

2.怎么判断对象可以被回收

java和c#都是使用根搜索算法(GC Roots Tracing)判断的。这个算法的基本思路就是通过一系列名为“GC Roots”的对象作为起点,从这些几点开始向下搜索,搜索所走过的路径成为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。

九. Activity的窗口机制

每个activity含有一个phoneWindow对象,phonewindow中含有DecorView。phoneWindow是Activity和DecorView的桥梁。DecorView只有一个LinerLayout的子view。包含通知栏,标题栏,内容栏。setContentView就是将xml的view添加到内容栏位置。

事件分发:Activity接到事件后,会传到Window对象中,window再将事件传递给DeocrView,Decorview传给它唯一的子View,一个ViewGroup,然后递归传递下去。

你可能感兴趣的:(知识点总结)