Android HandlerThread FD 优化 核心

核心内容

通过共享HandlerThread的方式,减少MessageQueue的创建,从而减少FD的创建,减少OOM的发生。

前言

我们常说,面向对象的开发语言中一切皆对象,任何对象都有他的属性和成员,因此后来拓展出了“类”这个概念,类是对象的抽象,一切都能抽象成为类,但类也是对象,在抽象的过程中先有对象才有类。作为操作系统,linux也有自己的规则——一切皆文件。

Android 作为基于unix-like的操作系统,本自带了操作系统最核心的基因——一切皆文件,这个核心思想是通过I/O的思想简化组件通信模式,一个组件必须以Input、Output或者同时兼备的模式去适配,这也统一后续的系统层通信发展路线,避免了碎片化。

FD在unix-like系统中用于描述组件(如进程)、资源(如文件)、节点(如驱动)等,在Android中,我们使用的进程、文件、MessageQueue、Socket、Binder、Pipe、共享内存、sqlite等均与其有关。

现状

FD释放

在很多情况下,对文件I/O读写必须及时close,当然为了避免被忽略,java官方开发了新的回收方式

1
2
3
4
5
6
java复制代码 try (FileInputStream fis = new FileInputStream("a.txt")) {
byte[] b = new byte[1024];
fis.read(b);
}catch (IOException e) {
System.out.println(e.getMessage());
}

同样,只要是Closeable的子类,均可以如此释放,如Socket等。
但问题是,I/O操作并不一定是单一方法种处理,比如我们录音过程,如果要添加音效,势必会转移到其他线程处理,这个时候,频繁的开启和关闭i/O显然不明智。其次,阻塞可能导致杂音问题,这个时候显然这个方法是不合适的。再比如SocketServer,监听到Socket,一般也要开启新的线程处理处理请求数据。

基于上述情况的不足,官方做法是利用CloseGuard做法是对I/O对象进行监视,在对象finalize发出warning信息,严格模式也是利用这种实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
java复制代码  class Foo {

private final CloseGuard guard = new CloseGuard();
public Foo() {
...;
guard.open("cleanup");
}
public void cleanup() {
guard.close();
...;
if (Build.VERSION.SDK_INT >= 28) {
Reference.reachabilityFence(this);
}
// For full correctness in the absence of a close() call, other methods may also need
// reachabilityFence() calls.
}
protected void finalize() throws Throwable {
try {
// Note that guard could be null if the constructor threw.
if (guard != null) {
guard.warnIfOpen();
}
cleanup();
} finally {
super.finalize();
}
}
}
}

那么,除了常见的一些监控和编程规范外,还有什么优化方式呢?

fd 共享

fd共享本质尽可能让同一个资源被多次利用,而不是一个资源打开多次,典型的做法就是Sqlite的操作放到ContentProvider中,以及Okhttp 中的连接池也起到相同的作用,再后来,Http 2.0的多路复用实现。说到这里,作为协程的老祖宗,epoll也是多路复用的实现,通过epoll可以做到监视多种fd,其实也可以做到fd共享。

fd 监控

在Android系统中,没有相应的api来获取应用的fd信息,更早期的Android是可以通过下面方式创建Shell(uid是相同的)进程去获取信息,类似CMD命令行一样,后来就不行了。

fd查询

命令方式

1
java复制代码adb shell ls -l /proc/{pid}/fd

app中调用的话使用如下方法

1
2
3
4
5
6
7
java复制代码public Process exec(String[] cmdarray, String[] envp, File dir)
throws IOException {
return new ProcessBuilder(cmdarray)
.environment(envp)
.directory(dir)
.start();
}

在实际的线上环境中,很难通过Process去监控fd的数量变化,不过读取fd的方法还是有的,如何做到监控呢,实际上可以定时也可以在关闭特定页面时触发检测逻辑,对比前后变化的差异。

1
2
3
4
5
6
java复制代码public static String[] getFds() {
String FD_DIR = "/proc/" + Process.myPid() + "/fd";
File fdFileDir = new File(FD_DIR);
String[] fds = fdFileDir.list();// 列出当前目录下所有的文件
return fds;
}

然后对FD进行识别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
java复制代码public static String readlink(String name) {
String FD_DIR = "/proc/" + Process.myPid() + "/fd";
String link = FD_DIR + File.separator + name;

Object realpath = BlockGuardHookerOs.invokeOsMethod("realpath", link);
if (realpath instanceof String) {
return (String) realpath;
}

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
try {
return Os.readlink(link);
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}

fd 差异比较

差异比较是比较之前的fd列表与最新的fd列表

1
java复制代码FDMonitor.diff(oldFdList,newFdList)

fd 监控缺陷

但是,这里仍然是有缺陷的,因为读取的到的fd有些 :node ,很难去识别,也很难定位到准确的线程资源上去,比如MessageQueue、进程和socket的。这些fd申请之后,如何对应到对象上去显然有一些难度。

fd表示符号 资源类型
socket:[1992] 网络请求相关
anon_inode:[eventpoll] MessageQueue epoll
anon_inode:[eventfd] MessageQueue相关
anon_inode:[timerfd] 系统定时器
anon_inode:[dmabuf] InputChannel WMS通信
/vendor/ 一般是系统操作使用
/dev/ashmem 内存相关
pipe 管道通信相关
/sys/ 一般是系统操作使用
/data/data/打开文件相关/data/app/ 私有目录文件fd
/storage/emulate/0/com.sample.abc sdcard打开文件fd

FD OOM

fd是OOM的元凶之一,fd触发的OOM基本上分为三类,一类是FD超过了阈值数量(如线程创建、too open many file),另一类是过多的fd资源申请,导致其他操作无法申请到内存,最后一类是fd申请的资源(如内存)超过了系统所能提供的内存。

FD 最大限制梳理

这里说一下,默认情况下,fd的数量最多为1024,当然一些高端机会超过这个数值限制,查询命令如下

1
java复制代码adb shell ulimit -n

当然,如果要在app中读取,上面的命令是不可以的,因此需要换种方式,那就是读取自己进程目录下的limits文件

1
java复制代码File file = new File("/proc/" + android.os.Process.myPid() + "/limits");

读取到文件,并进行解析

Soft Limit=1024,Hard Limit=4096,Units=files

以上是现状了,下面我们进入本篇的主题

FD 常用优化方法

FD优化的工具其实并不多,常用的的方法有

  • 及时关闭fd
  • 避免短时间内申请大量的fd资源 (如mmap、socket、thread、进程),按优先级事项申请
  • 控制fd数量,如线程的申请不宜过多。过多的HandlerThread并不一定能发挥cpu的优势,反而线程占用的内存比较高,更容易造成oom
  • 监控fd,防止fd泄露

下面,我们实现一种特殊的方法

HandlerThread FD 优化

本篇的重点是通过共享HandlerThread实现FD数量优化。

在 Android 系统中,创建一个 Looper 通常会创建 2 个 FD,一个是eventfd,另一个是epollfd,基本都是MessageQueue创建,而线程是没有FD的。在 Android 5.x上甚至会创建三个 FD,pipe_in、pipe_out 和 epollfd。

那么,在这里,我们的优化点显然不Looper,因为很难去更改系统底层实现,除非利用bhook这样的工具。如果想要通过纯java方式实现,那么,我们只能把视线放到HandlerThread上。

我们共享HandlerThread,这样每次只创建Thread,MessageQueue就可以避免创建了。

共享HandlerThread

实现自己的ShareHandlerThread和LightHandler

我们让HandlerThread 共享一个即可,思路就是模仿epoll多路复用机制,epoll多路复用和协程一样,一个监视线程,另一个是处理线程,我们这里让同一个RealHandlerThread (真实的HandlerThread)监视自定义的ShareHandlerThread创建的所有的Handler发送过来的Message,一旦到了执行时间,就发送Message到指定的线程执行,执行时到指定的Handler。

不过要这么实现的话,Handler我们也用不了,只能使用LightHandler了,但是为了保证执行的先后顺序,我们需要引入执行队列。

企业微信20231217-124109@2x.png

为什么这样可以实现,首先Looper机制本身具备先后顺序,因此我们把MessageQueue的消息发送到执行队列,其实影响并不大。

定义ShareHandlerThread

  • 必须也能进行MessageQueue类似的操作,如删除和查询消息,因为其中需要定义队列
  • 需要拿到消息后转发到自己的队列
  • 必须在自己的线程执行
  • 需要找到自己的LightHandler执行,因此这里得用Map影射一下
  • 必须可以quit或者quitySafely
  • 必须Callback消息的正确执行
  • 防止消息执行之前LightHandler被回收

我们这里主要核心是使用Handler.Callback去拦截消息,看过handler.dispatchMessage源码就能知道,其可以优先拦截消息,但其中Callback消息是很难拦截的,使用Handler.Callback也是无法拦截到,因为他在Handler.callback之前执行,因此我们只能在LightHandler中做特殊处理。

LightHandler映射也是很简单,我们使用name记录下来

1
java复制代码private final Map<String, WeakReference<LightHandler>> lightHandlerMaps = new ConcurrentHashMap<String, WeakReference<LightHandler>>();

但LightHandler被回收是一个潜在风险,因此我们可以利用WeakHashMap监视原始的Handler,只有原始的Handler被回收LightHandler才能被回收。

1
java复制代码private final WeakHashMap<Handler, LightHandler> recycleMonitor = new WeakHashMap<>();

下面是比较完整的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
java复制代码public class ShareHandlerThread implements Runnable, InternalHandler.SimpleCallback {
final static HandlerThread realThreadHandler = new HandlerThread("realThreadHandler");

static {
realThreadHandler.start();
}

private final Map<String, WeakReference<LightHandler>> lightHandlerMaps = new ConcurrentHashMap<String, WeakReference<LightHandler>>();
// 防止消息执行之前 LightHandler 被提前回收
private final WeakHashMap<Handler, LightHandler> recycleMonitor = new WeakHashMap<>();
private final String threadName;
Thread thread = null;

boolean isQuited = false;
boolean isStarted = false;

private static final int MSG_QUIT = Integer.MAX_VALUE;
private AbstractQueue<Message> queue = null;

//带名称的锁
private final Object nameLock = "queueLock";

private int tid;


public ShareHandlerThread(String name) {
this.threadName = "ShareHandlerThread#" + name;
}


public void start() {
if (isStarted) {
throw new IllegalThreadStateException();
}
if (this.queue == null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
this.queue = new LinkedTransferQueue<>();
} else {
this.queue = new LinkedBlockingQueue<>();
}
}
try {
thread = new Thread(this,this.threadName);
thread.start();
isStarted = true;
} catch (Throwable e) {
e.printStackTrace();
throw e;
}

}

public LightHandler createHandlerFromClass(Class<? extends LightHandler> KlassLightHandler) {
return createHandlerFromClass(KlassLightHandler, null);
}

public LightHandler createHandlerFromClass(Class<? extends LightHandler> KlassLightHandler, Handler.Callback callback) {
try {
Constructor<? extends LightHandler> constructor = KlassLightHandler.getDeclaredConstructor(Handler.class, Handler.Callback.class, ShareHandlerThread.class, String.class);
Handler handler = new InternalHandler(realThreadHandler.getLooper(), this);
return constructor.newInstance(handler, callback, this, generateHandlerName());
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}


public LightHandler createHandler() {
return createHandler(null);
}

public LightHandler createHandler(Handler.Callback callback) {
LightHandler lightHandler = new LightHandler(new InternalHandler(realThreadHandler.getLooper(), this), callback, this, generateHandlerName());
return lightHandler;
}

private String generateHandlerName() {
return threadName + "#" + SystemClock.uptimeMillis();
}

public LightHandler createAsyncHandler() {
return createAsyncHandler(null);
}

public LightHandler createAsyncHandler(Handler.Callback callback) {
LightHandler lightHandler = new LightHandler(new InternalHandler(realThreadHandler.getLooper(), this,true), callback, this, generateHandlerName());
return lightHandler;
}


@Override
public void run() {
tid = Process.myTid();
while (!isQuited) {
Message msg = queue.poll();
if (msg == null) {
continue;
}
if (msg.what == MSG_QUIT) {
break;
}
doHandleMessage(msg);
msg.recycle();
}
}

private void doHandleMessage(Message msg) {
Bundle data = msg.getData();
String keyName = (String) data.get(LightHandler.KEY);
WeakReference<LightHandler> reference = lightHandlerMaps.get(keyName);
if(reference == null) return;
LightHandler lightHandler = reference.get();
if (lightHandler == null) {
return;
}
lightHandler.dispatchMessage(msg);
}

@Override
public void dispatchMessage(Message msg) {
Message message = Message.obtain();
message.copyFrom(msg);
synchronized (nameLock){
queue.offer(message);
}
//这里返回true,不要和共享looper关联
}

public void addLightHandler(String handlerName, LightHandler lightHandler) {
lightHandlerMaps.put(handlerName, new WeakReference<>(lightHandler));
}

//不安全退出
public void quit() {
Message message = Message.obtain();
message.what = MSG_QUIT;
synchronized (nameLock) {
queue.clear();
queue.add(message);
}
}

//安全退出
public void quitSafely() {
Message message = Message.obtain();
message.what = MSG_QUIT;
synchronized (nameLock) {
queue.offer(message);
}
}

public LightHandler getTarget(Message msg) {
Bundle data = msg.peekData();
if(data == null){
return null;
}
String keyName = (String) data.get(LightHandler.KEY);
WeakReference<LightHandler> reference = lightHandlerMaps.get(keyName);
if(reference == null){
return null;
}
return reference.get();
}
//判断是否有消息
public boolean handleMessage(LightHandler lightHandler, int what, Object object) {
synchronized (nameLock) {
Iterator<Message> iterator = queue.iterator();
while (iterator.hasNext()) {
Message next = iterator.next();
if (next.what != what || next.obj != object) {
continue;
}
LightHandler target = getTarget(next);
if (target != lightHandler) {
continue;
}
return true;
}
}
return false;
}

//移除消息
public void removeCallbacksAndMessages(LightHandler lightHandler, Object token) {
synchronized (nameLock) {
Iterator<Message> iterator = queue.iterator();
while (iterator.hasNext()) {
Message next = iterator.next();
if (next.obj == token && getTarget(next) == lightHandler) {
iterator.remove();
}
}
}
}

// 移除消息
public void removeMessages(LightHandler lightHandler, int what, Object object) {
synchronized (nameLock) {
Iterator<Message> iterator = queue.iterator();
while (iterator.hasNext()) {
Message next = iterator.next();
if (next.what == what && next.obj == object && getTarget(next) == lightHandler) {
iterator.remove();
}
}
}
}
//删除callback,要删除的callback无需做保护, == 比较的是hashcode
public void removeCallbacks(LightHandler lightHandler, Runnable callback, Object token) {

synchronized (nameLock) {
Iterator<Message> iterator = queue.iterator();
while (iterator.hasNext()) {
Message next = iterator.next();
if (next.getCallback() == callback && next.obj == token && getTarget(next) == lightHandler) {
iterator.remove();
}
}
}
}
//查询callback
public boolean hasCallback(LightHandler lightHandler, Runnable callback, Object o) {
synchronized (nameLock) {
Iterator<Message> iterator = queue.iterator();
while (iterator.hasNext()) {
Message next = iterator.next();
if (next.getCallback() == callback && next.obj == o && getTarget(next) == lightHandler) {
return true;
}
}
}
return false;
}

public int getTid() {
return tid;
}
public long getThreadId() {
return thread == null ? -1 : thread.getId();
}

public Thread getThread() {
return thread;
}

//移除LightHandler
public void removeLightHandler(String key){
lightHandlerMaps.remove(key);
}

public void addMonitor(Handler handler, LightHandler lightHandler) {
recycleMonitor.put(handler,lightHandler);
}
}

InternalHandler实现

不过,在上面的代码中我们可以看到,我们还需要一个辅助HandlerThread的InternaHandler,主要负责消息传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
java复制代码public class InternalHandler extends Handler {
private SimpleCallback callback;

public InternalHandler(Looper looper, SimpleCallback callback) {
this(looper, callback, false);
}

public InternalHandler(Looper looper, SimpleCallback callback, boolean isAsync) {
super(looper);
this.callback = callback;
setAsynchronous(isAsync);
}

private void setAsynchronous(boolean isAsync) {
try {
Field mAsynchronousField = Handler.class.getDeclaredField("mAsynchronous");
changeFinalValue(this, mAsynchronousField, isAsync, true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}

//支持修改final字段
public static void changeFinalValue(Object object, Field field, Object newValue, boolean isSafeThread) {

try {
if (!field.isAccessible()) {
field.setAccessible(true);
}
// 如果field为private,则需要使用该方法使其可被访问
Field modifersField = null;
try {
modifersField = Field.class.getDeclaredField("modifiers");
} catch (Throwable e) {
e.printStackTrace();
}
try {
modifersField = Field.class.getDeclaredField("accessFlags");
} catch (Throwable e) {
e.printStackTrace();
}
modifersField.setAccessible(true);

int modifiers = field.getModifiers();
if (Modifier.isFinal(modifiers)) {
// 把指定的field中的final修饰符去掉
modifersField.setInt(field, modifiers & ~Modifier.FINAL);
}

field.set(object, newValue); // 为指定field设置新值
if (isSafeThread) { //如果要考虑线程安全,建议还原
if (Modifier.isFinal(modifiers)) {
modifersField.setInt(field, modifiers | Modifier.FINAL);
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}


@Override
public void dispatchMessage(Message msg) {
//将消息收敛到 ShareHandlerThread中
callback.dispatchMessage(msg);
}

public interface SimpleCallback {
void dispatchMessage(Message msg);
}
}

上面是InternalHandler的主要实现,很简单,但是难度主要在final字段修改这里,因为异步Hander的mAsynchronous字段是final修饰的且不公开的,因此还需要需要反射。

LightHandler实现

映射

这里有些难点,难点主要是如何让realHandlerThread中的消息执行时找到当前的LightHandler,为此我们这里做了个映射关系,在上面ShareHandlerThread中我们创建LightHandler给name的目的就是为了生成映射关系,但是Callback消息就有一定的难度,我们先处理一般消息。

不过,这里有个细节要注意,我们不能通过msg.getData()去获取Bundle,不然默认的new Bundle()会产生占内存4+4个数组元素的对象,因此,这里我们用peekData拿数据。

1
2
3
4
5
6
7
8
java复制代码private void attachLightHandler(Message msg) {
Bundle data = msg.peekData();
if(data == null){
data = new Bundle(1);
}
data.putString(KEY, handlerName);
msg.setData(data);
}

最终映射关系会知道ShareHandlerThread总的LightHandler

1
java复制代码    private final Map<String, LightHandler> lightHandlerMaps = new ConcurrentHashMap<>();

callback 问题

由于我们可以在Handler#dispatchMessage方法中修改回调,那事实上这个callback就不成问题

这里,只需要模拟正式的Handler处理流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
java复制代码public void dispatchMessage(Message msg) {
try {
cleanKeyData(msg);
Runnable msgCallback = msg.getCallback();
if(msgCallback != null){
msgCallback.run();
return;
}
Handler.Callback callback = getCallback();

if (callback != null) {
if (callback.handleMessage(msg)) {
return;
}
}
msg.setTarget(null);
handleMessage(msg, this);
} catch (Throwable e) {
e.printStackTrace();
throw e;
} finally {
msg.recycle();
}
}

getLooper问题

我们自定义的ShareHandlerThread显然是没有Looper的,因此我们最简单的办法就是把ShareHandlerThread对象返回出去即可。

1
2
3
java复制代码public Object getLooper(){
return fakeLooper;
}

跨进程问题

如果你对Handler熟悉的话,就知道Handler是可以借助IMessenger间接跨进程的,但LightHandler实现跨进程显然要修改Message或者在外面封装一下,考虑到Handler跨进程使用的机会并不多,因此我们暂时不做太多的处理。

LightHandler完整代码

下面是完整的实现代码,主要实现了

  • Message消息标记
  • 消息监控
  • callback 代理
  • callback 消息保护
  • finalize消息回收
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
java复制代码public class LightHandler {

private final Handler handler;
private final Handler.Callback callback;
private final String handlerName;
final static String KEY = "android.os.lightHandler.handlerName";

private ShareHandlerThread fakeLooper;
private Field mMessageQueueField;
private Method hasMessagesMethod;

public LightHandler(Handler handler, Handler.Callback callback, ShareHandlerThread fakeLooper, String name) {
this.handler = handler;
this.callback = callback;
this.fakeLooper = fakeLooper;
this.handlerName = name;
fakeLooper.addLightHandler(handlerName, this);
fakeLooper.addMonitor(handler, this);
}

public final boolean sendMessage(Message msg) {
attachLightHandler(msg);
return this.handler.sendMessage(msg);
}

private void attachLightHandler(Message msg) {

Bundle data = msg.peekData();
if (data == null) {
data = new Bundle(1);
}
data.putString(KEY, handlerName);
msg.setData(data);

}

public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
attachLightHandler(msg);
return this.handler.sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

public final boolean sendMessageAtFrontOfQueue(Message msg) {
attachLightHandler(msg);
return this.handler.sendMessageAtFrontOfQueue(msg);
}

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();
attachLightHandler(msg);
msg.what = what;
return this.handler.sendMessageAtTime(msg, uptimeMillis);
}

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
attachLightHandler(msg);
return this.handler.sendMessageAtTime(msg, uptimeMillis);
}

// obtain方法

public final Message obtainMessage() {
return Message.obtain(this.handler);
}

public final Message obtainMessage(int what) {
return Message.obtain(this.handler, what);
}

public final Message obtainMessage(int what, Object obj) {
return Message.obtain(this.handler, what, obj);
}

public final Message obtainMessage(int what, int arg1, int arg2) {
return Message.obtain(this.handler, what, arg1, arg2);
}

public final Message obtainMessage(int what, int arg1, int arg2, Object obj) {
return Message.obtain(this.handler, what, arg1, arg2, obj);
}

//runable方法
private Message getPostMessage(Runnable r) {
return getPostMessage(r, null);
}

private Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain(this.handler, r);
m.setTarget(null);
m.obj = token;
return m;
}

public final boolean post(Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}

public final boolean postAtFrontOfQueue(Runnable r) {
return sendMessageAtFrontOfQueue(getPostMessage(r));
}

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);
}

public final boolean postDelayed(
Runnable r, Object token, long delayMillis) {
return sendMessageDelayed(getPostMessage(r, token), delayMillis);
}

//remove类方法

/**
* Remove any pending posts of messages with code 'what' that are in the
* message queue.
*/
public final void removeMessages(int what) {
removeMessages(what, null);
}

/**
* Remove any pending posts of messages with code 'what' and whose obj is
* 'object' that are in the message queue. If <var>object</var> is null,
* all messages will be removed.
*/
public final void removeMessages(int what, Object object) {
this.handler.removeMessages(what, object);
this.fakeLooper.removeMessages(this, what, object);
}


public final void removeCallbacksAndMessages(Object token) {
this.handler.removeCallbacksAndMessages(token);
this.fakeLooper.removeCallbacksAndMessages(this, token);
}


public final boolean hasMessages(int what) {
return hasMessages(what, null);
}

public final boolean hasMessages(int what, Object object) {
return this.handler.hasMessages(what, object) || fakeLooper.handleMessage(this, what, object);
}

public final boolean hasCallbacks(Runnable r) {
if (this.fakeLooper.hasCallback(this, r, null)) {
return true;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
return this.handler.hasCallbacks(r);
}
MessageQueue queue = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
queue = this.handler.getLooper().getQueue();
} else {
try {
if (mMessageQueueField == null) {
mMessageQueueField = Handler.class.getDeclaredField("mQueue");
}
mMessageQueueField.setAccessible(true);
queue = (MessageQueue) mMessageQueueField.get(this.handler);
} catch (Throwable e) {
e.printStackTrace();
}
}
if (queue == null) {
return false;
}
try {
if (hasMessagesMethod == null) {
hasMessagesMethod = MessageQueue.class.getDeclaredMethod("hasMessages", Handler.class, Runnable.class, Object.class);
}
hasMessagesMethod.setAccessible(true);
hasMessagesMethod.invoke(this.handler, r, null);
} catch (Throwable e) {
e.printStackTrace();
}
return false;
}


/**
* Remove any pending posts of Runnable r that are in the message queue.
*/
public final void removeCallbacks(Runnable r) {
removeCallbacks(r, null);
}

public final void removeCallbacks(Runnable r, Object token) {
this.handler.removeCallbacks(r, token);
this.fakeLooper.removeCallbacks(this, r, token);
}

public Object getLooper() {
return fakeLooper;
}

public void dispatchMessage(Message msg) {
try {
cleanKeyData(msg);
Runnable msgCallback = msg.getCallback();
if(msgCallback != null){
msgCallback.run();
return;
}
Handler.Callback callback = getCallback();

if (callback != null) {
if (callback.handleMessage(msg)) {
return;
}
}
msg.setTarget(null);
handleMessage(msg, this);
} catch (Throwable e) {
e.printStackTrace();
throw e;
} finally {
msg.recycle();
}
}

public void handleMessage(Message msg, LightHandler lightHandler) {

}

private void cleanKeyData(Message msg) {
Bundle data = msg.peekData();
if (data != null) {
data.remove(KEY);
}
}
public Handler.Callback getCallback() {
return callback;
}
@Override
protected void finalize() throws Throwable {
fakeLooper.removeLightHandler(this.handlerName);
super.finalize();
}
}

完整代码就是核心逻辑。

总结

通过上述实现,我们就能实现共享Looper的的情况下,实现了消息的发送和到指定线程的处理,从而减少了MessageQueue的创建,开头说过,也避免了FD开销。

当然,这个是个简单的逻辑,实际过程中还需要进一步打磨优化。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%