zoukankan      html  css  js  c++  java
  • Android Launcher分析和修改3——Launcher启动和初始化

    前面两篇文章都是写有关Launcher配置文件的修改,代码方面涉及不多,今天开始进入Launcher代码分析。

    我们开机启动Launcher,Launcher是由Activity Manager启动的,而Activity Manager是由system server启动。

    原创博文,转载请标明出处:http://www.cnblogs.com/mythou/p/3157452.html 

    1、Launcher进程启动过程

    可以由下面图看到Launcher进程是如何被创建启动:

    Activity Manager通过发送Intend来启动Launcher。

    
    
    //Edited by mythou
    //http://www.cnblogs.com/mythou/
    Intent intent = new Intent(mTopAction, mTopData != null ? 
    Uri.parse(mTopData) : null); intent.setComponent(mTopComponent); if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL)
    { intent.addCategory(Intent.CATEGORY_HOME); }
    startActivityLocked(
    null, intent, null, null, 0, aInfo, null, null, 0, 0, 0, false, false);

    因此,如果你要开机启动一个替换Launcher的程序,只要在程序<intent-filter>里面加入action.MAIN 、

    category.HOME、category.DEFAULT就可以。如果出现多个程序都加入这种intent,系统会弹出让你选择

    哪个作为启动器。

     

    2、Launcher初始化——LauncherApplication。

    Application类,我想大部分做Android应用的朋友都用过,每个Android应用默认都有一个Application类,

    你也可以继承Application类,然后加入自己代码。Application是一个全局的应用类,在AndroidManifest.xml

    我们也可以找到Application标签。

    
    
    //Edited by mythou
    //http://www.cnblogs.com/mythou/
     <application
            android:name="com.android.launcher2.LauncherApplication"
            android:label="@string/application_name"  
            android:icon="@drawable/ic_launcher_home"
            android:hardwareAccelerated="@bool/config_hardwareAccelerated"
            android:largeHeap="@bool/config_largeHeap"
            android:configChanges="locale">
      </application>    

    Android四大组件的声明都需要放到application标签里面,默认使用的是系统的Application类,如果你在项目

    里面重载了它。就需要在标签,name属性下写上你的新的Application类名。Launcher里面就是继承了Application

    LauncherApplication。应用启动的时候首先会加载Application。

    我们可以看到Launcher主类Launcher.java的onCreate函数里面,第一个就是获取Application的实例。

    LauncherApplication app = ((LauncherApplication)getApplication());

     

    接下来我们看看LauncherApplication里面初始化,LauncherApplication大部分工作就是在初始化完成,剩下都是

    一些返回接口。

    
    
    //Edited by mythou
    //http://www.cnblogs.com/mythou/
       @Override
        public void onCreate() 
    { super.onCreate();
    //获取屏幕大小,主要用来区分手机还是平板 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;      //IconCahe里面保存了界面所有应用图标的绘画需要的数据,这个到时候具体分析再说。
    //加入这东西的主要原因是为了提高绘画界面的效率 mIconCache
    = new IconCache(this); //数据库加载类,LauncherModel是Launcher里面非常重要的一个类,相当于MVC模式里面的
         //Model功能,管理数据和初始化数据
    mModel = new LauncherModel(this, mIconCache); //下面注册了一些监听器,主要包含APK文件更新删除等数据变化的时候接收的通知
      //接收通知后,主要是用来更新Launcher里面的数据库。因为桌面应用图标数据,只会加载一次 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); 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);
        
    //contentresolver则是用于管理所有程序的contentprovider实例 ContentResolver resolver = getContentResolver(); //注册内容观察者,监听application数据库变化,回调 resolver.registerContentObserver(LauncherSettings.Favorites.CONTENT_URI, true, mFavoritesObserver); }

    上面是LauncherApplication最主要的工作,初始化整个Launcher的一些关键类,和注册一些监听器。主要都是用

    来监听应用的安装更新删除等导致Launcher数据库变化的操作。Launcher数据都是使用contentprovider来提供数据。

    其中注册的监听接口是

    
    
    //Edited by mythou
    //http://www.cnblogs.com/mythou/
        private final ContentObserver mFavoritesObserver = new ContentObserver(new Handler()) 
        {
            @Override
            public void onChange(boolean selfChange) 
            {
           //重新加载界面数据 mModel.startLoader(LauncherApplication.
    this, false); } };
    LauncherSettings.Favorites.CONTENT_URI里面数据发生变化的时候,都会调用mModel.startLoader()接口,
    重新加载Launcher的数据。startLoader的具体操作,我后面分析LauncherModel类的时候会分析。这一块涉及
    Launcher所有数据加载。
    剩下的接都是返回初始化时候创建的对象或者获取屏幕密度、获取是否大屏幕。
    后面很多处理都需要判断是否是大屏幕,4.0以后手机平板都共用一套系统,导致多了很多处理。

     

    3、Launcher.java初始化

    Launcher.java是Launcher里面最主要的类,是一个Activity。启动的第一个组件。既然是Activity,我们要分析它

    初始化,毫无疑问,需要找到onCreate()里面分析。把主要一些分析用注释方式写在代码里面,这样比较方便阅读。

     

    
    
    //Edited by mythou
    //http://www.cnblogs.com/mythou/
     @Override
        protected void onCreate(Bundle savedInstanceState) 
      { super.onCreate(savedInstanceState);
    //获取Application 实例 LauncherApplication app = ((LauncherApplication)getApplication());
         //LauncherModel类里面获取Launcher的对象引用 mModel
    = app.setLauncher(this);
    //获取IconCache,IconCache在Application里面初始化     mIconCache
    = app.getIconCache(); mDragController = new DragController(this); mInflater = getLayoutInflater(); mAppWidgetManager = AppWidgetManager.getInstance(this); //监听widget改变,以后在Model里面回调处理的结果 mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID); mAppWidgetHost.startListening();
         //这个是设置Launcher的跟踪调试文件,下面很多信息会写到这个文件里面。
    if (PROFILE_STARTUP)
         { android.os.Debug.startMethodTracing( Environment.getExternalStorageDirectory()
    + "/launcher"); } //读取本地配置,保存更新配置,清空IconCache checkForLocaleChange(); setContentView(R.layout.launcher); //对所有的UI控件进行加载和配置 setupViews(); //显示操作提示,第一次启动的时候才会显示 showFirstRunWorkspaceCling(); //注册监控Launcher数据库变化 registerContentObservers();      //锁住APP,初始化不能操作。 lockAllApps(); mSavedState = savedInstanceState; restoreState(mSavedState); // Update customization drawer _after_ restoring the states if (mAppsCustomizeContent != null)
         { mAppsCustomizeContent.onPackagesUpdated(); }
    if (PROFILE_STARTUP)
         { android.os.Debug.stopMethodTracing(); }
    //加载启动数据,所有界面数据(快捷方式、folder、widget、allApp)等在loader里面加载,这部分后面我会详细分析。 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);
         //下面这几个就是Android原生界面上的Market、搜索、声音输入按钮的默认图标显示。 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); } Log.i(TAG,
    "------------------------>Launcher init over") ; }

     上面就是Launcher.java的初始化,大部分我都写了注释。其实这里最主要的工作是加载界面数据:

    mModel.startLoader(this, true); 这块实现是在LauncherModel里面实现的。下一篇文章,我会详细

    说明如何加载和获取管理系统里面的APP相关数据。

    今天就讲到这里,如发现问题,请留言指出,欢迎留言讨论。

     

     相关系列文章:

    Android Launcher分析和修改1——Launcher默认界面配置(default_workspace)

    Android Launcher分析和修改2——Icon修改、界面布局调整、壁纸设置

     

     

  • 相关阅读:
    python 创建文件夹
    Python利用pandas处理Excel数据的应用
    解决git rebase操作后推送远端分支不成功的问题
    LeetCode 1 两数之和
    LeetCode 70 爬楼梯
    LeetCode 11 盛水最多的容器
    LeetCode 283 移动零
    数据结构与算法 ---- 数组 -- Array
    跳表???
    自顶向下编程
  • 原文地址:https://www.cnblogs.com/mythou/p/3157452.html
Copyright © 2011-2022 走看看