1. Launcher的启动过程

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

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

view plain copy to clipboard print ?
  1. Intentintent= new Intent(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就会通过:
view plain copy to clipboard print ?
  1. startActivityLocked( null ,intent, null , null ,0,aInfo,
  2. null , null ,0,0,0, false , false );

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

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

view plain copy to clipboard print ?
  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 的代码结构。

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

view plain copy to clipboard print ?
  1. <uses-permissionandroid:name= "android.permission.CALL_PHONE" />
  2. <uses-permissionandroid:name="android.permission.EXPAND_STATUS_BAR" />

这部分可以略过;

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

(1) Launcher HomeScreen Activity


view plain copy to clipboard print ?
  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>

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

view plain copy to clipboard print ?
  1. protected void onCreate(BundlesavedInstanceState){
  2. super.onCreate(savedInstanceState);
  3. //把xml文件的内容实例化到View中
  4. mInflater=getLayoutInflater();
  5. //监听应用程序控件改变事件
  6. mAppWidgetManager=AppWidgetManager.getInstance(this );
  7. mAppWidgetHost=new LauncherAppWidgetHost( 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=new SpannableStringBuilder();
  42. Selection.setSelection(mDefaultKeySsb,0);
  43. }

方法 onActivityResult(): 完成在workspace 上增加 shortcut appwidge Livefolder

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


(2) WallpaperChooser :设置墙纸。

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

view plain copy to clipboard print ?
  1. public void onCreate(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(new ImageAdapter( 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():

view plain copy to clipboard print ?
  1. <!--Enablesystem- default searchmode for anyactivity in Home-->
  2. <!--Intentreceivedusedtoinstallshortcutsfromotherapplications-->
  3. public void onReceive(Contextcontext,Intentdata){
  4. //接受并过滤Intent
  5. if (!ACTION_INSTALL_SHORTCUT.equals(data.getAction())){
  6. return ;
  7. }
  8. //获取屏幕
  9. int screen=Launcher.getScreen();
  10. //安装快捷方式
  11. if (!installShortcut(context,data,screen)){
  12. //如果屏幕已满,搜寻其他屏幕
  13. for ( int i=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 完成对数据库数据的遍历访问。

I nsert():插入一条数据。

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中提取。

线程private ApplicationsLoader mApplicationsLoader负责从包管理器中获取系统中安装的应用列表。(之后显示在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 xml中?和 @
  2. Android(安卓)实用工具Hierarchy Viewer实战
  3. android onResume is called before you unlock the phone
  4. Kotlin 中Butterknife 和Android(安卓)中使用butterknife
  5. Android(安卓)布局深度优化(减少布局层次)
  6. Android控件TextView中ellipsize属性(设置当文字长度超过textview
  7. Android(安卓)屏幕适配:最全面的解决方案
  8. 关于Android分辨率的支持
  9. Android(安卓)控件一 TextView

随机推荐

  1. android 让TextView自带滚动条
  2. [导入]超酷的android翻屏效果,不要错过
  3. Android之桌面组件AppWidget
  4. Android 动态切换底部tab按钮
  5. 【Android】在任何View上添加红点★★★
  6. 如何去掉ListView底部的ListDivider
  7. 视频聊天系统源码Android 播放视频
  8. Android文件下载使用Http协议
  9. Android(安卓)MP3录音实现
  10. Apktool 回编译出现No resource identifi