当前位置:首页>科技>万字长文新手入门教程文章硬不硬核你说了算
发布时间:2026-07-21阅读(1)
短短几个月,看着越来越多的读者通过我写的文章而关注公众号,我好开心,同时也诚惶诚恐,害怕无法持续输出高质量文章,让读者失望。但我知道,只有写出让读者心动的文章,才能得其心,会好好加油,为大家持续输出精品文章的。
本文分享Framework相关内容,提纲如下:

私信:Framework
一丶Framework通信1.1.Android Binder进程隔离:
内核空间中存放的是内核代码和数据,而进程的用户空间中存放的是用户程序的代码和数据 为了保证系统的安全,用户空间和内核空间是天然隔离的 每个进程有自己的虚拟内存空间,为了安全,每个进程只能操作自己的虚拟内存空间,只有操作系统才有权限操作物理内存空间
为什么要用Binder?

Binder的一次拷贝发生在用户空间拷贝到内核空间;
用户空间: App进程运行的内存空间;
内核空间: 系统驱动、和硬件相关的代码运行的内存空间,也就是进程ID为0的进程运行的空间;
程序局部性原则: 只加载少量代码;应用没有运行的代码放在磁盘中,运行时高速缓冲区进行加载要运行的代码;默认一次加载一个页(4K),若不够4K就用0补齐;
MMU:内存管理单元;
给CPU提供虚拟地址;
当对变量操作赋值时:
物理地址: 物理内存的实际地址,并不是磁盘;
虚拟地址: MMU根据物理内存的实际地址翻译出的虚拟地址;提供给CPU使用;


页命中:CPU读取变量时,MMU在物理内存的页表中找到了这个地址;
页未命中:CPU读取变量时,MMU在物理内存的页表中没有找到了这个地址,此时会触发MMU去磁盘读取变量并存到物理内存中;
普通的二次拷贝:
应用A拷贝到服务端:coay_from_user
从服务端拷贝到应用B:coay_to_user
mmap():
共享内存进程通信:
Binder通信原理:
角色:Server端A、Client端B、Binder驱动、内核空间、物理内存

Activity跳转时,最多携带1M-8k(1兆减去8K)的数据量;
真实数据大小为:1M内存-两页的请求头数据=1M-8K;
应用A直接将数据拷贝到应用B的物理内存空间中,数据量不能超过1M-8K;拷贝次数少了一次,少了从服务端拷贝到用户;
IPC通信机制:
以下为简单的主进程和子进程通信:
1、服务注册: 缓存中心中有三张表(暂时理解为三个HashMap,Binder用的是native的红黑树):
类的方法集合:key-value;
key:方法签名:“方法名” 有参数时用 “方法名-参数类型-参数类型-参数类型......”;
value: 方法本身;
注册后,服务若没被调用则一直处于沉默状态,不会占用内存,这种情况只是指用户进程里自己创建的服务,不适用于AMS这种;
2、服务发现: 当被查询到时,要被初始化;
3、服务调用:
AIDL: BpBinder:数据发送角色 BbBinder:数据接收角色

编译器生成的AIDL的java接口.Stub.proxy.transact()为数据发送处;
发送的数据包含:数据 方法code 方法参数等等;
请求头:包含了目的进程、大小等等参数,这些参数占了8K
编译器生成的AIDL的java接口.Stub.onTransact()为数据接收处;
Binder中的IPC机制:
ServiceManager维持了Binder这套通信框架;
1.2.Android handlerHandler、Message、MessageQueue、Looper;
以下为零散的记录,最后有总结; 内存泄露的本质:
长生命周期对象持有短生命周期对象,导致短生命周期对象销毁不掉;
持有链:
线程>>Looper>>MessageQueue>>Message>>Handler>>Activity;
Message对象的变量target为发送消息的Handler; MessageQueue 队列里放Message; Looper对象里实例化MessageQueue; 一个线程绑定一个Looper;
为什么要有handler? 主要目的是要解决线程切换问题,handler里的Message机制解决了线程间通信;
为什么有队列MessageQueue? MessageQueue是一个单向链表,next()调用nativePollOnce->lunx的epoll_wait()等待实现阻塞时队列;
队列的出现解决了"处理消息"阻塞到"发送消息"的问题;
队列是生产者消费者模式;
而要使用队列需要至少两个线程、和一个死循环;
为什么有Looper?
为了循环取出队列里的消息;
一个线程有几个Looper,为什么不会有多个?
一个线程一个Looper,放在ThreadLocalmap中;
假如Looper对象由Handler创建,每创建一个Handler就有一个Looper,那么调用Looper.loop()时开启死循环;在外边调用Looper的地方就会阻塞;

主线程中Looper的死循环为什么没有导致系统卡死?
获取当前线程:Thread.currentThread();
ThreadLocalMap:类似于HashMap;
每个Thread对象都有一个对应的ThreadLocalMap;

在Looper.prepare()时,存入Looper,存Looper时ThreadLocalMap的key为ThreadLocal,value为Looper;


内存抖动根本的解决方式是复用;
handler.obtainMessage();
Linux函数: epoll_create:App注册进红黑树中,拿到一个事件fd的值; epoll_ctl:注册事件类型,监听fd是否改变(Linux中事件都会被写入文件中,如触摸屏幕事件会写入到:dev/input/event0文件中),fd有改变时唤醒epoll_wait; epoll_wait:有事件时就分发,没事件就阻塞

总结: handler如何做的线程切换的? 首先Handler的使用步骤:
在第一步时,创建一个Looper,并放到当前线程的变量threadLocals中;threadLocals是一个map,key为ThreadLocal对象本身,value为Looper;在Looper.loop()时取出;

第二步,用户在当前线程(可能是子线程)创建Handler对象;
第三步,Looper.loop()一直在死循环,Looper.loop()这句代码下面的代码是不会被调用的,调用Looper.loop()函数时,先从当前线程的map变量中取出Looper,再从Looper中拿到队列MessageQueue,for循环中不断从队列中取出消息;

第四步,在其他线程调用handelr发送消息时,Message里有个target,就是发送消息的handler;

在Looper.loop()时,队列中取到消息时,调用msg.target.dispatchMessage(msg);其实就是handler对象.dispatchMessage(msg);

所以不论在哪个线程调用发送消息,都会调用到handler自己分发消息;而handler所处的线程是创建时的“当前线程”,所以处理时也就回到了“当前线程”;实现了线程切换,和线程通信;
Looper的死循环为什么不会让主线程卡死(或ANR)? 简单版:
详细:
子线程的Looper和子线程Looper有什么不同?
子线程Looper是可以退出的,主线程不行;
1.3.Jetpack之LiveData订阅与数据分发使用:
public class LiveDataActivity extends AppCompatActivity { MutableLiveData liveData= new MutableLiveData<String>(); void liveDataTest(){ // 任何线程都可以发送数据 liveData.postValue("postValue"); // 只有主线程可以发送数据 // liveData.setValue("setValue") } void observeTest(){ //订阅 liveData.observe(this, new Observer<String>() { @Override public void onChanged(String data) { //收到数据data } }); //可以有多个订阅 liveData.observe(this, new Observer<String>() { @Override public void onChanged(String data) { //收到数据data } }); }}
阶段一:
postValue:
protected void postValue(T value) { boolean postTask; synchronized (mDataLock) { postTask = mPendingData == NOT_SET; mPendingData = value; } if (!postTask) { return; } ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable); }
mPostValueRunnable:
volatile Object mPendingData = NOT_SET; private int mVersion; private final Runnable mPostValueRunnable = new Runnable() { @SuppressWarnings("unchecked") @Override public void run() { Object newValue; synchronized (mDataLock) { newValue = mPendingData; mPendingData = NOT_SET; } setValue((T) newValue); } };
setValue:
private volatile Object mData; private int mVersion; @MainThread protected void setValue(T value) { assertMainThread("setValue"); mVersion ; mData = value; dispatchingValue(null); }
看到这里发现,数据其实最后存到了mData中;若想发送订阅消息,肯定得添加订阅者;
阶段二:
添加订阅者,observe():
//用户使用: //liveData.observe(this@LiveDataActivity,{ // //}) private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = new SafeIterableMap<>(); @MainThread public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { assertMainThread("observe"); //如果被观察者的生命周期是DESTROYED,就不添加订阅者 if (owner.getLifecycle().getCurrentState() == DESTROYED) { // ignore return; } LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); ... owner.getLifecycle().addObserver(wrapper); }
LifecycleBoundObserver及它的父类ObserverWrapper:
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver { @NonNull final LifecycleOwner mOwner; LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) { super(observer); mOwner = owner; } ... @Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState(); if (currentState == DESTROYED) { removeObserver(mObserver); return; } Lifecycle.State prevState = null; while (prevState != currentState) { prevState = currentState; activeStateChanged(shouldBeActive()); currentState = mOwner.getLifecycle().getCurrentState(); } } ... @Override void detachObserver() { mOwner.getLifecycle().removeObserver(this); } } //ObserverWrapper private abstract class ObserverWrapper { //传进来的观察者放这里了 final Observer<? super T> mObserver; boolean mActive; int mLastVersion = START_VERSION; ObserverWrapper(Observer<? super T> observer) { mObserver = observer; } ... void activeStateChanged(boolean newActive) { if (newActive == mActive) { return; } mActive = newActive; changeActiveCounter(mActive ? 1 : -1); if (mActive) { dispatchingValue(this); } } }
阶段三:
分发:
在阶段一setValue()时,调用了dispatchingValue(null);
void dispatchingValue(@Nullable ObserverWrapper initiator) { if (mDispatchingValue) { mDispatchInvalidated = true; return; } mDispatchingValue = true; do { mDispatchInvalidated = false; if (initiator != null) { considerNotify(initiator); initiator = null; } else { for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator = mObservers.iteratorWithAdditions(); iterator.hasNext(); ) { considerNotify(iterator.next().getValue()); if (mDispatchInvalidated) { break; } } } } while (mDispatchInvalidated); mDispatchingValue = false; } private void considerNotify(ObserverWrapper observer) { if (!observer.mActive) { return; } ... if (observer.mLastVersion >= mVersion) { return; } observer.mLastVersion = mVersion; observer.mObserver.onChanged((T) mData); }
APP的启动到绘制过程中,AMS源码核心应用方案AMS(ActivityManagerService) 在SystemServer的进程中,是SystemServer中的一个对象;
作用:
AMS->PMS:

ActivityThread
ActivityThread中重要的对象:
点击桌面App图标发生了什么?
下图中4-5中少了上面7-23的步骤:
7-15创建并启动了Application;
16-22创建并启动了Activity;

应用内activity与activity的跳转是跨进程通信,还是同一个进程内通信?
是跨进程通信;
跳转流程参考上面的:省去了application的创建过程;
步骤3 步骤16-23;
2.2.Android Framework源码-PMSFramework面试必问三:Zygote,AMS,PMS连环炮SystemServer: Android一切服务的启动者;
ps:SystemManager: 是SystemServer的叔叔,SystemServer把所有服务都交给了SystemManager管理;
PMS(PackageManagerService): 在SystemServer的进程中,是SystemServer中的一个对象;
有一个缓存中心:mPackages;是一个Map,key为应用的包名,value为每个应用的Package;
在手机启动的时候,做了三件事,且只做一次:
作用:只解析每个Apk中的AndroidMnifest.xml中的信息,而不是去解析节点中每个xxxActivity.java文件;解析到的信息缓存到mPackages中,相当于“注册表”,方便之后AMS快速定位到相应的APP;

解析AndroidMnifest.xml流程:
Linux事件机制:
事件都是储存在文件中;
如触摸屏幕事件:存储在dev/input/event0的文件中,每次触摸都会以16进制数据储存;

INotify:监听文件状态,有变化则产生FD值
epoll机制:
epoll_create:注册监听事件类型
epoll_ctl:监听FD值,FD改变则唤醒epoll_wait()
epoll_wait:没事件则阻塞,有事件则分发;
将INotify和epoll封装为一个对象EventHub;

SystemServer进程启动时,创建了InputManagerService服务,这个IMS在native层创建了InputManager对象;
InputManager里有一个对象EventHub;
同时InputManager里面又开启了两个线程:
InputReaderThread:不断去读取EventHub里的事件;有事件时把数据封装后添加到队列,立马从队列里读取交给InputDispatcher进行分发;
InputDispatcherThread:InputDispatcher里面保存了wms中所有的window信息(wms会将window信息实时更新到InputDispatcher中),InputDispatcher就可以将事件分发给对应合适的window;
App进程中的ViewRootImpl和SystemServer中的IMS通过socketpair通信,因为事件产生的非常快且非常多使用binder通信不适合

在ViewRootImpl中setView后new了一个监听FD文件的回调,new WindowInputEventReceiver();
在回调中,底层使用epoll_ctl()函数监听FD是否变化,有变化则会回调至java层,dispatchInputEvent();
这里就是Activity-》Viewgroup->View的事件分发前置;
底层事件信号传递总结:

主角:ViewRootImpl、Choreographer、Surfaceflinfer
WMS扮演了什么角色?
作为协调者,协调view布局,绘制;
setContentView()
ps:这里递归调用,若嵌套层级太多,会导致栈溢出;因为递归调用不会释放栈;
ViewRootImpl 单例,管理所有View的绘制策略;
注意onCreate.setContentView后view数据已解析并实例化了;
帧速率: CPU/GPU出图速率;
刷新率: 屏幕刷新速率;
Vsync: 垂直同步绘制信号; 因可能硬件帧速率和刷新率不一致,用来同步刷新的问题;
Choreographer编舞者: 负责管理帧率节奏;

真正的绘制: ViewRootImpl.performTraversals()
在performDraw()中:

简单版总结: Activity.setContentView(R.layout.resId):
解析xml并实例化;
绘制发生时间: 在AMS回调ActivityThread中的handleResumeActivity时,也就是Resume时,而不是onCreate();
Android的事件处理的三种方法:
1、基于监听的事件处理机制
setOnClickListener,setOnLongClickListener、setOnTouchListener
注意:如果onTouchEvent方法return true,则单击事件和长摁事件不再执行;若onLongClick方法返回true,则单击事件不再处理。
2、基于回调的事件处理机制
需要定义继承组件的类,重写回调方法Touch方法执行时,先被Activity捕获,DispatchTouchEvent方法处理。return false,交给上层的onTouchEvent方法处理;return super.dispatchTouchEvent(ev),则传递给最外层的View。
View用Dispatch方法处理,return false,由上层的onTouchEvent方法处理。如果返回super.dispatchTouchEvent(ev),则本层的onInterceptTouchEvent拦截,如果拦截true,则拦截,false不拦截,传递给子View的DispatchTouchEvent处理。
常用的回调方法:onKeyDown,onKeyLongPress,onKeyUp,onTouchEvent,onTrackballEvent(轨迹球事件)监听和回调同时存在时,先调用监听。
3.1.2.Android基于监听基于监听的时间处理机制模型
流程模型图

监听三要素:
Event source 事件源 Event 事件 Event Listener 事件监听器 下面我们来看一下点击事件和触摸事件的监听三要素具体是那部分:


归纳:
事件监听机制是一种委派式的事件处理机制,事件源(组件)事件处理委托给事件监听器 当事件源发生指定事件时,就通知指定事件监听器,执行相应的操作
常⽤监听接⼝
View.OnClickListener 单击事件监听器必须实现的接⼝ View.OnCreateContextMenuListener 创建上下⽂菜单事件 View.OnFocusChangeListener 焦点改变事件 View.OnKeyListener 按键事件监听器 View.OnLongClickListener 长按事件监听器 View.OnTouchListener 触摸屏事件监听器
⾸先,事件监听机制中由事件源,事件,事件监听器三类对象组成。
事件监听器处理流程:
为事件源(例如:button)设置⼀个监听器,⽤于监听⽤户的操作(点击操作等)⽤户做出的操作触发事件源的监听器⾃动⽣成对应的事件对象将事件源对象作为参数传给事件监听器事件监听器对事件对象进⾏判断,执⾏对应的事件处理器(处理⽅法)在此以OnClickListener单击事件为例使用intent来实现页面的跳转
内部类形式实现监听
<TextView//id值 android: android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="内部类" android:gravity="center" android:textSize="20dp" android:textColor="#fff"/>public class MainActivity extends AppCompatActivity{//定义一个TextView对象 private TextView textView2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);//获得事件源 textView = findViewById(R.id.test2);//确定事件为点击事件,绑定监听器到事件源 textView.setOnClickListener(new myListener()); } //内部类实现页面跳转 private class myListener implements View.OnClickListener { @Override public void onClick(View v) { //采用显示Intent启动第二个页面startActivity(new Intent(MainActivity.this,internalActivity.class)); } }}匿名内部类实现
<TextView android: android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="匿名内部类" android:gravity="center" android:textSize="20dp" android:textColor="#fff"/>public class MainActivity extends AppCompatActivity { private TextView textView1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);//获得事件源 textView1 = findViewById(R.id.test3); //匿名内部类实现跳转 (实现监听器,绑定监听器到事件源要同步进行) textView1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) { startActivity(new Intent(MainActivity.this,anonymousActivity.class));} }); }}类本身实现监听器
<TextView android: android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="类本身打开浏览器" android:gravity="center" android:textSize="20dp" android:textColor="@color/colorWhite"/>public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private TextView textView2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //获得事件源 textView2 = findViewById(R.id.test4); //绑定监听器到事件源 textView2.setOnClickListener(this); }//类本身实现 浏览器跳转 @Override public void onClick(View v) { switch (v.getId()){case R.id.test4://采用隐式intent Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setData(Uri.parse("http://www.baidu.com")); startActivity(intent); break; } }}本节给大家介绍了Android中的事件处理机制,例子中的是onClickListener点击事件,当然除了这个以外还有其他的事件,比如onItemClickListener,凡是需要通过setXxxListener这些,基本上都是基于事件监听的!
3.1.3.Android基于回调回调事件处理原理
监听事件处理是事件源与事件监听器分开的而基于回调的事件处理UI组件不但是事件源,而且还是事件监听器,通过组件的相关回调方法处理对应的事件。
回调事件应用步骤
Ⅰ. 自定义View类,继承自需要的View UI类。ex :自定义 MyButton按钮类 extends 基础Button类
Ⅱ. 复写回调函数。ex:public boolean onTouchEvent(MotionEvent event)
每一个事件回调方法都会返回一个boolean值,①.如果返回true:表示该事件已被处理,不再继续向外扩散,②.如果返回false:表示事件继续向外扩散
而说到基于回调就离不开监听机制。
回调机制与监听机制的区别:
如果说事件监听机制是⼀种委托式的事件处理,那么回调机制则恰好与之相反:对于基于回调机制的事件处理模型来说,事件源与事件监听器是统⼀的,或者说事件监听器完全消失了。
当⽤户在GUI组件上激发某个事件时,组件⾃⼰特定的⽅法将会负责处理该事件。
监听机制的事件源与事件监听是分开的。我们需要自己设置一个监听器,回调机制的事件源与事件监听是绑定在一起的。
- boolean类型
几乎所有基于回调的事件处理方法都有一个boolean类型的返回值,该返回值用于表示该处理方法是否能完全处理该事件。如果处理事件的回调方法返回true,表明该处理方法已经完全处理改事件,该事件不会传播出去。如果处理事件的回调方法返回false,表明该处理方法并未完全处理该事件,该事件会传播出去。对于基于回调的时间传播而言,某组件上所发生的事件不仅会激发该组件上的回调方法,也会触发该组件所在Activity的回调方法——只要事件能传播到该Activity。
实例:
MyButton 子类
public class MyButton extends AppCompatButton { public MyButton(Context context , AttributeSet set) { super(context , set); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { super.onKeyDown(keyCode , event); Log.v("-MyButton-", "the onKeyDown in MyButton"); // 返回false,表明并未完全处理该事件,该事件依然向外扩散 return true; }}
- MainActivity
public class MainActivity extends AppCompatActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button bn = (Button) findViewById(R.id.bn); Log.v("-Listener-", "the onKeyDown in Listener"); // 为bn绑定事件监听器 bn.setOnKeyListener(new OnKeyListener() {@Overridepublic boolean onKey(View source , int keyCode, KeyEvent event) { // 只处理按下键的事件 if (event.getAction() == KeyEvent.ACTION_DOWN) { Log.v("-Listener-", "the onKeyDown in Listener"); } // 返回false,表明该事件会向外传播 return false; } }); } // 重写onKeyDown方法,该方法可监听它所包含的所有组件的按键被按下事件 @Override public boolean onKeyDown(int keyCode, KeyEvent event) { super.onKeyDown(keyCode , event); Log.v("-Activity-" , "the onKeyDown in Activity"); //返回false,表明并未完全处理该事件,该事件依然向外扩散 return true; }}这里是在模拟器里进行的测试,这里按下键盘(而不是点击),会看到 logcat 中的输出,如下:
V/-Listener-: the onKeyDown in ListenerV/-MyButton-: the onKeyDown in MyButtonV/-Activity-: the onKeyDown in Activity举例:
- Override组件类的事件处理函数实现事件的处理。
View类实现了KeyEvent.Callback接口中的一系列回调函数,因此,基于回调的事件处理机制通过自定义View来实现,自定义View时重写这些事件处理方法即可。
比对
3.1.4.Handler消息处理
- 基于监听器的事件模型符合单一职责原则,事件源和事件监听器分开实现。
- Android的事件处理机制保证基于监听器的事件处理会优先于基于回调的事件处理被触发。
- 某些特定情况下,基于回调的事件处理机制会更好的提高程序的内聚性。
什么是Handler
Handler是一个消息分发对象。
Handler是Android系统提供的一套用来更新UI的机制,也是一套消息处理机制,可以通过Handler发消息,也可以通过Handler处理消息。
Handler的工作原理
在下面介绍Handler机制前,首先得了解以下几个概念:
1.Message 消息,理解为线程间通讯的数据单元。例如后台线程在处理数据完毕后需要更新UI,则可发送一条包含更新信息的Message给UI线程。 Message Queue 消息队列,用来存放通过Handler发布的消息,按照先进先出执行。
2.Handler是Message的主要处理者,负责将Message添加到消息队列以及对消息队列中的Message进行处理。
3.Looper 循环器,扮演Message Queue和Handler之间桥梁的角色,循环取出Message Queue里面的Message,并交付给相应的Handler进行处理。 线程 UI thread 通常就是main thread,而Android启动程序时会替它建立一个Message Queue。每一个线程里可含有一个Looper对象以及一个MessageQueue数据结构。在你的应用程序里,可以定义Handler的子类别来接收Looper所送出的消息。
Handler的运行流程
在子线程执行完耗时操作,当Handler发送消息时,将会调用 MessageQueue.enqueueMessage,向消息队列中添加消息。 当通过 Looper.loop开启循环后,会不断地从消息池中读取消息,即调用 MessageQueue.next, 然后调用目标Handler(即发送该消息的Handler)的 dispatchMessage方法传递消息, 然后返回到Handler所在线程,目标Handler收到消息,调用 handleMessage方法,接收消息,处理消息。
3.1.5.源码分析
在子线程创建Handler
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() {public void handleMessage(Message msg) { // process incoming messages here} } ; Looper.loop(); }}从上面可以看出,在子线程中创建Handler之前,要调用 Looper.prepare()方法,Handler创建后,还要调用 Looper.loop()方法。而前面我们在主线程创建Handler却不要这两个步骤,因为系统帮我们做了。
主线程的Looper
在ActivityThread的main方法,会调用 Looper.prepareMainLooper()来初始化Looper,并调用 Looper.loop()方法来开启循环。
3.1.5.Looper
public final class ActivityThread extends ClientTransactionHandler { // ... public static void main(String[] args) { // ... Looper.prepareMainLooper(); // ... Looper.loop(); }}从上可知,要使用Handler,必须先创建一个Looper。
初始化looper:
public final class Looper { public static void prepare() { prepare(true); } private static void prepare(Boolean quitAllowed) { if (sThreadLocal.get() != null) {throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); } public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) {if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared.");}sMainLooper = myLooper(); } } private Looper(Boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); } // ...}从上可以看出,不能重复创建Looper,每个线程只能创建一个。创建Looper,并保存在 ThreadLocal。其中ThreadLocal是线程本地存储区(Thread Local Storage,简称TLS),每个线程都有自己的私有的本地存储区域,不同线程之间彼此不能访问对方的TLS区域。
开启Looper
3.1.6.Handler
public final class Looper { // ... public static void loop() { // 获取TLS存储的Looper对象 final Looper me = myLooper(); if (me == null) {throw new RuntimeException("No Looper; Looper.prepare() wasnt called on this thread."); } final MessageQueue queue = me.mQueue; // 进入loop主循环方法 for (;;) {Message msg = queue.next();// 可能会阻塞,因为next()方法可能会无线循环 if (msg == null) { // No message indicates that the message queue is quitting. return;}// This must be in a local variable, in case a UI event sets the logger final Printer logging = me.mLogging;if (logging != null) { logging.println(">>>>> Dispatching to " msg.target " " msg.callback ": " msg.what);}// ... final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;final long dispatchEnd;try { // 获取msg的目标Handler,然后分发Message msg.target.dispatchMessage(msg); dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;}finally { if (traceTag != 0) { Trace.traceEnd(traceTag); }}// ... msg.recycleUnchecked(); } }}创建Handler
public class Handler { // ... public Handler() { this(null, false); } public Handler(Callback callback, Boolean async) { // ... // 必须先执行Looper.prepare(),才能获取Looper对象,否则为null mLooper = Looper.myLooper(); if (mLooper == null) {throw new RuntimeException( "Cant create handler inside thread " Thread.currentThread() " that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; // 消息队列,来自Looper对象 mCallback = callback; // 回调方法 mAsynchronous = async; // 设置消息是否为异步处理方式 }}发送消息:
子线程通过Handler的post()方法或send()方法发送消息,最终都是调用 sendMessageAtTime()方法。
post方法:
public final Boolean post(Runnable r){ return sendMessageDelayed(getPostMessage(r), 0);}public final Boolean postAtTime(Runnable r, long uptimeMillis){ return sendMessageAtTime(getPostMessage(r), uptimeMillis);}public final Boolean postAtTime(Runnable r, Object token, long uptimeMillis){ return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);}public final Boolean postDelayed(Runnable r, long delayMillis){ return sendMessageDelayed(getPostMessage(r), delayMillis);}private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m;}send方法
3.1.7.分发消息
public final Boolean sendMessage(Message msg){ return sendMessageDelayed(msg, 0);}public final Boolean sendEmptyMessage(int what){ return sendEmptyMessageDelayed(what, 0);}public final Boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis);}public final Boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageAtTime(msg, uptimeMillis);}public final Boolean sendMessageDelayed(Message msg, long delayMillis){ if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() delayMillis);}sendMessageAtTime()public Boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException(this " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis);}private Boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis);}在loop()方法中,获取到下一条消息后,执行 msg.target.dispatchMessage(msg),来分发消息到目标Handler。
3.1.8.Handler的简单使用
public class Handler { // ... public void dispatchMessage(Message msg) { if (msg.callback != null) {// 当Message存在回调方法,调用该回调方法 handleCallback(msg); } else {if (mCallback != null) { // 当Handler存在Callback成员变量时,回调其handleMessage()方法 if (mCallback.handleMessage(msg)) { return; }}// Handler自身的回调方法 handleMessage(msg); } } private static void handleCallback(Message message) { message.callback.run(); }}在子线程中,进行耗时操作,执行完操作后,发送消息,通知主线程更新UI。
3.2.Framework事件机制—onInterceptTouchEvent拦截流程解析3.2.1.基本知识
public class Activity extends android.app.Activity { private Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) {super.handleMessage(msg);// 更新UI } } ; @Override public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) { super.onCreate(savedInstanceState, persistentState); setContentView(R.layout.activity_main); new Thread(new Runnable() {@Override public void run() { // 执行耗时任务 ... // 任务执行完后,通知Handler更新UI Message message = Message.obtain(); message.what = 1; mHandler.sendMessage(message);} } ).start(); }}事件分发的三个函数
事件的分发 dispatchTouchEvent() 事件的拦截 onInterceptTouchEvent() 事件的处理(消费) onTouchEvent()
事件分发的对象
被分发的对象是那些?被分发的对象是用户触摸屏幕而产生的点击事件,事件主要包括:按下、滑动、抬起与取消。这些事件被封装成MotionEvent对象。
MotionEvent.ACTION_DOWN 在屏幕按下时 MotionEvent.ACTION_MOVE 在屏幕上滑动时 MotionEvent.ACTION_UP在屏幕抬起时 MotionEvent.ACTION_CANCLE 滑动超出控件边界时
分发事件的组件
分发事件的组件,也称为分发事件者,包括Activity、View和ViewGroup。它们三者的一般结构为:
3.2.2.事件处理流程
首先,我们需要了解事件处理中的几个方法:
1、在ViewGroup中,事件分为dispatchTouchEvent(事件的分发),onInterceptTouchEvent(事件的拦截),onTouchEvent(事件的处理)。
2、在View中,事件分为dispatchTouchEvent(事件的分发),onTouchEvent(事件的处理)。
下面是demo的界面结构,它是由两个自定义的ViewGroup和一个自定义的View组成,并分别重写了它们的以上几个方法。
其中 MyViewGroupA代码如下:
public class MyViewGroupA extends LinearLayout { public MyViewGroupA(Context context) { super(context); } public MyViewGroupA(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: Log.i("MyViewGroupA","dispatchTouchEvent_ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.i("MyViewGroupA","dispatchTouchEvent_ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.i("MyViewGroupA","dispatchTouchEvent_ACTION_UP"); break; } return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: Log.i("MyViewGroupA","onInterceptTouchEvent_ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.i("MyViewGroupA","onInterceptTouchEvent_ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.i("MyViewGroupA","onInterceptTouchEvent_ACTION_UP"); break; } return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: Log.i("MyViewGroupA","onTouchEvent_ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.i("MyViewGroupA","onTouchEvent_ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.i("MyViewGroupA","onTouchEvent_ACTION_UP"); break; } return super.onTouchEvent(event); }}MyViewGroupB代码如下:
public class MyViewGroupB extends LinearLayout { public MyViewGroupB(Context context) { super(context); } public MyViewGroupB(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: Log.i("MyViewGroupB","dispatchTouchEvent_ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.i("MyViewGroupB","dispatchTouchEvent_ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.i("MyViewGroupB","dispatchTouchEvent_ACTION_UP"); break; } return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: Log.i("MyViewGroupB","onInterceptTouchEvent_ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.i("MyViewGroupB","onInterceptTouchEvent_ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.i("MyViewGroupB","onInterceptTouchEvent_ACTION_UP"); break; } return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: Log.i("MyViewGroupB","onTouchEvent_ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.i("MyViewGroupB","onTouchEvent_ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.i("MyViewGroupB","onTouchEvent_ACTION_UP"); break; } return super.onTouchEvent(event); }}MyView代码如下:
public class MyView extends View { public MyView(Context context) { super(context); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: Log.i("MyView","dispatchTouchEvent_ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.i("MyView","dispatchTouchEvent_ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.i("MyView","dispatchTouchEvent_ACTION_UP"); break; } return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: Log.i("MyView","onTouchEvent_ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.i("MyView","onTouchEvent_ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.i("MyView","onTouchEvent_ACTION_UP"); break; } return super.onTouchEvent(event); }}我们说过,事件传递是由上到下的,所以最外层的View首先对事件进行操作。而我们最外层是Activity,所以事件也是从这里开始。 Activity代码如下:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean dispatchTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: Log.i("Activity","dispatchTouchEvent_ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.i("Activity","dispatchTouchEvent_ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.i("Activity","dispatchTouchEvent_ACTION_UP"); break; } return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: Log.i("Activity","onTouchEvent_ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.i("Activity","onTouchEvent_ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.i("Activity","onTouchEvent_ACTION_UP"); break; } return super.onTouchEvent(event); }}现在我们通过触摸MyView开始进行分析。虽然dispatchTouchEvent是事件开始的第一步,但是在开发中,我们通常很少改写它,所以我们下面只讨论其他两个方法。 1、对以上方法均不作处理,都返回super。这意味着我们既不拦截,也不消费。
大家看输出结果:
I/Activity: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupA: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupA: onInterceptTouchEvent_ACTION_DOWNI/MyViewGroupB: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupB: onInterceptTouchEvent_ACTION_DOWNI/MyView: dispatchTouchEvent_ACTION_DOWNI/MyView: onTouchEvent_ACTION_DOWNI/MyViewGroupB: onTouchEvent_ACTION_DOWNI/MyViewGroupA: onTouchEvent_ACTION_DOWNI/Activity: onTouchEvent_ACTION_DOWNI/Activity: dispatchTouchEvent_ACTION_MOVEI/Activity: onTouchEvent_ACTION_MOVEI/Activity: dispatchTouchEvent_ACTION_UPI/Activity: onTouchEvent_ACTION_UP结合输出结果,我们可以总结出以下的结论:
image.png
结合流程图,不难发现,如果我对事件既不拦截,也不消费,当触发ACTION_DOWN的时候,事件会经过Activity——MyViewGroupA——MyViewGroupB——MyView一层层的向下进行dispatchTouchEvent(分发)—onInterceptTouchEvent(拦截)调用。当到达最底层MyView后,开始触发消费操作,因为我均不消费,ACTION_DOWN将由底层一层层向上冒,移交上层处理。当抵达最上层Activity后,说明下层均不消费,之后触发的ACTION_MOVE和ACTION_UP将不再向下层分发传递,直接交由Activity分发给自己进行处理。
2、我们将MyVIewGroupB的onInterceptTouchEvent返回值改为true,其他均是super。这意味着仅仅MyViewGroupB进行事件拦截,但均无消费
输出结果如下:
I/Activity: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupA: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupA: onInterceptTouchEvent_ACTION_DOWNI/MyViewGroupB: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupB: onInterceptTouchEvent_ACTION_DOWNI/MyViewGroupB: onTouchEvent_ACTION_DOWNI/MyViewGroupA: onTouchEvent_ACTION_DOWNI/Activity: onTouchEvent_ACTION_DOWNI/Activity: dispatchTouchEvent_ACTION_MOVEI/Activity: onTouchEvent_ACTION_MOVEI/Activity: dispatchTouchEvent_ACTION_UPI/Activity: onTouchEvent_ACTION_UP结合输出结果,总结如下:
当触发ACTION_DOWN的时候,事件依然是从Activity开始一层层向下传递,当传递到MyViewGroupB时,因为进行了事件拦截,所以执行完onInterceptTouchEvent后不再向下传递,而是直接交由MyViewGroupB的onTouchEvent进行消费处理。由于我们是只拦截,不消费,所以事件向上传递,交由上层处理,最终回到Activity。之后触发的ACTION_MOVE和ACTION_UP也不再向下传递,直接交由Activity分发给自己处理。
3、我们还是将MyViewGroupB的onInterceptTouchEvent返回super,但是将他的onTouchEvent返回true。这意味着我们不拦截,但是由MyViewGroupB进行事件处理。
输出结果如下:
I/Activity: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupA: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupA: onInterceptTouchEvent_ACTION_DOWNI/MyViewGroupB: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupB: onInterceptTouchEvent_ACTION_DOWNI/MyView: dispatchTouchEvent_ACTION_DOWNI/MyView: onTouchEvent_ACTION_DOWNI/MyViewGroupB: onTouchEvent_ACTION_DOWNI/Activity: dispatchTouchEvent_ACTION_MOVEI/MyViewGroupA: dispatchTouchEvent_ACTION_MOVEI/MyViewGroupA: onInterceptTouchEvent_ACTION_MOVEI/MyViewGroupB: dispatchTouchEvent_ACTION_MOVEI/MyViewGroupB: onTouchEvent_ACTION_MOVEI/Activity: dispatchTouchEvent_ACTION_UPI/MyViewGroupA: dispatchTouchEvent_ACTION_UPI/MyViewGroupA: onInterceptTouchEvent_ACTION_UPI/MyViewGroupB: dispatchTouchEvent_ACTION_UPI/MyViewGroupB: onTouchEvent_ACTION_UP结合输出结果,总结如下:
可以看出,当触发ACTION_DOWN的时候,事件的分发传递过程和1的时候一样,从Activity开始一层层向下传递,最终传递到最底层MyView,触发消费操作,然后MyView将消费操作移交上层处理,然后到达MyViewGroupB的onTouchEvent,并且进行了消费处理,事件处理到此不在向上移交。当触发ACTION_MOVE和ACTION_UP操作时,事件依然需要由Activity开始向下分发传递,但是当传递到MyViewGroupB后,由于其消费了ACTION_DOWN,事件将不再继续向下分发,而是直接由MyViewGroupB分发给自己的onTouchEvent进行继续处理。事件处理也不再向上移交。
4、将MyViewGroupB的onInterceptTouchEvent和onTouchEvent的返回值均改为true。这意味着既拦截,又消费。
输出结果如下:
I/Activity: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupA: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupA: onInterceptTouchEvent_ACTION_DOWNI/MyViewGroupB: dispatchTouchEvent_ACTION_DOWNI/MyViewGroupB: onInterceptTouchEvent_ACTION_DOWNI/MyViewGroupB: onTouchEvent_ACTION_DOWNI/Activity: dispatchTouchEvent_ACTION_MOVEI/MyViewGroupA: dispatchTouchEvent_ACTION_MOVEI/MyViewGroupA: onInterceptTouchEvent_ACTION_MOVEI/MyViewGroupB: dispatchTouchEvent_ACTION_MOVEI/MyViewGroupB: onTouchEvent_ACTION_MOVEI/Activity: dispatchTouchEvent_ACTION_UPI/MyViewGroupA: dispatchTouchEvent_ACTION_UPI/MyViewGroupA: onInterceptTouchEvent_ACTION_UPI/MyViewGroupB: dispatchTouchEvent_ACTION_UPI/MyViewGroupB: onTouchEvent_ACTION_UP结合输出结果,总结如下:
当触发ACTION_DOWN的时候,依然从Activity开始向下传递,当到达MyViewGroupB的是,因为在onInterceptTouchEvent进行了拦截操作,因此不再继续向下分发传递,而是交由MyViewGroupB的onTouchEvent进行处理消费。MyViewGroupB的onTouchEvent返回的是true,说明它决定对ACTION_DOWN进行处理,因此事件也就不再移交上层处理。当触发ACTION_MOVE和ACTION_UP的时候,事件还是从Activity开始向下传递,当到达MyViewGroupB的时候,由于之前进行了拦截操作,因此,MyViewGroupB直接将事件分发给自己的onTouchEvent进行处理,不在向下分发传递。事件处理也不再向上层移交。
获取本文PDF版(视频 文字原稿),私信:Framework
上一篇:婚外情犯法吗家庭中的是非曲直
下一篇:如何注册qq号 怎样注册qq号
Copyright © 2024 有趣生活 All Rights Reserve吉ICP备19000289号-5 TXT地图HTML地图XML地图