- Launcher自行开发,往Workspace中插入一个自定义的CellLayout来作为负一屏的容器。 这种方式是最常用的方案。
- 利用Google的feed屏方案,基于ILauncherOverlay和ILauncherOverlayCallback这两个接口来实现,Launcher作为客户端,负一屏是一个独立应用作为服务端,通过aidl来通信来实现加载负一屏以及支持相互滑页。
方案一: 桌面自行开发,可以快速完美的加入负一屏,但是当负一屏的业务越来越多时,会拖累launcher的性能,内存等。
实现可以关注我的下一篇博文 [Launcher负一屏实现第一章]
要解决方案一的问题,我们就需要考虑将负一屏独立出去,作为单独的进程运行,这种实现我们需要思考两个问题。
问题1:负一屏作为独立进程,以什么方式显示出来?
问题2:负一屏的界面属于什么层级,和launcher是什么关系,如何交互?
本文主要讲述下第二种方案的实现。
客户端Launcher的实现
- 首先我们导入google官方定义了两个interface接口,ILauncherOverlay和ILauncherOverlayCallback。
ILauncherOverlay定义的方法是客户端调用服务端的,方法的实现在service端,ILauncherOverlayCallback是服务端回调客户端的,实现在客户端。
- Launcher通过bindservice后,拿到ILauncherOverlay实体,来和服务端进行通信,传递关键信息给服务端。
- Launcher在onAttachedToWindow的时候,会通过windowAttached(WindowManager.LayoutParams attrs, ILauncherOverlayCallback callbacks, int options)方法,将Launcher的Activity的window属性,和launcher实例化出来的ILauncherOverlayCallback.Stub回调传给服务端。
- 针对用户在屏幕的滑动操作, 调用startScroll(), onScroll(float progress), endScroll()来通知服务端;
- launcher这边打开关闭负一屏,用openOverlay(),closeOverlay()来通知服务端;
launcher作为客户端,相应的改动并不大,绑定服务后,只需要在正确的地方调用接口,来通知服务端,重点和难点在服务端的实现。
服务端Service的实现
- 首先新建一个工程,将客户端的ILauncherOverlay和ILauncherOverlayCallback接口文件拷贝过来,注意目录要保持一致(aidl通信)。
AndroidManifest中定义个Service,实例化ILauncherOverlay.Stub,并通过onBind来return给客户端;
ILauncherOverlay.Stub mStub = new ILauncherOverlay.Stub() {
};
- 在客户端调用服务端的windowAttached的时候,服务端的主要实现如下
- 需要开始创建一个新的window,,然后将客户端的LayoutParams中的部分属性赋值给服务端的window
到此,就可以在launcher的上层显示一个负一屏的window了,如果不给负一屏容器设置一个translationX的话,默认该window是盖在launcher上的,我们可以将translationX默认值设置在屏幕以外。
之后,我们可以根据launcher调用startScroll(),onScroll(float progress),endScroll(), 传过来的scroll值,来改变负一屏window中的view的translationX,来达到负一屏滑动的效果,同时将scroll的progress通过ILauncherOverlayCallback中的overlayScrollChanged(float progress)回调给launcher,launcher可以让workspace做相应的translationX,这样就可以达到负一屏和launcher的滑动关联,而不是负一屏盖在launcher上。
记得在滑页结束后,来确定哪个window需要focus,通过设置window的flag来完成focus控制。
总结:
第一种常规方案,能快速实现负一屏,但有一些缺点,如运行在launcher进程中,对launcher是有消耗的,当负一屏的业务越来越多时,会对launcher内存,性能造成影响。
第二种方案的实现,得以让负一屏独立出去,负一屏的显示依赖launcher的activity的token,但是运行却在独立的进程中。