欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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(); }
}