核心内容
通过共享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官方开发了新的回收方式
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信息,严格模式也是利用这种实现。
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查询
命令方式
adb shell ls -l /proc/{pid}/fd
app中调用的话使用如下方法
public Process exec(String[] cmdarray, String[] envp, File dir)
throws IOException {
return new ProcessBuilder(cmdarray)
.environment(envp)
.directory(dir)
.start();
}
在实际的线上环境中,很难通过Process去监控fd的数量变化,不过读取fd的方法还是有的,如何做到监控呢,实际上可以定时也可以在关闭特定页面时触发检测逻辑,对比前后变化的差异。
public static String[] getFds() {
String FD_DIR = "/proc/" + Process.myPid() + "/fd";
File fdFileDir = new File(FD_DIR);
String[] fds = fdFileDir.list();// 列出当前目录下所有的文件
return fds;
}
然后对FD进行识别
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列表
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,当然一些高端机会超过这个数值限制,查询命令如下
adb shell ulimit -n
当然,如果要在app中读取,上面的命令是不可以的,因此需要换种方式,那就是读取自己进程目录下的limits文件
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了,但是为了保证执行的先后顺序,我们需要引入执行队列。
为什么这样可以实现,首先Looper机制本身具备先后顺序,因此我们把MessageQueue的消息发送到执行队列,其实影响并不大。
定义ShareHandlerThread
- 必须也能进行MessageQueue类似的操作,如删除和查询消息,因为其中需要定义队列
- 需要拿到消息后转发到自己的队列
- 必须在自己的线程执行
- 需要找到自己的LightHandler执行,因此这里得用Map影射一下
- 必须可以quit或者quitySafely
- 必须Callback消息的正确执行
- 防止消息执行之前LightHandler被回收
我们这里主要核心是使用Handler.Callback去拦截消息,看过handler.dispatchMessage源码就能知道,其可以优先拦截消息,但其中Callback消息是很难拦截的,使用Handler.Callback也是无法拦截到,因为他在Handler.callback之前执行,因此我们只能在LightHandler中做特殊处理。
LightHandler映射也是很简单,我们使用name记录下来
private final Map<String, WeakReference<LightHandler>> lightHandlerMaps = new ConcurrentHashMap<String, WeakReference<LightHandler>>();
但LightHandler被回收是一个潜在风险,因此我们可以利用WeakHashMap监视原始的Handler,只有原始的Handler被回收LightHandler才能被回收。
Looper 问题解决
在Android系统中,Looper本身提供了很多静态方法,但是如何更好的兼容原有逻辑呢?这里提供一种新的方法,定义一个LightLooper,使其实现如下逻辑。
public abstract class LightLooper {
//获取Looper
public abstract LightLooper getLooper();
static final ThreadLocal<LightLooper> sThreadLocal = new ThreadLocal<LightLooper>();
//静态获取Looper
public static LightLooper myLooper() {
return sThreadLocal.get();
}
void onPrepare() {
sThreadLocal.set(this);
}
void onEnd() {
sThreadLocal.set(null);
}
}
注意看,LightLooper是抽象类,如何让LightLooper 优雅的兼容进去呢?
这里我们让ShareHandlerThread继承LightLooper即可,当然还有其他方法,这里我们怎么简单怎么来。
ShareHandlerThread具体源码
下面是核心类ShareHandlerThread的源码实现
public class ShareHandlerThread extends LightLooper 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;
private boolean isPrepared = false;
public ShareHandlerThread(String name) {
this.threadName = "ShareThread#" + name;
}
public static HandlerThread real() {
return realThreadHandler;
}
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 static LightHandler newHandler(LightLooper looper) {
if (!(looper instanceof ShareHandlerThread)) {
return null;
}
ShareHandlerThread shareHandlerThread = (ShareHandlerThread) looper;
LightHandler lightHandler = new LightHandler(new InternalHandler(realThreadHandler.getLooper(), shareHandlerThread), null, shareHandlerThread, shareHandlerThread.generateHandlerName());
return lightHandler;
}
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() {
isPrepared = true;
onPrepare();
tid = Process.myTid();
while (!isQuited) {
Message msg = null;
synchronized (nameLock) {
msg = queue.poll();
}
if (msg == null) {
continue;
}
if (msg.what == MSG_QUIT) {
msg.recycle();
break;
}
doHandleMessage(msg);
msg.recycle();
}
onEnd();
}
private void doHandleMessage(Message msg) {
LightHandler lightHandler = getTarget(msg);
if (lightHandler == null) {
return;
}
lightHandler.dispatchMessage(msg);
}
@Override
public void dispatchMessage(Message msg) {
Message copyMessage = Message.obtain(msg);
synchronized (nameLock) {
queue.offer(copyMessage);
}
//这里返回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;
}
if (data.isEmpty()) {
return null;
}
String keyName = (String) data.get(LightHandler.KEY);
if (TextUtils.isEmpty(keyName)) {
return null;
}
WeakReference<LightHandler> reference = lightHandlerMaps.get(keyName);
if (reference == null) {
return null;
}
return reference.get();
}
//判断是否有消息
public boolean hasMessage(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 || token == null) && 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 || object == null)&& 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 || token == null) && 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 || o == null) && 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);
}
@Override
public LightLooper getLooper() {
if (isStarted) {
return this;
}
return null;
}
}
这里容易出问题的地方就是recycle的调用和消息复制,复制使用Message#obtain(Message),不要使用Message#copyFrom(Message),而recycle要避免多次调用
InternalHandler实现
不过,在上面的代码中我们可以看到,我们还需要一个辅助HandlerThread的InternaHandler,主要负责消息传递和消息转发,充当接收和转发,意味着它本身不会执行任何耗时任务。
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拿数据。
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
private final Map<String, LightHandler> lightHandlerMaps = new ConcurrentHashMap<>();
callback 问题
由于我们可以在Handler#dispatchMessage方法中修改回调,那事实上这个callback就不成问题
这里,只需要模拟正式的Handler处理流程
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对象返回出去即可。
public Object getLooper(){
return fakeLooper;
}
跨进程问题
如果你对Handler熟悉的话,就知道Handler是可以借助IMessenger间接跨进程的,但LightHandler实现跨进程显然要修改Message或者在外面封装一下,考虑到Handler跨进程使用的机会并不多,因此我们暂时不做太多的处理。
LightHandler完整代码
下面是完整的实现代码,主要实现了
- Message消息标记
- 消息监控
- callback 代理
- callback 消息保护
- finalize消息回收
InternalHandler负责接收消息到RealHandlerThread,InternalHandler分发消息到指定的LightHandler,而LightHandler负责真正的消息处理。
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() {
Message msg = Message.obtain(this.handler);
attachLightHandler(msg);
return msg;
}
public final Message obtainMessage(int what) {
Message msg = Message.obtain(this.handler, what);
attachLightHandler(msg);
return msg;
}
public final Message obtainMessage(int what, Object obj) {
Message msg = Message.obtain(this.handler, what, obj);
attachLightHandler(msg);
return msg;
}
public final Message obtainMessage(int what, int arg1, int arg2) {
Message msg = Message.obtain(this.handler, what, arg1, arg2);
attachLightHandler(msg);
return msg;
}
public final Message obtainMessage(int what, int arg1, int arg2, Object obj) {
Message msg = Message.obtain(this.handler, what, arg1, arg2, obj);
attachLightHandler(msg);
return msg;
}
//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.hasMessage(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 (Build.VERSION.SDK_INT >= 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 LightLooper getLooper() {
return fakeLooper;
}
public void dispatchMessage(Message msg) {
try {
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;
}
}
public void handleMessage(Message msg, LightHandler lightHandler) {
}
public Handler.Callback getCallback() {
return callback;
}
@Override
protected void finalize() throws Throwable {
fakeLooper.removeLightHandler(this.handlerName);
super.finalize();
}
}
上面的风险点是如果Message的attachLightHandler的信息附带不上,那么消息处理可能存在风险。
完整代码就是核心逻辑。
使用
用法基本和HandlerThread类似,但要注意Handler的创建
this.shareHandlerThread = new ShareHandlerThread("SurfaceHandler");
this.shareHandlerThread.start();
this.surfaceHandler = shareHandlerThread.createHandler(this);
或者静态方式创建LightHandler,这里调用静态方法ShareHandlerThread#newHandler即可
this.shareHandlerThread = new ShareHandlerThread("SurfaceHandler");
this.shareHandlerThread.start();
this.surfaceHandler = ShareHandlerThread.newHandler(shareHandlerThread.getLooper());
另外消息的如下
surfaceHandler.obtainMessage(MSG_DRAW,0,0,surface).sendToTarget();
总结
通过上述实现,我们就能实现共享Looper的的情况下,实现了消息的发送和到指定线程的处理,从而减少了MessageQueue的创建,开头说过,也避免了FD开销。
当然,这个是个简单的逻辑,实际过程中还需要进一步打磨优化,目前可以正常运行和小规模使用。