您的位置:首页 > 移动开发 > Android开发

Android Launcher分析和修改3——Launcher启动和初始化

2014-05-13 09:24 399 查看
转载自:http://bbs.9ria.com/thread-224974-1-1.html

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

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

  1、Launcher进程启动过程

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

  



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

  

  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的程序,只要在程序里面加入action.MAIN 、

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

  哪个作为启动器。

  2、Launcher初始化——LauncherApplication。

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

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

  我们也可以找到Application标签。

  <application <="" application[="" size][="" font]

    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">

复制代码

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

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

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

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

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

复制代码

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

  一些返回接口。

  @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来提供数据。

  其中注册的监听接口是

  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()里面分析。把主要一些分析用注释方式写在代码里面,这样比较方便阅读。

  @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相关数据。

原文链接:http://www.cnblogs.com/mythou/p/3157452.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: