文章目录
问题背景
Android官方提供了一个DreamService类以实现屏保的功能,内部提供了两个回调:
- onAttachToWindow()
- onDetachToWindow()
昨天碰到了一个系统性的问题:
在启动DreamService屏保之后,系统的其他App直接startActivity()并不会退出屏保,也就是DreamService并不会收到onDetachToWindow()回调?
分析问题
1. DreamService 怎么实现屏保
论如何实现屏保可以参考《基于DreamService的屏保》
DreamService实现屏保功能很简单,只需要两个步骤
- 实现DreamService的onAttachedToWindow()和onDetachToWindow()
- 声明权限
android:permission="android.permission.BIND_DREAM_SERVICE
如果你熟悉NotificationManagerService和NotificationListenerService,你会发现DreamService跟他们的实现是一致的。
DreamService 就是利用窗口Window,来显示屏保功能,如果你是做系统应用的,那你应该很熟悉了。
// DreamService.java
private final void attach(IBinder windowToken, boolean canDoze, IRemoteCallback started) {
...
mWindow = new PhoneWindow(this);
mWindow.setCallback(this);
getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
...
mHandler.post(new Runnable() {
@Override
public void run() {
...
onDreamingStarted();
...
}
});
}
// 设定布局
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
}
DreamService在attach的私有方法内部创建了PhoneWindow,跟Activity创建很像。
在WIndow创建成功以后会回调到onAttachToWindow(),我们就可以直接在onAttachToWindow()添加我们的自定义布局setContentView()
2. DreamManagerService 怎么启动 DreamService
上面问题1,大概简述了DreamService怎么利用Window创建自己的屏保,但是attach()方式是哪里调用的呢?
DreamService的onBind()创建了DreamServiceWrapper,DreamServiceWrapper实现了IDreamService的binder接口,内部对外提供了attach(),detach()和wakeUp()接口。DreamService作为了binder的服务端。
其中,wakeUp()就是唤醒,attach()屏保启动,detach()结束屏保服务
其实是DreamManagerService绑定服务DreamService的binder。
private final class DreamServiceWrapper extends IDreamService.Stub {
@Override
public void attach(final IBinder windowToken, final boolean canDoze,
IRemoteCallback started) {
mHandler.post(new Runnable() {
@Override
public void run() {
DreamService.