Android Launcher2代码跟踪

为了代码跟踪的方便我们将Launcher2源码导入到eclipse中。


在androidManifest.xml中,有如下代码:

<application
        android:name="com.android.launcher2.LauncherApplication"
        android:label="@string/application_name"
        android:icon="@mipmap/ic_launcher_home"
        android:hardwareAccelerated="true"
        android:largeHeap="@bool/config_largeHeap"
        android:supportsRtl="true">
        <activity
            android:name="com.android.launcher2.Launcher"
            android:launchMode="singleTask"
            android:clearTaskOnLaunch="true"
            android:stateNotNeeded="true"
            android:theme="@style/Theme"
            android:windowSoftInputMode="adjustPan"
            android:screenOrientation="nosensor">
            <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>

从中我们可以知道启动过程需要先后初始化LauncherApplication和Launcher的对象。更加简洁的说,启动过程可以分成两步,第一步在LauncherApplication.onCreate()方法中,第二步在Launcher.onCreate()方法中。

下面首先我们看第一步,

@Override
    public void onCreate() {
        super.onCreate();

        // set sIsScreenXLarge and sScreenDensity *before* creating icon cache
        sIsScreenLarge = getResources().getBoolean(R.bool.is_large_screen);
        sScreenDensity = getResources().getDisplayMetrics().density;

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

        // Register intent receivers
        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);

        // Register for changes to the favorites
        ContentResolver resolver = getContentResolver();
        resolver.registerContentObserver(LauncherSettings.Favorites.CONTENT_URI, true,
                mFavoritesObserver);
    }

LauncherApplication是Application的子类,是整个程序的入口。因此,一些全局信息的初始化和保存工作就放到这里执行。包括屏幕大小,像素密度信息的获取,以及BroadcastReceiver和ContentObserver的注册都在整个程序的开始就完成。

下面看Launcher的onCreate:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        if (DEBUG_STRICT_MODE) {
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                    .detectDiskReads()
                    .detectDiskWrites()
                    .detectNetwork()   // or .detectAll() for all detectable problems
                    .penaltyLog()
                    .build());
            StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                    .detectLeakedSqlLiteObjects()
                    .detectLeakedClosableObjects()
                    .penaltyLog()
                    .penaltyDeath()
                    .build());
        }

        super.onCreate(savedInstanceState);
        LauncherApplication app = ((LauncherApplication)getApplication());
        mSharedPrefs = getSharedPreferences(LauncherApplication.getSharedPreferencesKey(),
                Context.MODE_PRIVATE);
        mModel = app.setLauncher(this);
        mIconCache = app.getIconCache();
        mDragController = new DragController(this);
        mInflater = getLayoutInflater();

        mAppWidgetManager = AppWidgetManager.getInstance(this);
        mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);
        mAppWidgetHost.startListening();

        // If we are getting an onCreate, we can actually preempt onResume and unset mPaused here,
        // this also ensures that any synchronous binding below doesn't re-trigger another
        // LauncherModel load.
        mPaused = false;

        if (PROFILE_STARTUP) {
            android.os.Debug.startMethodTracing(
                    Environment.getExternalStorageDirectory() + "/launcher");
        }

        checkForLocaleChange();
        setContentView(R.layout.launcher);
        setupViews();
        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) {
            if (sPausedFromUserAction) {
                // If the user leaves launcher, then we should just load items asynchronously when
                // they return.
                mModel.startLoader(true, -1);
            } else {
                // We only load the page synchronously if the user rotates (or triggers a
                // configuration change) while launcher is in the foreground
                mModel.startLoader(true, mWorkspace.getCurrentPage());
            }
        }

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

        updateGlobalIcons();

        // On large interfaces, we want the screen to auto-rotate based on the current orientation
        unlockScreenOrientation(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中的内容

在继续分析之前,我们通过hierarchyviewer来对其整个布局有个整体的认识:


在launcher.xml中对应的代码如下:

<com.android.launcher2.DragLayer
        android:id="@+id/drag_layer"

其中的 
<com.android.launcher2.Workspace
            android:id="@+id/workspace"
对应


<include
            android:id="@+id/qsb_bar"
            layout="@layout/qsb_bar"

对应 

<include
            android:id="@+id/dock_divider"
            layout="@layout/workspace_divider"

对应



<include
            android:id="@+id/paged_view_indicator"
            layout="@layout/scroll_indicator"

对应


<include layout="@layout/hotseat"
            android:id="@+id/hotseat"

对应



<include layout="@layout/apps_customize_pane"
            android:id="@+id/apps_customize_pane"

对应



以上我们对launcher的整个布局有了个感性的认识,下面我们继续接着对launcher的onCreate进行跟踪。

1.LauncherApplication.setLauncher

LauncherModel setLauncher(Launcher launcher) {
        mModel.initialize(launcher);
        return mModel;
    }

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.LauncherAppWidgetHost.startListening

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

3.checkForLocaleChange

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

4.setupViews

/**
     * Finds all the views we need and configure them properly.
     */
    private void setupViews() {
        final DragController dragController = mDragController;

        mLauncherView = findViewById(R.id.launcher);
        mDragLayer = (DragLayer) findViewById(R.id.drag_layer);
        mWorkspace = (Workspace) mDragLayer.findViewById(R.id.workspace);
        mQsbDivider = findViewById(R.id.qsb_divider);
        mDockDivider = findViewById(R.id.dock_divider);

        mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
        mWorkspaceBackgroundDrawable = getResources().getDrawable(R.drawable.workspace_bg);
        mBlackBackgroundDrawable = new ColorDrawable(Color.BLACK);

        // Setup the drag layer
        mDragLayer.setup(this, dragController);

        // Setup the hotseat
        mHotseat = (Hotseat) findViewById(R.id.hotseat);
        if (mHotseat != null) {
            mHotseat.setup(this);
        }

        // Setup the workspace
        mWorkspace.setHapticFeedbackEnabled(false);
        mWorkspace.setOnLongClickListener(this);
        mWorkspace.setup(dragController);
        dragController.addDragListener(mWorkspace);

        // Get the search/delete bar
        mSearchDropTargetBar = (SearchDropTargetBar) mDragLayer.findViewById(R.id.qsb_bar);

        // Setup AppsCustomize
        mAppsCustomizeTabHost = (AppsCustomizeTabHost) findViewById(R.id.apps_customize_pane);
        mAppsCustomizeContent = (AppsCustomizePagedView)
                mAppsCustomizeTabHost.findViewById(R.id.apps_customize_pane_content);
        mAppsCustomizeContent.setup(this, dragController);

        // Setup the drag controller (drop targets have to be added in reverse order in priority)
        dragController.setDragScoller(mWorkspace);
        dragController.setScrollView(mDragLayer);
        dragController.setMoveTarget(mWorkspace);
        dragController.addDropTarget(mWorkspace);
        if (mSearchDropTargetBar != null) {
            mSearchDropTargetBar.setup(this, dragController);
        }
    }

在这个方法中简单的对所有的UI控件进行加载和配置:由于UI组建较多,setupViews中所进行的操作也比较繁琐,下面用一时序图来展现他们之间的关系


上图中的相关对象对应着launcher.xml的相关布局。至于相关代码,以后进行跟踪............

5.showFirstRunWorkspaceCling   在应用第一次被启动的时候,此方法会被调用,用于向用户展示一个指导界面。以后都不会再出现。

6.registerContentObservers对给定URL所代表的数据进行监听,及时对数据变化做出反应。

7.LauncherModel.startLoader   主要就是在应用启动的时候对数据进行加载,下面分析其加载过程.....


---------------------------------------------------------------------------------------------------------------------------------------------------------


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值