当前位置: 代码迷 >> Android >> Android4.0源码Launcher起步流程分析【android源码Launcher系列一】
  详细解决方案

Android4.0源码Launcher起步流程分析【android源码Launcher系列一】

热度:12   发布时间:2016-05-01 10:52:51.0
Android4.0源码Launcher启动流程分析【android源码Launcher系列一】

??? 最近研究ICS4.0的Launcher,发现4.0和2.3有稍微点区别,但是区别不是特别大,所以我就先整理一下Launcher启动的大致流程。 Launcher其实是贯彻于手机的整个系统的,时时刻刻都在运行,要是Launcher不运行了,手机就得黑屏了。Launcher的 LauncherMode=singletask,所以说不管Launcher启动了哪个应用,总有个Launcher的实例在堆栈中,并且位于栈底。点 击Home键进入到Launcher,上篇Android的全局键(home键/长按耳机键)详解【android源码解析八】 中有详细的介绍。大致思路其实就是启动launcher的时候,新启动一个task。大致先说这么多,先看截图:

?

?

????????????????????????????????????

?????????????????????????????????????????????????????????????????????????? 图(1)

????? 上图是4.0的Launcher界面,下面我们分步来解析一下Launcher的启动过程。

?

???? Step 0:首先要给大家介绍一下Launcher的数据库,这个数据库中存放着待机界面的图标,主屏底部的应用程序图标和桌面folder中各应用程序的图 标,ICS4.0的folder中只能放应用程序的快捷方式,shortcut不能放到这个folder中,先看截图:?

??????????????????????????????????????????????????????????????????????? 图(2)

????? ?说说各字段的含义:

??????????????? title:表示桌面应用程序的名字,有的title为空,表示是widget的快捷方式;

?????????????intent:表示启动这个图标的intent放到数据库中,当click的时候就会调用这个字段,启动相应的应用程序;

???????container:表示应用程序的容器,folder的容器为整数,-100:表示在桌面的程序,-101:表示是主屏底部的程序;

?????????? screen:表示在第几个屏,folder的screen都是0, container=-101的为0,1,3,4;2为allapp的按钮;

?????????????? cellX:表示在屏幕X轴的位置,(0,1,2,3),左上角为0点,往右依次增加;

???????????????cellY:表示在屏幕Y轴的位置,(0,1,2,3),左上角为0点,往下依次增加;

????????????? spallX:表示占X轴几个格;

????????????? spallY:表示占Y轴几个格;

???????? itemType:应用程序用0表示,shortcut用1表示,folder用2表示,widget用4表示;

??? appWidgetId:-1表示不是widget,数字大于0表示才是widget;

???????isShortCut:值为0表示不是应用程序的ShortCut,值为1表示是应用程序的ShortCut;

???????? iconType:值为0表示图标的名字被定义为包名的资源id,值为1表示图标用bitmap保存;

???????????????? icon:表示应用程序的图标,二进制的;显示为一张图片;

?????? 说明:folder中的应用快捷方式绑定folder---->是用container的值绑定folder的id的;

??????? 详细的讲解请参考LauncherSettings.java这个类,有数据库字段的详细讲解;

?????????手 机是在第一次烧机完成后,数据库的值还没有,这时候launcher解析default_workspace.xml把这个值存到数据库中;所以说想定制 什么样的开机桌面就在default_workspace.xml中做相应的配置,具体参照我前面的博客:

Android中源码Launcher主屏幕程序排列详解【安卓Launcher进化一】中有详细的介绍:

?????? i f (!convertDatabase(db)) {
??????????????? ?// Populate favorites table with initial favorites
??????????????? loadFavorites(db, R.xml.default_workspace);
????????}

?

??????Step?1:开机后先启动LauncherApplication.java这个类的onCreate()方法,下面看代码:???

???

   @Override    public void onCreate() {        super.onCreate();        // set sIsScreenXLarge and sScreenDensity *before* creating icon cache        // 在创建图标缓存之前先设置sIsScreenXLarge和屏幕设备的分辨率        final int screenSize = getResources().getConfiguration().screenLayout &                Configuration.SCREENLAYOUT_SIZE_MASK;        sIsScreenLarge = screenSize == Configuration.SCREENLAYOUT_SIZE_LARGE ||            screenSize == Configuration.SCREENLAYOUT_SIZE_XLARGE;        sScreenDensity = getResources().getDisplayMetrics().density;        // 实例化图标缓存区的对象        mIconCache = new IconCache(this);        // 实例化一个LauncherModel对象,这个类是保存Launcher的内存启动状态,更新Launcher的数据库的作用        mModel = new LauncherModel(this, mIconCache);        // Register intent receivers        // 注册监听,应用package增加,删除,改变的监听。        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();        // 注册application是否可用,语言改变,方向改变的监听。4.0支持横竖屏        filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);        filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);        filter.addAction(Intent.ACTION_LOCALE_CHANGED);        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);        registerReceiver(mModel, filter);        filter = new IntentFilter();        filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);        registerReceiver(mModel, filter);        filter = new IntentFilter();        filter.addAction(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED);        registerReceiver(mModel, filter);        // Register for changes to the favorites        // 注册favorites应用程序数据库改变的监听        ContentResolver resolver = getContentResolver();        resolver.registerContentObserver(LauncherSettings.Favorites.CONTENT_URI, true,                mFavoritesObserver);    }
?

???????Step 2:在LauncherApplication.java中onTerminate()的方法,解除监听的绑定;

?

 /**     * There's no guarantee that this function is ever called.     */    @Override    public void onTerminate() {        super.onTerminate();        unregisterReceiver(mModel);        ContentResolver resolver = getContentResolver();        resolver.unregisterContentObserver(mFavoritesObserver);    }

?

???? Step 3:Step1中的数据库mFavoritesObserver监听内部类如下:

?

   /**     * Receives notifications whenever the user favorites have changed.     */    private final ContentObserver mFavoritesObserver = new ContentObserver(new Handler()) {        @Override        public void onChange(boolean selfChange) {            mModel.startLoader(LauncherApplication.this, false);        }    };

?

????? 说明:mModel.startLoader(。。,。。)是开启一个线程,设置线程的优先级NORM_PRIORITY,开始load桌面图标对应的数据库,这个过程是和Launcher.onCreate()同时进行的;
?

??? Step 4: 接着我们来看看mModel.startLoader(LauncherApplication.this, false)的方法:

?

   public void startLoader(Context context, boolean isLaunching) {        synchronized (mLock) {            if (DEBUG_LOADERS) {                Log.d(TAG, "startLoader isLaunching=" + isLaunching);            }            // Don't bother to start the thread if we know it's not going to do anything            if (mCallbacks != null && mCallbacks.get() != null) {                // If there is already one running, tell it to stop.                // also, don't downgrade isLaunching if we're already running                isLaunching = isLaunching || stopLoaderLocked();                mLoaderTask = new LoaderTask(context, isLaunching);                sWorkerThread.setPriority(Thread.NORM_PRIORITY);                sWorker.post(mLoaderTask);            }        }    }

??

?? Step 5:接着我们来看看LoaderTask.java的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) {                    if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to " +                            (mIsLaunching ? "DEFAULT" : "BACKGROUND"));                    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");                    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) {                        if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to BACKGROUND");                        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();                }                // Restore the default thread priority after we are done loading items                synchronized (mLock) {                    android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);                }            }            // Update the saved icons if necessary            if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");            for (Object key : sDbIconCache.keySet()) {                updateSavedIcon(mContext, (ShortcutInfo) key, sDbIconCache.get(key));            }            sDbIconCache.clear();            // Clear out this reference, otherwise we end up holding it until all of the            // callback runnables are done.            mContext = null;            synchronized (mLock) {                // If we are still the last one to be scheduled, remove ourselves.                if (mLoaderTask == this) {                    mLoaderTask = null;                }            }        }        public void stopLocked() {            synchronized (LoaderTask.this) {                mStopped = true;                this.notify();            }        }
?

加载桌面图标对应的数据库的值,这些值能把这些图标显示在屏幕上

?

?

??? Step 6:LauncherApplication.onCreate()方法启动完成后,接着开始调用Launcher.java的onCreate()方法。代码如下:

?
    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        // 得到LauncherApplication的对象app        LauncherApplication app = ((LauncherApplication)getApplication());        // 得到LauncherModel对象mModel,设置一个mCallbacks = new WeakReference<Callbacks>(callbacks)的        // 回调callbacks        mModel = app.setLauncher(this);        // 得到图标缓存的对象mIconCache        mIconCache = app.getIconCache();        // 得到拖拽控制类DragController的对象        mDragController = new DragController(this);        // 得到一个LayoutInflater布局的对象        mInflater = getLayoutInflater();        // 得到一个AppWidgetManager的对象        mAppWidgetManager = AppWidgetManager.getInstance(this);        // 得到LauncherAppWidgetHost的一个对象        mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);        // Start receiving onAppWidgetChanged calls for your AppWidgets.        mAppWidgetHost.startListening();        if (PROFILE_STARTUP) {            android.os.Debug.startMethodTracing(                    Environment.getExternalStorageDirectory() + "/launcher");        }        // 检查Locale的语言级别,mcc, mnc的改变        checkForLocaleChange();        // 加载Launcher.xml布局文件        setContentView(R.layout.launcher);        // Launcher的布局的初始化        setupViews();        // 第一次启动Android的展示设置向导,        // 这个SharedPreferences中存在        // <boolean name="cling.workspace.dismissed" value="true" />        // 如果值为true,则不显示设置向导,为false,则显示设置向导。        showFirstRunWorkspaceCling();        // 注册数据库观察者        registerContentObservers();        lockAllApps();        mSavedState = savedInstanceState;        restoreState(mSavedState);        // Update customization drawer _after_ restoring the states        if (mAppsCustomizeContent != null) {            mAppsCustomizeContent.onPackagesUpdated();        }        if (PROFILE_STARTUP) {            android.os.Debug.stopMethodTracing();        }        if (!mRestoring) {            mModel.startLoader(this, true);        }        if (!mModel.isAllAppsLoaded()) {            ViewGroup appsCustomizeContentParent = (ViewGroup) mAppsCustomizeContent.getParent();            mInflater.inflate(R.layout.apps_customize_progressbar, appsCustomizeContentParent);        }        // For handling default keys        mDefaultKeySsb = new SpannableStringBuilder();        Selection.setSelection(mDefaultKeySsb, 0);        // 注册系统对话框消失的监听        IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);        registerReceiver(mCloseSystemDialogsReceiver, filter);        boolean searchVisible = false;        boolean voiceVisible = false;        // If we have a saved version of these external icons, we load them up immediately        // 如果我们已经保存了外部图标的版本,我们立即加载它们        int coi = getCurrentOrientationIndexForGlobalIcons();        if (sGlobalSearchIcon[coi] == null || sVoiceSearchIcon[coi] == null ||                sAppMarketIcon[coi] == null) {            updateAppMarketIcon();            searchVisible = updateGlobalSearchIcon();            voiceVisible = updateVoiceSearchIcon(searchVisible);        }        if (sGlobalSearchIcon[coi] != null) {             updateGlobalSearchIcon(sGlobalSearchIcon[coi]);             searchVisible = true;        }        if (sVoiceSearchIcon[coi] != null) {            updateVoiceSearchIcon(sVoiceSearchIcon[coi]);            voiceVisible = true;        }        if (sAppMarketIcon[coi] != null) {            updateAppMarketIcon(sAppMarketIcon[coi]);        }        mSearchDropTargetBar.onSearchPackagesChanged(searchVisible, voiceVisible);        // On large interfaces, we want the screen to auto-rotate based on the current orientation        if (LauncherApplication.isScreenLarge() || Build.TYPE.contentEquals("eng")) {            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);        }    }
?

??? Step 7:其中LauncherModel这个类中有个回调接口,具体定义如下:

?

 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 void bindPackagesUpdated();        public boolean isAllAppsVisible();        public void bindSearchablesChanged();    }
?

?

对LauncherModel进行初始化的时候mModel = app.setLauncher(this);---->mModel.initialize(launcher);----->

???????????? ?public void initialize(Callbacks callbacks) {
????????????????????? synchronized (mLock) {
????????????????????????????? mCallbacks = new WeakReference<Callbacks>(callbacks);
????????????????????? ?}
?????????????? }

这 个callbacks就是定义的接口回调,具体实现是在Launcher.java中定义的,启动Launcher的过程中,这些实现是异步来实现的。还 有Launcher.java的onResume()方法没有讲解,到这儿基本上Android的Launcher已经启动起来了,这个 onResume()我研究后再更新。

????? 欢迎各界同僚留言指正错误和拍砖!欢迎留言!

本文转载自:http://blog.csdn.net/wdaming1986/article/details/7585649?

  相关解决方案