1.Launcher的启动过程

从网络上找了一段关于Launcher的启动过程的文章,作为学习Launcher的背景知识:

Linuxkernel启动以后会通过app_main进程来初始化androidRuntimeJava运行环境,而zygoteAndroid的第一个进程。所有的android的应用以及大部分系统服务都是通过zygotefork出来的子进程(我现在看到的只有native的servicemanager不是zygotefork出来的)。在systemserver中启动的若干系统服务中与我们启动进程相关的就是AcitivityManager
当systermserver启动好所有服务以后,系统就进入”systemready”状态,这个时候ActivityManager就登场了。ActivityManager光看代码行就知道是一个重量级的服务,它主要管理Activity之间的跳转,以及进程的生命周期。当ActivityManager发现系统已经启动好以后它就会发出一个intent:

[c-sharp] view plain copy
  1. Intentintent=newIntent(mTopAction,mTopData!=null?Uri.parse(mTopData):null);
  2. intent.setComponent(mTopComponent);
  3. if(mFactoryTest!=SystemServer.FACTORY_TEST_LOW_LEVEL){
  4. intent.addCategory(Intent.CATEGORY_HOME);
  5. }

通过这个category类型为home的intent,ActivityManager就会通过:
[c-sharp] view plain copy
  1. startActivityLocked(null,intent,null,null,0,aInfo,
  2. null,null,0,0,0,false,false);

启动 Home 进程了。而这个启动Home进程的过程实际上还是去通过zygotefork出的一个子进程。

因此只要在manifest中具备这样的intent-filter都可以在开机的时候作为Home启动:

[c-sharp] view plain copy
  1. <intent-filter>
  2. <actionandroid:name="android.intent.action.MAIN"/>
  3. <categoryandroid:name="android.intent.category.HOME"/>
  4. <categoryandroid:name="android.intent.category.DEFAULT"/>
  5. </intent-filter>

多个home之间的switch会在开始的时候有个选择,至于这个选择好像是packagemanager来实现的,没有仔细研究过。

2.UI结构

通过launcher/Res/Layout-land/launcher.xml分析可以得到主屏幕的UI结构:

整个homescreen是一个包含三个childview的FrameLayout(com.android.launcher.DragLayer)。


第一个child就是桌面com.android.launcher.Workspace。这个桌面又包含三个child。每个child就对应一个桌面。这就是你在Android上看到的三个桌面。每个桌面上可以放置下列对象:应用快捷方式,appwidget和folder。


第二个child是一个SlidingDrawer控件,这个控件由两个子控件组成。一个是com.android.launcher.HandleView,就是Android桌面下方的把手,当点击这个把手时,另一个子控件,com.android.launcher.AllAppsGridView就会弹出,这个子控件列出系统中当前安装的所有类型为category.launcher的Activity。


第三个child是com.android.launcher.DeleteZone。当用户在桌面上长按一个widget时,把手位置就会出现一个垃圾桶形状的控件,就是这个控件。

3.应用程序代码分析

Launcher中的AndroidManifest.xml可以看出整个Launcher的代码结构。

首先,是一些权限的声明。例如:

[c-sharp] view plain copy
  1. <uses-permissionandroid:name="android.permission.CALL_PHONE"/>
  2. <uses-permissionandroid:name="android.permission.EXPAND_STATUS_BAR"/>

这部分可以略过;

其次,Application的构成,如上图:

(1)LauncherHomeScreenActivity

[c-sharp] view plain copy
  1. <intent-filter>
  2. <actionandroid:name="android.intent.action.MAIN"/>
  3. <categoryandroid:name="android.intent.category.HOME"/>
  4. <categoryandroid:name="android.intent.category.DEFAULT"/>
  5. <categoryandroid:name="android.intent.category.MONKEY"/></intent-filter>

上面这段代码就标志着它是开机启动后HomeActivity。通过Launcher.javaonCreat()的分析我们可以大致把握屏幕的主要活动:

[c-sharp] view plain copy
  1. protectedvoidonCreate(BundlesavedInstanceState){
  2. super.onCreate(savedInstanceState);
  3. //把xml文件的内容实例化到View中
  4. mInflater=getLayoutInflater();
  5. //监听应用程序控件改变事件
  6. mAppWidgetManager=AppWidgetManager.getInstance(this);
  7. mAppWidgetHost=newLauncherAppWidgetHost(this,APPWIDGET_HOST_ID);
  8. mAppWidgetHost.startListening();
  9. //用于调试?
  10. if(PROFILE_STARTUP){
  11. android.os.Debug.startMethodTracing("/sdcard/launcher");
  12. }
  13. //监听locale,mcc,mnc是否改变,如果改变,则重写新配置
  14. //mcc:mobilecountrycode(国家代码China460);mnc:mobilenetworkcode(网络代码)
  15. checkForLocaleChange();
  16. /*Thisallowssuchapplicationstohaveavirtualwallpaperthatislargerthanthephysicalscreen,matchingthesizeoftheirworkspace.*/
  17. setWallpaperDimension();
  18. //显示主屏幕UI元素,workspace,slidingdrawer(handleviewandappgridview),deletezone
  19. setContentView(R.layout.launcher);
  20. //Findsalltheviewsweneedandconfigurethemproperly.
  21. //完成workspace,slidingdrawer,deletezone的各种事件操作和监听
  22. setupViews();
  23. //Registersvariousintentreceivers.
  24. //允许其他应用对本应用的操作
  25. registerIntentReceivers();
  26. //Registersvariouscontentobservers.
  27. //例如,注册一个内容观察者跟踪喜爱的应用程序
  28. registerContentObservers();
  29. //重新保存前一个状态(目的??)
  30. mSavedState=savedInstanceState;
  31. restoreState(mSavedState);
  32. //调试?
  33. if(PROFILE_STARTUP){
  34. android.os.Debug.stopMethodTracing();
  35. }
  36. //LoadsthelistofinstalledapplicationsinmApplications.
  37. if(!mRestoring){
  38. startLoaders();
  39. }
  40. //Forhandlingdefaultkeys??
  41. mDefaultKeySsb=newSpannableStringBuilder();
  42. Selection.setSelection(mDefaultKeySsb,0);
  43. }

方法onActivityResult():完成在workspace上增加shortcutappwidgeLivefolder

方法onSaveInstantceState()和onRestoreInstanceState():为了防止SensorLandPort布局自动切换时数据被置空,通过onSaveInstanceState方法可以保存当前窗口的状态,在即将布局切换前将当前的Activity压入历史堆栈。如果我们的Activity在后台没有因为运行内存吃紧被清理,则切换时回触发onRestoreIntanceState()


(2)WallpaperChooser:设置墙纸。

同理我们从onCreat()作为入口来分析这个活动的主要功能。

[c-sharp] view plain copy
  1. publicvoidonCreate(Bundleicicle){
  2. super.onCreate(icicle);
  3. //设置允许改变的窗口状态,需在setContentView之前调用
  4. requestWindowFeature(Window.FEATURE_NO_TITLE);
  5. //添加墙纸资源,将资源标识符加入到动态数组中
  6. findWallpapers();
  7. //显示墙纸设置屏幕的UI元素,Imageview,GalleryandButton(LinearLayout)
  8. setContentView(R.layout.wallpaper_chooser);
  9. //图片查看功能的实现
  10. mGallery=(Gallery)findViewById(R.id.gallery);
  11. mGallery.setAdapter(newImageAdapter(this));
  12. mGallery.setOnItemSelectedListener(this);
  13. mGallery.setCallbackDuringFling(false);
  14. //Button事件监听,点击选择setWallpaper(Resid)
  15. findViewById(R.id.set).setOnClickListener(this);
  16. mImageView=(ImageView)findViewById(R.id.wallpaper);
  17. }

(3)default_searchable

对于home中任意的Acitivty,使能系统缺省Search模式,这样就可以使用android系统默认的searchUI


(4)InstallShortcutReceiver

继承自BroadcastReceiver,重写onReceier()方法,对于发送来的Broadcast(这里指Intent)进行过滤(IntentFilt)并且响应(这里是InstallShortcut())。这里分析下onReceive():

[c-sharp] view plain copy
  1. <!--Enablesystem-defaultsearchmodeforanyactivityinHome-->
  2. <!--Intentreceivedusedtoinstallshortcutsfromotherapplications-->
  3. publicvoidonReceive(Contextcontext,Intentdata){
  4. //接受并过滤Intent
  5. if(!ACTION_INSTALL_SHORTCUT.equals(data.getAction())){
  6. return;
  7. }
  8. //获取屏幕
  9. intscreen=Launcher.getScreen();
  10. //安装快捷方式
  11. if(!installShortcut(context,data,screen)){
  12. //如果屏幕已满,搜寻其他屏幕
  13. for(inti=0;i<Launcher.SCREEN_COUNT;i++){
  14. if(i!=screen&&installShortcut(context,data,i))break;
  15. }
  16. }
  17. }

其中IntallShortcut()方法:首先,对传入的坐标进行判断(findEmptyCell(),如果是空白位置,则可以放置快捷方式;其次,缺省情况下,我们允许创建重复的快捷方式,具体创建过程(addShortcut())就是把快捷方式的信息传入数据库(addItemToDatabase())。


(5)UninstallShortcutReceiver

同理,UninstallShortcutReceiver()继承自BroadcastReceiver(),实现onReceiver()方法。定义一个ContentResolver对象完成对数据库的访问和操作(通过URI定位),进而删除快捷方式 。


(6)LauncherProvider

继承自ContentProvider(),主要是建立一个数据库来存放HomeScreen中的数据信息,并通过内容提供者来实现其他应用对launcher中数据的访问和操作。

重写了ContentProvider()中的方法

getType():返回数据类型。如果有自定义的全新类型,通过此方法完成数据的访问。

query():查询数据。传入URI,返回一个Cursor对象,通过Cursor完成对数据库数据的遍历访问。

Insert():插入一条数据。

bulkInsert():大容量数据的插入。

delete():删除一条数据。

update():更改一条数据。

sendNotify():发送通知。

DatabaseHelper继承自一个封装类SQLiteOpenHelper(),方便了数据库的管理和维护。

重写的方法:

onCreate():创建一个表。其中db.execSQL()方法执行一条SQL语句,通过一条字符串执行相关的操作。当然,对SQL基本语句应该了解。

onUpgrade():升级数据库。

HomeScreen数据库操作的一些方法:

addClockWidget(),addSearchWidget,addShortcut,addAppShortcut,

loadFavorites(),launcherAppWidgetBinder(),convertWidget(),updateContactsShortcuts(),

copyFromCursor()

补充:

类AddAdapter(AddAdapter.java)列出了这四个类型对象。当用户在桌面空白处长按时,下列函数序列被执行:

Launcher::onLongClick-->

Launcher::showAddDialog-->

Launcher::showDialog(DIALOG_CREATE_SHORTCUT);-->

Launcher::onCreateDialog-->

Launcher::CreateShortcut::createDialog:这个函数创建一个弹出式对话框,询问用户是要添加什么(快捷方式,appwidget,文件夹和墙纸)其内容就来自AddAdapter。

类DesktopItemsLoader负责将桌面上所有的对象从contentprovider中提取。

线程privateApplicationsLoadermApplicationsLoader负责从包管理器中获取系统中安装的应用列表。(之后显示在AllAppsGridView上)。ApplicationsLoader::run实现:
1)通过包管理器列出系统中所有类型为Launcher,action为MAIN的activity;
2)对每一个Activity,
a)将Activity相关元数据信息,如title,icon,intent等缓存到appInfoCache;
b)填充到ApplicationsAdapter中。填充过程中用到了一些小技巧,每填充4(UI_NOTIFICATION_RATE)个activity更新一下相应view。

在Launcher::onCreate中,函数startLoaders被调用。而该函数接着调用loadApplications和loadUserItems,分别获取系统的应用列表,以及显示在桌面上的对象列表(快捷方式,appwidget,folder等)。
Launcher上排列的所有应用图标由AllAppsGridView对象呈现。这个对象是一个GridView。其对应的Adapter是ApplicationsAdapter,对应的model则是ApplicationInfo数组。数组内容是由ApplicationsLoader装载的。

更多相关文章

  1. Android流式布局实现
  2. Android(安卓)- GridView,自定义开关控件,状态选择器selector,自定
  3. Android属性动画,从源码的角度分析
  4. Android(安卓)相对布局:RelativeLayout
  5. Android中Activity组件详解
  6. Android:你要的WebView与 JS 交互方式 都在这里了
  7. android之视频播放
  8. Android与JS互调的简单使用
  9. 【Android】Android(安卓)4.0 无法接收开机广播的问题

随机推荐

  1. Ubuntu下为AndroidStudio编译并使用x264(
  2. Android(安卓)的回调事件详解
  3. Android(安卓)HAL 开发 (4)
  4. android manager 更新 android的有效方法
  5. 设置android软键盘,默认不弹出的方法
  6. Android(安卓)学习(1)——AndroidStudio安
  7. android LayoutInflater的使用
  8. Android(安卓)学习记录-获取天气API
  9. Android中launcherMode="singleTask"详解
  10. linux 下 使用shell 控制ant批量打包