一、Android的应用程序的入口定义在AndroidManifest.xml文件中可以找出:

<manifest 
xmlns:android="http://schemas.android.com/apk/res/android" 
package="com.android.launcher"> 
 
<original-package android:name="com.android.launcher2" /> 
... 
<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">      --运行时最小堆内存,避免内存out of memory错误的出现    > 
    <activity 
        android:name="com.android.launcher2.Launcher" 
        ... 
        > 
        <intent-filter> 
            <action android:name="android.intent.action.MAIN" /> 
            <category android:name="android.intent.category.HOME" /> 
            <category android:name="android.intent.category.DEFAULT" /> 
            <category android:name="android.intent.category.MONKEY"/> 
        </intent-filter> 
    </activity> 
    ... 
</application> 
</manifest>

二、

LauncherApplication----onCreate 应用入口

1)获取屏幕的显示尺寸、来判断是否是大屏幕,同时得到它的屏幕密度全局变量。

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;

2)建立应用图标缓存器;创建LauncherModel 对象,在launcher数据变更时操作数据库。

mIconCache = new IconCache(this);
mModel = new LauncherModel(this, mIconCache);

//LauncherModel主要用于加载桌面的图标、插件和文件夹,同时LaucherModel是一个广播接收器,在程序包发生改变、区域、或者配置文件发生改变时,都会发送广播给LaucherModel,LaucherModel会根据不同的广播来做相应加载操作

3)注册(Intent.ACTION_PACKAGE_ADDED  Intent.ACTION_PACKAGE_REMOVED  Intent.ACTION_PACKAGE_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);

4)注册本地化配置变化监听,搜寻相关变化监听,外部存储上的应用变化监听。接收器同上

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

5)注册对桌面favorites content provider 数据变化监听器,触发后执行onChang方法。

ContentResolver resolver = getContentResolver();
resolver.registerContentObserver(LauncherSettings.Favorites.CONTENT_URI, true,
mFavoritesObserver);Launcher Activity:实现了点击、长按、触屏、LauncherModel,AllAppViews接口。
protected void onCreate(Bundle savedInstanceState) { 
    ... 
    mModel = app.setLauncher(this); 
    mIconCache = app.getIconCache(); 
    ... 
    mAppWidgetManager = AppWidgetManager.getInstance(this); 
    mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID); 
    mAppWidgetHost.startListening(); 
    ... 
    //检查本地保存的配置是否需要更新 
    checkForLocaleChange(); 
    setContentView(R.layout.launcher); 
    //对UI控件进行初始化和配置 
    setupViews(); 
    //向用户展示指导的页面 
    showFirstRunWorkspaceCling(); 
    registerContentObservers(); 
    ... 
    if (!mRestoring) { 
    //为Launcher加载数据 
        mModel.startLoader(this, true); 
    } 
    ... 
}

可以将Launcher.onCreate()所执行的操作大概分为七步:
1、LauncherAppliaction.setLauncher()。
2、AppWidgetHost.startListening(),对widget事件进行监听
3、checkForLocaleChange(),检查更新本地保存的配置文件
4、setupViews(),配置UI控件
5、showFirstRunWorkspaceCling(),第一次启动时显示的指导画面
6、registerContentObservers(),设置内容监听器
7、LauncherModel.startLoader(),为Launcher加载Workspace和AllApps中的内容

三、下面具体来看启动过程中到底做了些什么

1、LauncherModel setLauncher(Launcher launcher) {
  mModel.initialize(launcher);
  return mModel;
}/**
* Set this as the current Launcher activity object for the loader.
*/
public void initialize(Callbacks callbacks) {
  synchronized (mLock) {
    mCallbacks = new WeakReference<Callbacks>(callbacks);
  }
}

由于Launcher实现了Callback接口。在mModel中,将传入的Launcher对象向下转型为Callback赋值给mCallbacks变量。并在LauncherModel中获得了一个Callbacks的软引用。通过这一过程,将Launcher对象作为Callback与mModel进行绑定,当mModel后续进行操作时,Launcher可以通过回调得到结果。

2、mAppWidgetHost.startListening()

LauncherAppWidgetHost继承自AppWidgetHost,它的作用就是帮助Launcher管理AppWidget,并且能够捕获长按事件,使得应用可以正常的删除、添加AppWidget。通过调用mAppWidgetHost.startListening()方法,开启监听。

3、checkForLocaleChange()

private void checkForLocaleChange() {
  if (sLocaleConfiguration == null) {
    new AsyncTask<Void, Void, LocaleConfiguration>() {
    @Override
      protected LocaleConfiguration doInBackground(Void... unused) {
        LocaleConfiguration localeConfiguration = new LocaleConfiguration();
        readConfiguration(Launcher.this, localeConfiguration);
        return localeConfiguration;
    }    @Override
    protected void onPostExecute(LocaleConfiguration result) {
      sLocaleConfiguration = result;
      checkForLocaleChange(); // recursive, but now with a locale configuration
    }
      }.execute();
    return;
    }  final Configuration configuration = getResources().getConfiguration();
  final String previousLocale = sLocaleConfiguration.locale;
  final String locale = configuration.locale.toString();  final int previousMcc = sLocaleConfiguration.mcc;
  final int mcc = configuration.mcc;  final int previousMnc = sLocaleConfiguration.mnc;
  final int mnc = configuration.mnc;  boolean localeChanged = !locale.equals(previousLocale) || mcc != previousMcc || mnc != previousMnc;
  if (localeChanged) {
    sLocaleConfiguration.locale = locale;
    sLocaleConfiguration.mcc = mcc;
    sLocaleConfiguration.mnc = mnc;    mIconCache.flush();
    final LocaleConfiguration localeConfiguration = sLocaleConfiguration;
    new Thread("WriteLocaleConfiguration") {
      @Override
      public void run() {
      writeConfiguration(Launcher.this, localeConfiguration);
      }
    }.start();
  }
}

在这个方法中,先是检查了本地文件的配置与当前设备的配置是否一致,如果不一致,则更新配置,并且清空IconCache,因为配置的改变可能会改变语言环境,所以需要清空IconCache中的内容重新加载。

4、setupViews()  这个方法中简单的对所有的UI控件进行加载和配置

I、mDragLayer = (DragLayer) findViewById(R.id.drag_layer);
        mWorkspace = (Workspace) mDragLayer.findViewById(R.id.workspace);
        mQsbDivider = (ImageView) findViewById(R.id.qsb_divider);
        mDockDivider = (ImageView) findViewById(R.id.dock_divider);        // Setup the drag layer
        mDragLayer.setup(this, dragController);DragLayer继承自FrameLayout,是整个Launcher的根容器。当快捷图标或者AppWidget被拖拽时,事件的处理就在DragLayer进行操作的。
 public void setup(Launcher launcher, DragController controller) {
          mLauncher = launcher;
          mDragController = controller;
    }

只是简单的做了赋值操作,使DragLayer持有Launcher和DragController对象的引用。DragController可以帮助其实现拖拽操作。

II、Hotseat也是FrameLayout的直接子类,代表主屏幕下方的dock栏,可以放置4个快捷图标和一个进入AllApps的按钮。

mHotseat = (Hotseat) findViewById(R.id.hotseat);
        if (mHotseat != null) {
              mHotseat.setup(this);
        }public void setup(Launcher launcher) {
  mLauncher = launcher;
  setOnKeyListener(new HotseatIconKeyEventListener());
}mHotseat.setup()方法调用之后,Hotseat持有Launcher对象的引用,并且用HotseatIconKeyEvenListener对自身的按键进行监听,进入HotseatIconKeyEvenListener
/**
 * A keyboard listener we set on all the hotseat buttons.
 */
class HotseatIconKeyEventListener implements View.OnKeyListener {
      public boolean onKey(View v, int keyCode, KeyEvent event) {
            final Configuration configuration = v.getResources().getConfiguration();
            return FocusHelper.handleHotseatButtonKeyEvent(v, keyCode, event, configuration.orientation);
      }
}调用方法handleHotseatButtonKeyEvent()来处理相应的事件
 /**
     * Handles key events in the workspace hotseat (bottom of the screen).
     */
    static boolean handleHotseatButtonKeyEvent(View v, int keyCode, KeyEvent e, int orientation) {
          final ViewGroup parent = (ViewGroup) v.getParent();
          final ViewGroup launcher = (ViewGroup) parent.getParent();
          final Workspace workspace = (Workspace) launcher.findViewById(R.id.workspace);
          final int buttonIndex = parent.indexOfChild(v);
          final int buttonCount = parent.getChildCount();
          final int pageIndex = workspace.getCurrentPage();        // NOTE: currently we don't special case for the phone UI in different
        // orientations, even though the hotseat is on the side in landscape mode.  This
        // is to ensure that accessibility consistency is maintained across rotations.          final int action = e.getAction();
          final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
          boolean wasHandled = false;
          switch (keyCode) {
                case KeyEvent.KEYCODE_DPAD_LEFT:
                      if (handleKeyEvent) {
                          // Select the previous button, otherwise snap to the previous page
                            if (buttonIndex > 0) {
                                  parent.getChildAt(buttonIndex - 1).requestFocus();
                            } else {
                                  workspace.snapToPage(pageIndex - 1);
                            }
                      }
                      wasHandled = true;
                      break;
              case KeyEvent.KEYCODE_DPAD_RIGHT:
                    if (handleKeyEvent) {
                          // Select the next button, otherwise snap to the next page
                          if (buttonIndex < (buttonCount - 1)) {
                                parent.getChildAt(buttonIndex + 1).requestFocus();
                          } else {
                                workspace.snapToPage(pageIndex + 1);
                            }
                      }
                      wasHandled = true;
                      break;
              case KeyEvent.KEYCODE_DPAD_UP:
                    if (handleKeyEvent) {
                          // Select the first bubble text view in the current page of the workspace
                          final CellLayout layout = (CellLayout) workspace.getChildAt(pageIndex);
                          final CellLayoutChildren children = layout.getChildrenLayout();
                          final View newIcon = getIconInDirection(layout, children, -1, 1);
                          if (newIcon != null) {
                                newIcon.requestFocus();
                          } else {
                                workspace.requestFocus();
                           }
                     }
                    wasHandled = true;
                    break;
              case KeyEvent.KEYCODE_DPAD_DOWN:
                    // Do nothing
                    wasHandled = true;
                    break;
              default: break;
          }
          return wasHandled;
    }

III、未完待续