承接上一篇文章,当我们进入startLoader方法中,看到最后有这样一行代码
sWorker.post(mLoaderTask);
第一想法是开启了子线程,要执行耗时操作,想想也对加载数据当然是耗时操作要开启子线程。但是别急者去看runnable中的逻辑,先来看看sWorker这个Handler吧。
private static final Handler sWorker = new Handler(sWorkerThread.getLooper());
平时我们创建Handler对象就直接new一个了,为什么这个构造要传入一个参数呢,获取的是一个Looper,那这个Looper是哪个线程的Looper呢?再来看看sWorkerThread对象。
private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
是一个HandlerThread的类,看HandlerThread的源码是一个Thread的子类,好先到这里,下一篇在具体说说Launcher中我们可以学习的一些设计方式,现在我们只要知道Handler执行了post方法,因为你对应Handler的Looper是在子线程中创建的,所以代码要在子线程中执行post方法参数中Runnable类中的run方法的逻辑。
进入的LoaderTask这个内部类中,直接找到run方法:这其中比较重要的两行代码如下
....
isUpgrade = loadAndBindWorkspace();
...
loadAndBindAllApps();
第一行代码是用来加载和显示手机Launcher桌面上的数据,第二行代码是用来加载Launcher中应用菜单列表中的所有的APP数据。这里说的的是原生的安卓应用(模拟器上的Android系统就是原生的),想小米改过的系统就只有一级桌面了,没有了中间的应用菜单列表按钮。先看第一个方法
private boolean loadAndBindWorkspace() {
...
isUpgradePath = loadWorkspace();
....
//第一个参数是负数,表示需要对所有的桌面页进行刷新。如果正数或者0,表示对指定页面进行刷新。
//第二个参数表示是否需要清理桌面的重复数据。
bindWorkspace(-1, isUpgradePath);
....
}
这个方法中最重要的是这两行代码,第一行,看方法名就知道它是用来加载数据的,第二行是用来讲数据绑定到控件上显示出来的。
loadWorkSpace()当中的逻辑比较多了,在这里就不贴代码了,它主要是从数据库中获取到对应的字段,通过集合传递到bindWorkspace方法中,然后bindWorkspace方法通过回调接口,将数据传递到Launcher中完成数据和控件的绑定来实现数据的展示。
private void loadAndBindAllApps() {
....
loadAllApps();
....
onlyBindAllApps();
}
同理对于加载应用菜单列表中的应用来说,也是先加载然后绑定这样的逻辑,但是和加载桌面数据不同的是在loadAllApps()方法中没有通过数据库来加载,使用的是PackageManager来获取手机中的所有应用(这里需要说明一下,我的讲解中使用的是Android4.4的Launcher源码来说,在Android5.0中加入了多账户的机制之后,这里就不是使用的PackageManager来实现获取所有应用了,5.0之后就是获取的登录账户的所有应用)。然后onlyBindAllApps()方法就和上面一样了,拿到数据调用回调接口,将数据传递到Launcher中,展示数据。
这就是基本的Launcher的加载逻辑,这里值得要提一下的是,如果想要屏蔽掉应用菜单列表,把所有的应用都加载到桌面上,Google在系统中提供了一个开关,在Hotseat.java这个类中的resetLayout()中有一个if判断,当这个if判断是true的时候就是显示应用菜单按钮,false就是显示应用菜单按钮。
下一篇我们就一起来看看在Launcher中有哪些很好的逻辑实现可以学习的。
欢迎关注我的微信公众号,我会把一些生活的感想和投资方面的总结写到公众号,希望你能来和我一起交流技术之外的东西。