自定义view与view绘制时大小的确定
- viewGroup
- 需要重写的方法
- onMeasure:用于计算childView的测量值以及模式,从而计算设置自己的宽高
- onLayout: 设置所有childView的显示位置
- 整体流程小结
onMeasure会传递该viewGroup的父viewGroup的MeasureSpec(即父viewGroup的建议测量模式与测量尺寸,在重写onMeasure方法时,先调用measureChildren计算出所有childView的尺寸,然后变了所有childView获取到尺寸,再结合父viewGroup的建议测量模式与尺寸以及自己的业务需求设置setMeasuredDimension,这样就确定了viewGroup的尺寸。可以知道,viewGroup并不是绝对由谁去确定的,可以根据自己的业务需求动态设置)
- 需要重写的方法
- view
- 需要重写的方法
- onMeasure:根据父viewGroup的建议测量模式与测量尺寸,计算设置自己的宽高
- onDraw: 绘制view
- 需要重写的方法
内存抖动出现的原因
- 指在短时间内有大量的对象被创建或者被回收的现象。
- 内存抖动产生原因:频繁(如在循环里)创建对象,会导致垃圾回收机制频繁运行。
- 内存抖动影响:频繁内存抖动会导致垃圾回收频繁运行,造成系统卡顿
cpu优化的处理
可以通过as的Profiler查看cpu使用率
gc是什么时候触发的
- 新生代触发:Eden区中没有足够空间进行分配时,将会触发一次Minor GC
- 老年代触发:老年代空间不足,JVM会进行Major GC,如果Major GC完后空间还是不足,就会抛出java.lang.OutOfMemoryError: Java heap space异常
- 方法区空间不足触发:(方法区有些人又称为“永久代”),JVM会进行Major GC,如果Major GC完后空间还是不足,就会抛出java.lang.OutOfMemoryError: PermGen space异常
- 调用System.gc()方法触发:System.gc()会建议JVM进行Major GC,因为是建议并不一定会进行,但是大多数情况下还是会进行Major GC,强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc()
hander里面的delay消息是怎么实现的
- 插入消息机制:post(Runnable r)方法最终还是调用到sendMessageDelayed最终还是调用方法sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)。这个方法将传递了消息和消息要执行的时刻,然后调用插入enqueueMessage到消息队列中。消息队列的消息是根据时刻排序的链表,插入也是根据这个逻辑插入。
- 读取消息机制:looper循环读取消息获取下一个消息,实际是类似于线程的休眠。插入消息时重新唤醒计算并插入,循环处理时,获取到下一个消息后,如果不需要休眠就立即处理,如果需要休眠,然后执行休眠到下次唤醒重新循环执行一次这个过程。休眠使用的是linux中的epoll机制,具体是调用了epoll_wait这个方法
looper为啥不会堵塞主线程
阻塞在epoll wait,并不是for的死循环等待,并不占用CPU资源。另外主线程的looper,它才行ui消息处理的根本,它一直在等待并处理消息的。
线程、Handler跟Looper之间的对应关系
一个线程可以创建多个Handler,但只能创建一个Looper,一个MessageQueue。Handler跟Looper之间没有对应关系。比如在一个activity中可以创建多个handler,它都是用了默认的looper与MessageQueue,handler发的消息最终还是回调到对应的handler处理。
handler为啥设计使用obtainMessage方法
可以避免重复创建Message对象。首先可以节省了内存,适合频繁发送的同个消息。
handler发送大量消息会有什么问题
这是我的猜想:插入的过程是加了锁的,当消息队列里有大量延迟消息,同时大量消息堵塞着等待插入,有可能出现anr。
handler主线程更新的原理是什么
简单说Handler用于同一个进程的线程间通信。Looper让主线程无限循环地从自己的MessageQueue拿出消息处理,既然这样我们就知道处理消息肯定是在主线程中处理的,那么怎样在其他的线程往主线程的队列里放入消息呢?其实很简单,我们知道在同一进程中线程和线程之间资源是共享的,也就是对于任何变量在任何线程都是可以访问和修改的,只要考虑并发性做好同步就行了,那么只要拿到MessageQueue 的实例,就可以往主线程的MessageQueue放入消息,主线程在轮询的时候就会在主线程处理这个消息。那么怎么拿到主线程 MessageQueue的实例,是可以拿到的(在主线程下mLooper = Looper.myLooper();mQueue = mLooper.mQueue;),
okhttp的实现原理
整个OkHttp功能的实现就在这五个默认的拦截器中,所以先理解拦截器模式的工作机制是先决条件。这五个拦截器分别为: 重试拦截器、桥接拦截器、缓存拦截器、连接拦截器、请求服务拦截器。每一个拦截器负责的工作不一样,就好像工厂流水线,最终经过这五道工序,就完成了最终的产品。
但是与流水线不同的是,OkHttp中的拦截器每次发起请求都会在交给下一个拦截器之前干一些事情,在获得了结果之后又干一些事情。整个过程在请求向是顺序的,而响应向则是逆序。
当用户发起一个请求后,会由任务分发起Dispatcher将请求包装并交给重试拦截器处理。
1、重试拦截器在交出(交给下一个拦截器)之前,负责判断用户是否取消了请求;在获得了结果之后,会根据响应码判断是否需要重定向,如果满足条件那么就会重启执行所有拦截器。
2、桥接拦截器在交出之前,负责将HTTP协议必备的请求头加入其中(如:Host)并添加一些默认的行为(如:GZIP压缩);在获得了结果后,调用保存cookie接口并解析GZIP数据。
3、缓存拦截器顾名思义,交出之前读取并判断是否使用缓存;获得结果后判断是否缓存。
4、连接拦截器在交出之前,负责找到或者新建一个连接,并获得对应的socket流;在获得结果后不进行额外的处理。
5、请求服务器拦截器进行真正的与服务器的通信,向服务器发送数据,解析读取的响应数据。
在经过了这一系列的流程后,就完成了一次HTTP请求!
okhttp的缓存机制是怎么实现的
线程的sleep与wait有什么区别
-
属于不同的两个类,sleep()方法是线程类(Thread)的静态方法,wait()方法是Object类里的方法。
-
sleep()方法不会释放锁,wait()方法释放对象锁。
-
sleep()方法可以在任何地方使用,wait()方法则只能在同步方法或同步块中使用。
-
sleep()必须捕获异常,wait()方法、notify()方法和notiftAll()方法不需要捕获异常。
-
sleep()使线程进入阻塞状态(线程睡眠),wait()方法使线程进入等待队列(线程挂起),也就是阻塞类别不同。
-
它们都可以被interrupted方法中断。
Android中的多线程开发
- new thread
- AsyncTask
- 线程池
synchronized与lock的区别
如何理解Android中的xmlns
英文叫做 XML namespace,中文翻译为 XML 命名bai空间。
在Android中,目前我们碰到的xmlns一共有三种:
- xmlns:android=“http://schemas.android.com/apk/res/android”。android:命名空间android用于 Android 系统定义的一些属性
- xmlns:tools=“http://schemas.android.com/tools”。tools:根据官方定义,tools命名空间用于在 XML 文档记录一些,当应用打包的时候,会把这部分信息给过滤掉,不会增加应用的 size,说直白点,这些属性是为IDE提供相关信息.
- xmlns:app=“http://schemas.android.com/apk/res-auto” 。app:命名空间app用于我们应用自定义的一些属性
Android-Service概念和用途
service的意义
- Activity能看见,service看不见。打个比方,比如你要 启动一个推送的服务,并且后台维持,acitivity显然不合适
- 比如你做个上传功能,如果放到Activity里面,用户一结束Activity(比如那种一键清理),你的上传就挂了,就需要用Service
线程会不会随着activity的结束而结束
不会的 所以理论上 最好在service中去开启线程 好控制线程的生命周期 但实际开发中 大多都直接在activity new Thread
handler内测泄露的原因
Handler对象隐性地持有了Activity的对象。当handler延迟发送信息时,而在activity跳转之后就出现内存没有回收,导致内存泄漏
图片占据的内存算法
https://www.cnblogs.com/dasusu/p/9789389.html
IM即时通讯部分概念理解
getSystemService过程及后续流程是怎么样的
【Android源码解析–SystemServer启动流程】
as打包过程过程做了什么
什么是依赖倒置
- 高层模块不应该依赖低层模块,两者都应该依赖其抽象
- 抽象不应该依赖细节
- 细节应该依赖抽象
下面是依赖倒置原则在Java语言中的表现:
- 模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的
- 接口或抽象类不依赖于实现类
- 实现类依赖于接口或抽象类
数据加密的做法
- https方式。Android下面如何使用
- 对称加密(根据版本更新秘钥)、md5校验是否篡改数据
代码混淆如何做
常见使用ProGuard
组件化插件化是什么
从桌面启动一个应用,整个流程是怎么样的
jetpack组件了解
根搜索算法的根是什么
在Java语言中,可以作为GCRoots的对象包括下面几种:
-
(1). 虚拟机栈(栈帧中的局部变量区,也叫做局部变量表)中引用的对象。
-
(2). 方法区中的类静态属性引用的对象。
-
(3). 方法区中常量引用的对象。
-
(4). 本地方法栈中JNI(Native方法)引用的对象。
Touch事件如何传递到Activity
ctivity里面有个PhoneWindow,PhoneWindow里面有个DecorView,而DecorView的parent是ViewRootImpl,所以Activity的很多方法调用都是从ViewRootImpl开始的
单例模式双重锁定深入了解下,第一锁第二锁用处
双重校验锁第一次进行判空原因:当程序顺序执行的时候,如果不进行判空,每一个线程都会先去获得当前类的类锁,而其他线程都进入阻塞状态。单例模式中初始化单例的程序只会执行一次,大部分情况下会直接到return语句返回,如果都阻塞在获取锁的位置,会大大降低程序的运行速度双重校验锁第二次进行判空原因:假设有两个线程A和B,都进行完第一次判空了,A和B都阻塞,这个时候A线程获取了类锁,然后B线程被阻塞,A线程新建了一个实例后释放了锁,B线程获取锁,又新建了一个实例,这破坏了单例设计模式的初衷
Android内存优化
构造单例的时候尽量别用Activity的引用;
静态引用时注意应用对象的置空或者少用静态引用;
使用静态内部类+软引用代替非静态内部类;
及时取消广播或者观察者注册;
耗时任务、属性动画在Activity销毁时记得cancel;
文件流、Cursor等资源及时关闭;
Activity销毁时WebView的移除和销毁。
内存泄露检测
getWidth与getMeasuredWidth的区别
- getWidth是view的显示宽度,由绘制view的 mRight 、 mLeft确定。onLayout方法后
public final int getWidth() {
return mRight - mLeft;
}
- getMeasuredWidth是测量宽度,由measure方法后确定。onMeasure方法后
public final int getMeasuredWidth() {
return mMeasuredWidth & MEASURED_SIZE_MASK;
}
可知,如果内容超出屏幕而且可以滑动显示,那么view的测量宽度是比显示宽度大的。一般情况下两个值是一样的,MeasureSpec.UNSPECIFIED(如NestedScrollView子view的测量模式强行设置为这个模式)情况下才有超出父类控件限制大小