Android--launcher启动过程解析

第一步:我们先从LauncherApplication.java开始,先找到onCreate()方法:

public void onCreate() {
        //设置最小堆内存8M
        VMRuntime.getRuntime().setMinimumHeapSize(8 * 1024 * 1024); //llx modify the heapsize
        super.onCreate();

        //建立应用图标缓存器         
        mIconCache = new IconCache(this);
        //建立LauncherModel
        mModel = new LauncherModel(this, mIconCache);
        // Register intent receivers        
        //注册Intent.ACTION_PACKAGE_ADDED,Intent.ACTION_PACKAGE_REMOVED,
       //Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE,
       //Intent.ACTION_LOCALE_CHANGED 事件监听器
       //LauncherModel作为广播接收器对上面事件进行监听
      IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
       filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
       filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
       filter.addDataScheme("package");
       registerReceiver(mModel, filter);

       filter = new IntentFilter();
       filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
       filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
       registerReceiver(mModel, filter);

       filter = new IntentFilter();
       filter.addAction(Intent.ACTION_LOCALE_CHANGED);
       registerReceiver(mModel, filter);
       
     // Register for changes to the favorites
        //添加对桌面favorites content provider 数据变化监听器
       ContentResolver resolver = getContentResolver();
       resolver.registerContentObserver(LauncherSettings.Favorites.CONTENT_URI, true,mFavoritesObserver);
 }
第二步:看下Launcher.java中的onCreate()方法:
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //获取LauncherApplication LauncherModel mIconCache等LauncherApplication初始化的对象
        LauncherApplication app = ((LauncherApplication)getApplication());
        mModel = app.setLauncher(this);
        mIconCache = app.getIconCache();
        //新建拖放控制器new DragController(this)
        mDragController = new DragController(this);
        mInflater = getLayoutInflater();

        //获取桌面组件管理器,启动桌面组件host
        mAppWidgetManager = AppWidgetManager.getInstance(this);
        mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);
        mAppWidgetHost.startListening();
        if (PROFILE_STARTUP) {
            android.os.Debug.startMethodTracing("/sdcard/launcher");
        }
        //从array.hotseats中加载所有的hotseats
        loadHotseats();

        //从加载本地设置
        checkForLocaleChange();setWallpaperDimension();

        //加载布局文件
        setContentView(R.layout.launcher);
        //初始化所有控件
        setupViews();
        registerContentObservers();
        lockAllApps();
        //从Bundle savedInstanceState获取桌面持久化数据
        mSavedState = savedInstanceState;
        restoreState(mSavedState);

        if (PROFILE_STARTUP) {
           android.os.Debug.stopMethodTracing();
         }

        if (!mRestoring) {
        //LauncherModel.Loader.startLoader() 代码同步处理
        mModel.startLoader(this, true);
         }

       // For handling default keys
        mDefaultKeySsb = new SpannableStringBuilder();
        Selection.setSelection(mDefaultKeySsb, 0);

        //注册Intent.ACTION_CLOSE_SYSTEM_DIALOGS广播监听
        IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        registerReceiver(mCloseSystemDialogsReceiver, filter);
     }
第三步:加载桌面项: 在LauncherModel.java的Thread的run方法, 是在主线程完成以后才开始加载

public void run() {
            // Optimize for end-user experience: if the Launcher is up and // running with the
            // All Apps interface in the foreground, load All Apps first. Otherwise, load the
            // workspace first (default).
            final Callbacks cbk = mCallbacks.get();
            final boolean loadWorkspaceFirst = cbk != null ? (!cbk.isAllAppsVisible()) : true;

            keep_running: {
                // Elevate priority when Home launches for the first time to avoid
                // starving at boot time. Staring at a blank home is not cool.
                synchronized (mLock) {
                    android.os.Process.setThreadPriority(mIsLaunching
                            ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);
                }
                //判断是否先加载桌面
                if (loadWorkspaceFirst) {
                    if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");
                    //从数据库launcher.db中查询中所有桌面项构造对应类型的ItemInfo对象存入
                    loadAndBindWorkspace();
                } else {
                    if (DEBUG_LOADERS) Log.d(TAG, "step 1: special: loading all apps");
                    loadAndBindAllApps();
                }
                if (mStopped) {
                    break keep_running;
                }

                // Whew! Hard work done.  Slow us down, and wait until the UI thread has
                // settled down.
                synchronized (mLock) {
                    if (mIsLaunching) {
                        android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    }
                }
                waitForIdle();

                // second step
                if (loadWorkspaceFirst) {
                    if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");
                    loadAndBindAllApps();
                } else {
                    if (DEBUG_LOADERS) Log.d(TAG, "step 2: special: loading workspace");
                    loadAndBindWorkspace();
                }
            }

这里调用了Launcher.java中startBinding方法

public void startBinding() {
        final Workspace workspace = mWorkspace;
        int count = workspace.getChildCount();
        for (int i = 0; i < count; i++) {
            // Use removeAllViewsInLayout() to avoid an extra requestLayout() and invalidate().
            ((ViewGroup) workspace.getChildAt(i)).removeAllViewsInLayout();
        }

        if (DEBUG_USER_INTERFACE) {
            android.widget.Button finishButton = new android.widget.Button(this);
            finishButton.setText("Finish");
            workspace.addInScreen(finishButton, 1, 0, 0, 1, 1);

            finishButton.setOnClickListener(new android.widget.Button.OnClickListener() {
                public void onClick(View v) {
                    finish();
                }
            });
        }
    }
还有Launcher.java的bindItem()方法:

public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end) {
        setLoadOnResume();
        //获取桌面的celllayout对象,也就是workspace下5个用户桌面中的一个
        final Workspace workspace = mWorkspace;
        for (int i=start; i<end; i++) {
            //根据ItemInfo对象创建桌面图标view对象
            final ItemInfo item = shortcuts.get(i);
            mDesktopItems.add(item);
            switch (item.itemType) {
                case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
                case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
                    final View shortcut = createShortcut((ShortcutInfo)item);
                   //获取item.screen, item.cellX, item.cellY, spanX, spanY并添加到屏幕上。
                    workspace.addInScreen(shortcut, item.screen, item.cellX, item.cellY, 1, 1,false);
                    break;
                case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
                    final FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this,
                            (ViewGroup) workspace.getChildAt(workspace.getCurrentScreen()),
                            (UserFolderInfo) item);
                    workspace.addInScreen(newFolder, item.screen, item.cellX, item.cellY, 1, 1,false);
                    break;
                case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
                    final FolderIcon newLiveFolder = LiveFolderIcon.fromXml(
                            R.layout.live_folder_icon, this,
                            (ViewGroup) workspace.getChildAt(workspace.getCurrentScreen()),
                            (LiveFolderInfo) item);
                    workspace.addInScreen(newLiveFolder, item.screen, item.cellX, item.cellY, 1, 1,false);
                    break;
            }
        }
         //.重新设置桌面图标view 的layoutparam(类型为cellLayout.layoutparam)
          workspace.requestLayout();
    }
注意,这两个方法都是异步调用。原因应该很清楚:时间。

另外还要注意一下两点:

         1.桌面图标view对象添加OnLongClickListener=laucher,由laucher负责监听桌面图标view的longclick事件

         2.如果桌面图标是DropTarget对象,拖放控制器mDragController添加该view到拖放目的地列表

Launcher.java的代码中有bindFolders()bindAppWidget()方法,都是回调方法。主要看下bindAppWidget()方法吧。

/**

     * Add the views for a widget to the workspace.
     *
     * Implementation of the method from LauncherModel.Callbacks.
     */
    public void bindAppWidget(LauncherAppWidgetInfo item) {
        setLoadOnResume();

        final long start = DEBUG_WIDGETS ? SystemClock.uptimeMillis() : 0;
        if (DEBUG_WIDGETS) {
            Log.d(TAG, "bindAppWidget: " + item);
        }
        final Workspace workspace = mWorkspace;
        //获取LauncherAppWidgetInfo的appWidgetId
        final int appWidgetId = item.appWidgetId;
        //根据appWidgetInfo创建桌面组件的view AppWidgetHostView对象
        final AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
        if (DEBUG_WIDGETS) {
            Log.d(TAG, "bindAppWidget: id=" + item.appWidgetId + " belongs to component " + appWidgetInfo.provider);
        }

        item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);

        item.hostView.setAppWidget(appWidgetId, appWidgetInfo);
        item.hostView.setTag(item);
        //添加到对应桌面的cell
        workspace.addInScreen(item.hostView, item.screen, item.cellX,
                item.cellY, item.spanX, item.spanY, false);

        workspace.requestLayout();

        mDesktopItems.add(item);

        if (DEBUG_WIDGETS) {
            Log.d(TAG, "bound widget id="+item.appWidgetId+" in "
                    + (SystemClock.uptimeMillis()-start) + "ms");
        }
    }

当都加载完成以后会执行finishBindingItems():

/**
     * Callback saying that there aren't any more items to bind.
     *
     * Implementation of the method from LauncherModel.Callbacks.
     */
    public void finishBindingItems() {
        setLoadOnResume();
        if (mSavedState != null) {
            if (!mWorkspace.hasFocus()) {
                mWorkspace.getChildAt(mWorkspace.getCurrentScreen()).requestFocus();
            }
            final long[] userFolders = mSavedState.getLongArray(RUNTIME_STATE_USER_FOLDERS);
            if (userFolders != null) {
                for (long folderId : userFolders) {
                    final FolderInfo info = sFolders.get(folderId);
                    if (info != null) {
                        openFolder(info);
                    }
                }
                final Folder openFolder = mWorkspace.getOpenFolder();
                if (openFolder != null) {
                    openFolder.requestFocus();
                }
            }
            mSavedState = null;
        }
        if (mSavedInstanceState != null) {
            super.onRestoreInstanceState(mSavedInstanceState);
            mSavedInstanceState = null;
        }
        mWorkspaceLoading = false;
    }

前面那三个都是都是回调方法,控制器当然是LauncherModel.java了,让我们在代码里看一下:

其接口定义如下:

public interface Callbacks {
        public boolean setLoadOnResume();
        public int getCurrentWorkspaceScreen();
        public void startBinding();
        public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end);
        public void bindFolders(HashMap<Long,FolderInfo> folders);
        public void finishBindingItems();
        public void bindAppWidget(LauncherAppWidgetInfo info);
        public void bindAllApplications(ArrayList<ApplicationInfo> apps);
        public void bindAppsAdded(ArrayList<ApplicationInfo> apps);
        public void bindAppsUpdated(ArrayList<ApplicationInfo> apps);
        public void bindAppsRemoved(ArrayList<ApplicationInfo> apps, boolean permanent);
        public boolean isAllAppsVisible();
    }

想看仔细的,自己可以在代码中找一下。

最后执行 bindAllApplications() , bindAppsAdded()方法

public void bindAllApplications(ArrayList<ApplicationInfo> apps) {
        mAllAppsGrid.setApps(apps);
    }
    /**
     * A package was installed.
     *
     * Implementation of the method from LauncherModel.Callbacks.
     */
    public void bindAppsAdded(ArrayList<ApplicationInfo> apps) {
        setLoadOnResume();
        removeDialog(DIALOG_CREATE_SHORTCUT);
        mAllAppsGrid.addApps(apps);
    }

到这基本上就是整个的启动过程了。


    PS:这篇文章没有太多文字性的东西,关于代码的问题,请看代码注释,比较详细了。如果有疑问,欢迎留言探讨!

  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值