android 面试知识点

  1. Handle 原理

消息机制主要包含:MessageQueue,Handler和Looper这三大部分,以及Message

Message:需要传递的消息,可以传递数据;

MessageQueue:消息队列,但是它的内部实现并不是用的队列,实际上是通过一个单链表的数据结构来维护消息列表,因为单链表在插入和删除上比较有优势。主要功能向消息池投递消息(MessageQueue.enqueueMessage)和取走消息池的消息(MessageQueue.next);

Handler:消息辅助类,主要功能向消息池发送各种消息事件(Handler.sendMessage)和处理相应消息事件(Handler.handleMessage);

Looper:不断循环执行(Looper.loop),从MessageQueue中读取消息,按分发机制将消息分发给目标处理者。

消息机制的运行流程:创建消息队列,循环获取消息,发送消息,分发处理信息

在子线程执行完耗时操作,当Handler发送消息时,将会调用MessageQueue.enqueueMessage,向消息队列中添加消息。当通过Looper.loop开启循环后,会不断地从线程池中读取消息,即调用MessageQueue.next,然后调用目标Handler(即发送该消息的Handler)的dispatchMessage方法传递消息,然后返回到Handler所在线程,目标Handler收到消息,调用handleMessage方法,接收消息,处理消息。

 

  1. Android 事件分发机制

onTouch() 方法优先级高于 onTouchEvent(event) 方法

遵从 Activity => ViewGroup => View 的顺序进行事件分发,然后通过调用 onTouchEvent() 方法进行事件的处理。

Activity的onUserInteraction方法的作用是当触屏点击按home,back,menu键等都会触发此方法。

从顶层窗口Decter =>PhoneWindow=>Activity=>ViewGroup=>View进行事件分发,

因为Activity为应用顶层窗口,所以没有onInterceptTouchEvent 方法,当点击事件传递到ViewGroup中时,会调用ViewGroup onInterceptTouchEvent方法,如果onInterceptTouchEvent方法的intercept(拦截) 返回true,则ViewGroup消费该点击事件,如果返回为false,则继续向子View传递,如果子 View消费,事件分发结束,不消费,

 

1.当onInterceptTouchEvent返回ture时,若onTouchEvent返回true,后续事件将不再经过该ViewGroup的onInterceptTouchEvent方法,直接交由该ViewGroup的onTouchEvent方法处理;若onTouchEvent方法返回false,后续事件都将交由父ViewGroup处理,不再经过该ViewGroup的onInterceptTouchEvent方法和onTouchEvent方法。

2.当onInterceptTouchEvent返回false时,事件继续向子View分发;

3.对于子View,当onTouchEvent返回true,父ViewGroup派发过来的touch事件已被该View消费,后续事件不会再向上传递给父ViewGroup,后续的touch事件都将继续传递给子View。

4.对于子View,onTouchEvent返回false,表明该View并不消费父ViewGroup传递来的down事件,而是向上传递给父ViewGroup来处理;后续的move、up等事件将不再传递给该View,直接由父ViewGroup处理掉。

5.onTouch先于onTouchEvent调用,onClick事件是在onTouchEvent中ACTION_UP中触发的。

  1. Android View 绘制流程

ent调用,on

  1. Binder 多进程AIDL
  2.  

 

传统linux IPC 机制

 

 

Android Binder IPC 机制中涉及到的内存映射通过 mmap() 来实现,mmap() 是操作系统中一种内存映射的方法。将用户空间的一块内存区域映射到内核空间。映射关系建立后,用户对这块内存区域的修改可以直接反应到内核空间;反之内核空间对这段区域的修改也能直接反应到用户空间。

一次完整的 Binder IPC 通信过程通常是这样:

  1. 首先 Binder 驱动在内核空间创建一个数据接收缓存区;
  2. 接着在内核空间开辟一块内核缓存区,建立内核缓存区和内核中数据接收缓存区之间的映射关系,以及内核中数据接收缓存区和接收进程用户空间地址的映射关系;
  3. 发送方进程通过系统调用 copyfromuser() 将数据 copy 到内核中的内核缓存区,由于内核缓存区和接收进程的用户空间存在内存映射,因此也就相当于把数据发送到了接收进程的用户空间,这样便完成了一次进程间的通信。

 Binder 通信过程:

  1. 首先,一个进程使用 BINDERSETCONTEXT_MGR 命令通过 Binder 驱动将自己注册成为 ServiceManager;
  2. Server 通过驱动向 ServiceManager 中注册 Binder(Server 中的 Binder 实体),表明可以对外提供服务。驱动为这个 Binder 创建位于内核中的实体节点以及 ServiceManager 对实体的引用,将名字以及新建的引用打包传给 ServiceManager,ServiceManger 将其填入查找表。
  3. Client 通过名字,在 Binder 驱动的帮助下从 ServiceManager 中获取到对 Binder 实体的引用,通过这个引用就能实现和 Server 进程的通信。
  4.  

 

 

各JAVA类职责描述

IBinder : IBinder 是一个接口,代表了一种跨进程通信的能力。只要实现了这个借口,这个对象就能跨进程传输。

IInterface : IInterface 代表的就是 Server 进程对象具备什么样的能力(能提供哪些方法,其实对应的就是 AIDL 文件中定义的接口)

Binder : Java 层的 Binder 类,代表的其实就是 Binder 本地对象。BinderProxy 类是 Binder 类的一个内部类,它代表远程进程的 Binder 对象的本地代理;这两个类都继承自 IBinder, 因而都具有跨进程传输的能力;实际上,在跨越进程的时候,Binder 驱动会自动完成这两个对象的转换。

Stub : AIDL 的时候,编译工具会给我们生成一个名为 Stub 的静态内部类;这个类继承了 Binder, 说明它是一个 Binder 本地对象,它实现了 IInterface 接口,表明它具有 Server 承诺给 Client 的能力;Stub 是一个抽象类,具体的 IInterface 的相关实现需要开发者自己实现。

  1. Android 屏幕适配

采用今日头条适配方案

https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/README-CN.md

 

  1. Android Windows 、Activity、ViewRoot、DecorVeiw的关系

Activity就像个控制器,不负责视图部分。Window像个承载器,装着内部视图。DecorView就是个顶层视图,是所有View的最外层布局。ViewRoot像个连接器,负责沟通,通过硬件的感知来通知视图,进行用户之间的交互。

 

  1. Android 布局优化之ViewStub、include、merge
    1. Include 使用注意

一个xml布局文件有多个include标签需要设置ID,才能找到相应子View的控件,否则只能找到第一个include的layout布局,以及该布局的控件

include标签如果使用layout_xx属性,会覆盖被include的xml文件根节点对应的layout_xx属性,建议在include标签调用的布局设置好宽高位置,防止不必要的bug

include 添加id,会覆盖被include的xml文件根节点ID,这里建议include和被include覆盖的xml文件根节点设置同名的ID,不然有可能会报空指针异常

如果要在include标签下使用RelativeLayout,如layout_margin等其他属性,记得要同时设置layout_width和layout_height,不然其它属性会没反应

b) Merge标签

merge标签主要用于辅助include标签,在使用include后可能导致布局嵌套过多,多余的layout节点或导致解析变慢

使用场景:

1、根布局是FrameLayout且不需要设置background或padding等属性,可以用merge代替,因为Activity的ContentView父元素就是FrameLayout,所以可以用merge消除只剩一个.

2、某布局作为子布局被其他布局include时,使用merge当作该布局的顶节点,这样在被引入时顶结点会自动被忽略,而将其子节点全部合并到主布局中.

3、自定义View如果继承LinearLayout(ViewGroup),建议让自定义View的布局文件根布局设置成merge,这样能少一层结点.

使用注意:

  1. 因为merge标签并不是View,所以在通过LayoutInflate.inflate()方法渲染的时候,第二个参数必须指定一个父容器,且第三个参数必须为true,也就是必须为merge下的视图指定一个父亲节点.
  2. 因为merge不是View,所以对merge标签设置的所有属性都是无效的.
  3. 注意如果include的layout用了merge,调用include的根布局也使用了merge标签,那么就失去布局的属性了
  4. merge标签必须使用在根布局
  5. ViewStub标签中的layout布局不能使用merge标签
    1. ViewStub

ViewStub 标签最大的优点是当你需要时才会加载,使用它并不会影响UI初始化时的性能.各种不常用的布局像进度条、显示错误消息等可以使用ViewStub标签,以减少内存使用量,加快渲染速度.ViewStub是一个不可见的,实际上是把宽高设置为0的View.效果有点类似普通的view.setVisible(),但性能体验提高不少

使用注意:

  1. ViewStub标签不支持merge标签
  2. ViewStub的inflate只能被调用一次,第二次调用会抛出异常,setVisibility可以被调用多次,但不建议这么做(ViewStub 调用过后,可能被GC掉,再调用setVisibility()会报异常)
  3. 为ViewStub赋值的android:layout_XX属性会替换待加载布局文件的根节点对应的属性

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值