Launcher2分析-加载和绑定AllApp列表
程序员文章站
2022-05-16 20:33:22
launcher2分析-加载和绑定allapp列表。android应用列表的视图就在launcher.xml中,也就是说应用列表视图一开始就已经加载好了,只是没有显示出来,属性为invisible,...
launcher2分析-加载和绑定allapp列表。android应用列表的视图就在launcher.xml中,也就是说应用列表视图一开始就已经加载好了,只是没有显示出来,属性为invisible,它是和workspace在同一个viewgroup中。id为apps_customize_pane,实际类型为com.android.launcher2.appscustomizetabhost,继承自tabhost,而layout apps_customize_pane.xml中包含了一个id为apps_customize_pane_content,类型为appscustomizepagedview的child,改类型间接继承了pagedview,是应用列表的核心view。
从launchermodel$loadertask#loadandbindapps()开始分析:
private void loadandbindallapps() { if (debug_loaders) { log.d(tag, "loadandbindallapps mallappsloaded=" + mallappsloaded); } if (!mallappsloaded) {//判断是否所有app都加载过了 loadallappsbybatch();//加载所有app信息并且分批绑定 synchronized (loadertask.this) { if (mstopped) { return; } mallappsloaded = true; } } else { onlybindallapps();//跳过加载过程,直接绑定 } }
分析loadallappsbybatch():
private void loadallappsbybatch() { final long t = debug_loaders systemclock.uptimemillis() : 0; // don't use these two variables in any of the callback runnables. // otherwise we hold a reference to them. final callbacks oldcallbacks = mcallbacks.get(); if (oldcallbacks == null) { // this launcher has exited and nobody bothered to tell us. just bail. log.w(tag, "loadertask running with no launcher (loadallappsbybatch)"); return; } final intent mainintent = new intent(intent.action_main, null);//需要action为main的 mainintent.addcategory(intent.category_launcher);//还需要category为launcher的 //跟linux多用户有关,有多少个用户,就有多少个userhandle,但是手机一般来说就一个吧 final list profiles = musermanager.getuserprofiles(); mbgallappslist.clear(); final int profilecount = profiles.size(); for (int p = 0; p < profilecount; p++) { userhandle user = profiles.get(p); list apps = null; int n = integer.max_value;//这个只是初始化指,后面会改变 int startindex; int i = 0; int batchsize = -1; while (i < n && !mstopped) {//n为apps的size if (i == 0) { final long qiatime = debug_loaders systemclock.uptimemillis() : 0; apps = mlauncherapps.getactivitylist(null, user);//获取对应用户的所有app if (debug_loaders) { log.d(tag, "queryintentactivities took " + (systemclock.uptimemillis()-qiatime) + "ms"); } if (apps == null) { return; } n = apps.size();//在这里重新赋值给n,而不会是integer的max value if (debug_loaders) { log.d(tag, "queryintentactivities got " + n + " apps"); } if (n == 0) { // there are no apps! return; } if (mbatchsize == 0) { batchsize = n; } else { batchsize = mbatchsize;//设置怎么分批,一批有多少个应用。应该是太多一批可能会导致anr,导致其他事件无法被及时响应 } final long sorttime = debug_loaders systemclock.uptimemillis() : 0; collections.sort(apps, new launchermodel.shortcutnamecomparator(mlabelcache));//将apps重排序 if (debug_loaders) { log.d(tag, "sort took " + (systemclock.uptimemillis()-sorttime) + "ms"); } } final long t2 = debug_loaders systemclock.uptimemillis() : 0; startindex = i; for (int j=0; i added = mbgallappslist.added;//将added引用个对象发出去 final boolean firstprofile = p == 0; mbgallappslist.added = new arraylist();//将added成员指向新的对象,因为这次是新增,那么下次就不是了 mhandler.post(new runnable() { public void run() { final long t = systemclock.uptimemillis(); if (callbacks != null) { if (firstprofile) {//firstprofile应该代表的是root用户,需要加加载所有app callbacks.bindallapplications(added);//后面会重点分析这个方法 } else { callbacks.bindappsadded(added);//如果是其他用户,则只加载新增内容 } if (debug_loaders) { log.d(tag, "bound " + added.size() + " apps in " + (systemclock.uptimemillis() - t) + "ms"); } } else { log.i(tag, "not binding apps: no launcher activity"); } } }); if (debug_loaders) { log.d(tag, "batch of " + (i-startindex) + " icons processed in " + (systemclock.uptimemillis()-t2) + "ms"); } if (mallappsloaddelay > 0 && i < n) { try { if (debug_loaders) { log.d(tag, "sleeping for " + mallappsloaddelay + "ms"); } thread.sleep(mallappsloaddelay);//每批app的绑定任务交到主线程的队列中后,要休眠一段时间再向队列放入下一批任务 } catch (interruptedexception exc) { } } } if (debug_loaders) { log.d(tag, "cached all " + n + " apps in " + (systemclock.uptimemillis()-t) + "ms" + (mallappsloaddelay > 0 " (including delay)" : "")); } } }
分析一下mbgallappslist.add(new applicationinfo(apps.get(i), user, miconcache, mlabelcache));其中mbgallappslist是allappslist类型,其中add方法的如下:
public void add(applicationinfo info) { if (findactivity(data, info.componentname, info.user)) {//当对应用户已经存在这个component时,就不会添加到data和added中 return; } data.add(info);//添加到data,存放所有app added.add(info);//添加到added,存放相对于上次加载来说为新增的app }
launcher实现了launchermodel的callback,下面分析launcher#bindallapplications()
public void bindallapplications(final arraylist apps) { runnable setallappsrunnable = new runnable() { public void run() { if (mappscustomizecontent != null) { //这个mappscustomizecontent就是一开始说的appscustomizepagedview类型对象,调用setapps方法后,就会去重绘这个view了。 mappscustomizecontent.setapps(apps); } } }; // remove the progress bar entirely; we could also make it gone // but better to remove it since we know it's not going to be used view progressbar = mappscustomizetabhost. findviewbyid(r.id.apps_customize_progress_bar); if (progressbar != null) { ((viewgroup)progressbar.getparent()).removeview(progressbar); // we just post the call to setapps so the user sees the progress bar // disappear-- otherwise, it just looks like the progress bar froze // which doesn't look great mappscustomizetabhost.post(setallappsrunnable);//会在progressbar消失后再post到消息队列中 } else { // if we did not initialize the spinner in oncreate, then we can directly set the // list of applications without waiting for any progress bars views to be hidden. setallappsrunnable.run(); } }
上一篇: ASP.NET4.0尚未在Web服务器上注册解决方法
下一篇: 中国电信赵慧玲:云计算与智能管道