`
亚当爱上java
  • 浏览: 707353 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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 

  • 大小: 145.9 KB
  • 大小: 137.8 KB
分享到:
评论
1 楼 317994096 2014-08-12  
支持下。Launcher分析起来东西比较多 还是不容易的。

相关推荐

    android4.0-launcher可运行源码

    《深入解析Android 4.0 Launcher源码》 在Android操作系统中,Launcher是用户与系统交互的首要界面,它承担着应用启动、桌面布局管理以及快捷方式创建等核心功能。当我们谈论“android4.0-launcher可运行源码”时,...

    android 定制 launcher 4.0源码

    7. **对比原生源码**:对比Android开源项目的原生Launcher源码,如AOSP(Android Open Source Project),找出差异,理解特定功能的实现方式。 通过以上步骤,你可以逐步了解和掌握Android 4.0 Launcher的定制原理...

    android4.0 Launcher2

    总结,Android 4.0的Launcher2是一个强大且易用的启动器,它的源代码为我们揭示了Android桌面系统的工作原理。通过深入学习和理解这部分源码,开发者不仅可以了解Android系统的内部机制,还能为自己的应用开发提供...

    Android 4.0 Launcher2 源码 Eclipse版

    【Android 4.0 Launcher2 源码 Eclipse版】是一个专门为Android 4.0 (Ice Cream Sandwich)系统设计的启动器源代码,适合开发者深入理解Android系统的桌面启动器工作原理,以及进行自定义开发。这个源代码版本是为...

    android4.0原生launcher代码

    Android 4.0(冰淇淋三明治,Ice Cream Sandwich)的 Launcher 是用户界面的核心部分,它作为系统的启动器,负责展示应用图标、小部件和主屏幕。理解其源码对于开发者深入理解 Android 系统的工作原理、定制个性化...

    Android 4.0 Launcher系统源码

    Android 4.0 Launcher系统源码是Android操作系统中桌面启动器的重要组成部分,它负责管理主屏幕、应用快捷方式、小部件以及桌面布局等用户界面。深入理解这部分源码对于开发者来说,有助于定制个性化启动器或者优化...

    android4.0 launcher源码

    Android 4.0 Launcher源码解析 Android 4.0(Ice Cream Sandwich,简称ICS)是Google推出的一个重要版本,其Launcher作为用户与系统交互的主界面,扮演着至关重要的角色。Launcher2是该版本中默认的桌面启动器,它...

    android4.0 Launcher源码

    通过对Android 4.0 Launcher源码的分析,开发者可以更深入地了解Android系统的架构,提高应用开发的专业技能。无论是对于系统级别的优化,还是对个人项目的需求,都能从中受益匪浅。因此,花时间研究和理解这段源码...

    android4.0 主界面源码 launcher

    Android 4.0的Launcher源码提供了一个很好的基础,开发者可以通过以下方式自定义或扩展功能: 1. 动画效果:修改或添加新的滑动、缩放等动画效果。 2. 图标和小部件行为:修改图标点击行为,或者实现自定义小部件...

    launcher源码(ADWlauncher+android4.0原生launcher)

    这里我们关注的是"launcher源码",包括ADW.Launcher和Android 4.0(Ice Cream Sandwich,简称ICS)的原生Launcher。这两个启动器在Android发展史上具有重要意义,为后来的许多定制和优化提供了基础。 首先,ADW....

    android4.0中Launcher2源码

    通过对Android 4.0中Launcher2的源码学习,开发者可以深入了解Android系统的桌面实现,掌握如何构建高效、可定制的启动器,以及如何优化用户体验。同时,这也为深入研究Android系统其他组件,如Activity、Service、...

    android 4.0 launcher分析

    回到Android 4.0 Launcher的启动流程。系统启动后,App_main进程初始化Android运行时环境,zygote进程作为所有Android应用和服务的父进程。SystemServer启动并管理各种系统服务,包括Activity Manager Service(AMS...

    Android4.0 Ice Cream Sandwich Launcher 源码

    下面我们将深入探讨Android 4.0 ICS Launcher的源码,分析其中的关键知识点。 1. **UI设计更新**:ICS引入了更加现代化的界面设计,如半透明状态栏和导航栏,以及平滑过渡效果。在源码中,你可以看到如何通过自定义...

    Android 4.0 Launcher2可导入eclipse中直接运行

    Android 4.0 的 Launcher2 是 Android 操作系统的一个核心组件,它是用户界面的主要部分,负责桌面、应用抽屉和快捷方式的管理。这个项目是为开发者提供的源代码,允许他们深入理解 Launcher2 的工作原理,并对其...

    android 4.0 Launcher2 源码

    通过深入分析 Android 4.0 Launcher2 的源码,开发者可以学习到 Android UI 设计、数据管理、事件处理、动画制作以及性能优化等多个方面的知识。这不仅有助于定制个性化桌面,也能提升对 Android 系统整体运行机制的...

    android Launcher 4.0 (原生版本)

    Android Launcher 4.0,是Android操作系统的一个重要组成部分,它作为用户与系统交互的初始界面,扮演着桌面的角色。在Android 4.0(Ice Cream Sandwich,简称ICS)这个版本中,Launcher进行了诸多改进和优化,提升...

    android4.0 launcher2

    通过分析和学习"Android 4.0 Launcher2"的源代码,开发者可以了解Android桌面启动器的设计理念,学习到如何定制自己的桌面应用,包括图标布局、动画效果、交互逻辑等方面,这对于Android开发人员深入理解系统级应用...

    安卓Android源码——Android Launcher 源码修改可编译.zip

    "安卓Android源码——Android Launcher 源码修改可编译.zip" 这个标题表明我们关注的是Android操作系统的源代码,特别是与启动器(Launcher)相关的部分。Launcher是用户与Android系统交互的主要界面,它管理应用...

    android4.0Launcher源码

    4.0Launcher的源码,在项目中的library文件中包含了编译所需要的framework_intermediates,android-common_intermediates,core_intermediates的jar文件,项目还整合了android.support.v13.dreams.BasicDream.java这...

    android 4.0 launcher2 源码eclipse可以编译

    本代码是4.0 launcher 源码. 支持4.0 4.1 系统. 真机运行截图见 shoot.png. 如果您遇到麻烦请自己搭建android开发环境:linux系统,虚拟机,下载android源码 等.这将花费有经验的您几天时间. 迅速获得编译技术支持(如果...

Global site tag (gtag.js) - Google Analytics