launcher.apk 分析

http://blog.sina.com.cn/s/blog_674212810100y8t5.html

Launcher.apk是android runtime的一部分,是系统起来运行的第一个应用程序。它的主要功能就是设置桌面背景图片,加载两个widget(桌面的小应用程序),分别是clock 和search。然后设置menu按键后的内容,并实现具体的功能。Oncreate()是它运行的第一个函数。

Oncreate()

clip_image001|--setMinimumHeapSize(4M)

|--mInflater = getLayoutInflater() 新建一个layout的解压缩器

|--setWallpaperDimension() 设置横屏和竖屏的坐标参数

|-- enableSensors(); 检查sensor是否已经打开

|-- enableOpenGL(); 检查opengl是否已经打开

|-- setupViews(); 主要是画桌面背景

|--registerIntentReceivers(); 注册IntentReceivers来监测状态的变化以便相应的产生动作

|-- registerContentObservers(); 注册ContentObservers

|--restoreState() 保存状态

|--startLoaders() 用来加载其他应用程序和用户items,函数具体实现在LauncherModel.java中

clip_image002 |--loadApplications() Loads the list of installed applications in mApplications.

|--new ApplicationsAdapter()

|--mLoader.join(APPLICATION_NOT_RESPONDING_TIMEOUT) (mLoader是一个线程)

|--new ApplicationsLoader() (mApliacationsLoader是一个线程)

clip_image003 |--Intent(Intent.ACTION_MAIN, null) 其他应用程序Manifest.xml中会用到

|--mainIntent.addCategory(Intent.CATEGORY_LAUNCHER)

|--Launcher launcher = mLauncher.get() {AllAppsGridView.java}

|--PackageManager manager = launcher.getPackageManager()

|-- manager.queryIntentActivities(mainIntent, 0)

|--ChangeNotifier action = new ChangeNotifier(applicationList) (ChangeNotifier 是一个线程)

|--用一个循环把所有的app都加载进来

|--loadUserItems()

|--launcher.onDesktopItemsLoaded() {launcher.java中onDesktopItemsLoaded()}

clip_image004[4] |--bindDesktopItems() Refreshes the shortcuts shown on the workspace

|--ItemInfo item = shortcuts.get(i)

|--switch (item.itemType)

|--case Settings.Favorites.ITEM_TYPE_APPLICATION:

case Settings.Favorites.ITEM_TYPE_SHORTCUT:

|-- createShortcut((ApplicationInfo) item)

|-- createShortcut() 新建一个快捷方式

|--case Settings.Favorites.ITEM_TYPE_USER_FOLDER

|-- 建立一个新的USER_FOLDER(用户文件夹)

|-- default:

|-- createWidget(mInflater, widget)

|--openUserFolder() 建立一个新的USER_FOLDER(用户文件夹)

|--new DesktopItemsLoader(launcher) DesktopItemsLoader是一个线程

clip_image005 |--int itemType = c.getInt(itemTypeIndex)

|--switch (itemType)

case Settings.Favorites.ITEM_TYPE_APPLICATION:

case Settings.Favorites.ITEM_TYPE_SHORTCUT:

|--intent = Intent.getIntent(c.getString(intentIndex))

|--case Settings.Favorites.ITEM_TYPE_USER_FOLDER

|--findOrMakeFolder(userFolders, id)

|--case Settings.Favorites.CONTAINER_DESKTOP

|--desktopItems.add(folderInfo) 添加到桌面上

|--case Settings.Favorites.ITEM_TYPE_WIDGET_CLOCK:

case Settings.Favorites.ITEM_TYPE_WIDGET_SEARCH:

case Settings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME:

clip_image006[4] |--switch (itemType)

|--case Settings.Favorites.ITEM_TYPE_WIDGET_CLOCK

|--Widget.makeClock() 添加一个时钟在当前界面上

|--case Settings.Favorites.ITEM_TYPE_WIDGET_SEARCH

|--Widget.makeSearch() 在当前界面上添加一个google search

|--case Settings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME

|--Widget.makePhotoFrame() 在当前界面添加一章小图片

还有一个重要的部分就是当menu按键按下时定义的内容。下面是函数的调用情况以及函数的功能

OnCreateOptionsMenu() 来定义menu的菜单

clip_image007 ADD 、SEARCH_SETTING、NOTIFICATION、WALLPAPER_SETTING、SETTING

OnPrepareOptionsMenu() display the menu

clip_image008[4]

OnOptionsItemSelected() 当选择了Menu中的选项时执行相应动作

clip_image009|--MENU_ADD

|--addItems()

|--showAddDilog()

|--showDialog()

|--MENU_WALLPAPER_SETTING

|--startWallpaper() {home.java}

|--intent(ACTION_SET_WALLPAPER) 启动一个intent来设置背景图片

|--MENU_SEARCH

|--onSearchRequested() {SearchInvoke.java}

|--MENU_NOTIFICATIONS

|--showNotifications()

|--getSystemService(STATUB_BAR_SERVICE) 启动系统的sevice来显示notification

|--MENU_SETTING

|--Intent(android.provider.Settings.ACTION_SETTINGS) 启动一个intent来进行系统的设置

startActivityForResult(Intent intent, int requestCode)用来启动一个intent并接收从它返回的数据,用setResult()来设置返回值,用onActivityResult(int requestCode, int resultCode, Intent data)对返回的数据进行相应的处理。

onActivityResult(int requestCode, int resultCode, Intent data)

|--completeAddShortcut(data, mAddItemCellInfo, !mDesktopLocked);

(requestCode=REQUEST_CREATE_SHORTCUT)

|-- sModel.addDesktopItem(info) {LauncherModel.java}

|-- mDesktopItems.add(info) 将ItemInfo info 加入到ArrayList中

|-- createShortcut(info)

|-- createShortcut() 新建一个快捷方式

|--completeAddPhotoFrame(data, mAddItemCellInfo); Add a PhotFrame to the workspace

(requestCode=REQUEST_CHOOSE_PHOTO)

|--completeUpdatePhotoFrame(data, mAddItemCellInfo); Updates a workspace PhotoFrame

(requestCode=REQUEST_UPDATE_PHOTO)

相关知识链接:

ContentObservers http://tech.it168.com/j/2008-02-25/200802250125273.shtml

Widget http://baike.baidu.com/view/704016.htm

IntentReceivers http://bbs2.chinaunix.net/archiver/tid-1320757.html

Intent http://developer.android.com/reference/android/content/Intent.html

Activity http://developer.android.com/reference/android/app/Activity.html

相关知识:

Activity 知识:

activity是单独的,用于处理用户操作。几乎所有的activity都要和用户打交道,所以activity类创建了一个窗口,开发人员可以通过setContentView(View)接口把UI放到activity创建的窗口上,当activity指向全屏窗口时,也可以用其他方式实现:作为漂浮窗口(通过windowIsFloating的主题集合),或者嵌入到其他的activity(使用ActivityGroup)。大部分的Activity子类都需要实现以下两个接口:

onCreate(Bundle)接口是初始化activity的地方. 在这儿通常可以调用setContentView(int)设置在资源文件中定义的UI, 使用findViewById(int) 可以获得UI中定义的窗口.

onPause()接口是使用者准备离开activity的地方,在这儿,任何的修改都应该被提交(通常用于ContentProvider保存数据).

为了能够使用Context.startActivity(),所有的activity类都必须在AndroidManifest.xml文件中定义有相关的“activity”项。

activity类是Android 应用生命周期的重要部分。

Activity生命周期

在系统中的Activity被一个Activity栈所管理。当一个新的Activity启动时,将被放置到栈顶,成为运行中的Activity,前一个Activity保留在栈中,不再放到前台,直到新的Activity退出为止。

Activity有四种本质区别的状态:

在屏幕的前台(Activity栈顶),叫做活动状态或者运行状态(active or running)

如果一个Activity失去焦点,但是依然可见(一个新的非全屏的Activity 或者一个透明的Activity 被放置在栈顶),叫做暂停状态(Paused)。一个暂停状态的Activity依然保持活力(保持所有的状态,成员信息,和窗口管理器保持连接),但是在系统内存极端低下的时候将被杀掉。

如果一个Activity被另外的Activity完全覆盖掉,叫做停止状态(Stopped)。它依然保持所有状态和成员信息,但是它不再可见,所以它的窗口被隐藏,当系统内存需要被用在其他地方的时候,Stopped的Activity将被杀掉。

如果一个Activity是Paused或者Stopped状态,系统可以将该Activity从内存中删除,Android系统采用两种方式进行删除,要么要求该Activity结束,要么直接杀掉它的进程。当该Activity再次显示给用户时,它必须重新开始和重置前面的状态。

下面的图显示了Activity的重要状态转换,矩形框表明Activity在状态转换之间的回调接口,开发人员可以重载实现以便执行相关代码,带有颜色的椭圆形表明Activity所处的状态。

launcher.apk 分析_第1张图片

在上图中,Activity有三个关键的循环:

整个的生命周期,从onCreate(Bundle)开始到onDestroy()结束。Activity在onCreate()设置所有的“全局”状态,在onDestory()释放所有的资源。例如:某个Activity有一个在后台运行的线程,用于从网络下载数据,则该Activity可以在onCreate()中创建线程,在onDestory()中停止线程。

可见的生命周期,从onStart()开始到onStop()结束。在这段时间,可以看到Activity在屏幕上,尽管有可能不在前台,不能和用户交互。在这两个接口之间,需要保持显示给用户的UI数据和资源等,例如:可以在onStart中注册一个IntentReceiver来监听数据变化导致UI的变动,当不再需要显示时候,可以在onStop()中注销它。onStart(),onStop()都可以被多次调用,因为Activity随时可以在可见和隐藏之间转换。

前台的生命周期,从onResume()开始到onPause()结束。在这段时间里,该Activity处于所有Activity的最前面,和用户进行交互。Activity可以经常性地在resumed和paused状态之间切换,例如:当设备准备休眠时,当一个Activity处理结果被分发时,当一个新的Intent被分发时。所以在这些接口方法中的代码应该属于非常轻量级的。

Activity的整个生命周期都定义在下面的接口方法中,所有方法都可以被重载。所有的Activity都需要实现onCreate(Bundle)去初始化设置,大部分Activity需要实现onPause()去提交更改过的数据,当前大部分的Activity也需要实现onFreeze()接口,以便恢复在onCreate(Bundle)里面设置的状态。

public class Activity extends ApplicationContext {

protected void onCreate(Bundle icicle);

protected void onStart();

protected void onRestart();

protected void onResume();

protected void onFreeze(Bundle outIcicle);

protected void onPause();

protected void onStop();

protected void onDestroy();

}

startActivity(Intent)接口用于启动一个新的activity,新的activity将被放置到activity栈顶。使用一个单一的参数:描述activity的执行动作的Intent。

有时候我们希望在activity结束的时候获得activity的反馈结果,例如:在一个activity中,让用户在一个联系人列表中选择某一个人,在该页面结束的时候,能够返回选中的人员信息。要做到这一点,需要调用startSubActivity(Intent, int)接口进行启动,第二个参数为调用者的标识。结果将在onActivityResult(int, int, String, Bundle)中返回。

当一个activity退出时,可以调用setResult(int)返回数据给上一级的activity。它必须支持结果编码,可以是标准的RESULT_CANCELED, RESULT_OK,或者从RESULT_FIRST_USER开始的自定义编码。此外,还可以返回一个字符串(通常是URL的某一项数据),也可以返回一个包含任意内容的包。所有的返回信息都会反馈到上一级的Activity.onActivityResult()接口,并带有上一级activity提供的原始标识号。

如果一个子activity失败了(如崩溃了),父activity将会接收到一个RESULT_CANCELED的结果编码。

public class MyActivity extends Activity

{

...

static final int PICK_CONTACT_REQUEST = 0;

protected boolean onKeyDown(int keyCode, KeyEvent event)

{

if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {

// When the user center presses, let them pick a contact.

startSubActivity(

new Intent(Intent.PICK_ACTION,

new ContentURI(”content://contacts”)),

PICK_CONTACT_REQUEST);

return true;

}

return false;

}

protected void onActivityResult(int requestCode, int resultCode,

String data, Bundle extras)

{

if (requestCode == PICK_CONTACT_REQUEST) {

if (resultCode == RESULT_OK) {

// A contact was picked. Here we will just display it

// to the user.

startActivity(new Intent(Intent.VIEW_ACTION, data));

}

}

}

}

保存持久状态

一般来说,activity有两种持久状态需要处理:共享的文档类数据(典型的是使用了content provider存储在SQLite中),内在的状态(如用户的嗜好)。

针对内容提供的数据,google建议采用“编辑到位”的用户模型,也就是说,用户的编辑动作是立即有效的,无须进行额外的确认步骤,支持这个模式只需要简单遵守下面的两个规则:

当创建一个新的文档时,相关的数据库条目和文件都是立即创建的,例如:用户选择写一个新的电子邮件,一旦开始写,则新的电子邮件条目创建出来了。所以如果进入其他的activity,则这封电子邮件将会出现在草稿箱中。

当一个activity的onPause()接口被调用时,它应该提交用户的修改到内容提供者或者文件中。这样确保其他将要运行的activity能够看到这些变化。在整个activity的生命周期中,有很多时候都需要频繁提交数据,例如:在启动一个新的activity之前,在结束自己的activity之前,在输入字段进行切换的时候等等。

这个模型是为了防止用户在activity之间浏览时的数据丢失,允许系统在activity停止后的任何时间里安全地杀掉activity(因为系统资源要用在其他地方)。注意:这样意味着在activity里按了“返回”键并不等于“取消”,它意味着activity的当前数据被保存下来,离开了activity。在一个activity中要取消编辑动作必须有另外一套机制来实现,比如一个清晰的“恢复”或者“撤销”动作。

可以在content package里面查看更多的内容提供者信息,有一些重要的方面,在activity调用和activity之间的数据传递的不同。

activity也提供了一些API用于管理内在的状态,可以用在如浏览器中用户设置的缺省主页等。

activity的持久状态由getPreferences(int)来进行管理,允许获取或者修改一套“名字/值”的对。为了在多个应用程序组件(activities, receivers, services, providers)之间共享持久状态,可以使用Context.getSharedPreferences()接口获取一个共享对象。(注意:不可能跨越应用程序包来共享数据,但是可以使用内容提供者来做)

下面是一个例子,进行持久性设置:

public class CalendarActivity extends Activity { ... static final int DAY_VIEW_MODE = 0; static final int WEEK_VIEW_MODE = 1; private SharedPreferences mPrefs; private int mCurViewMode; protected void onCreate(Bundle icicle) { super.onCreate(icicle); SharedPreferences mPrefs = getSharedPreferences(); mCurViewMode = mPrefs.getInt("view_mode" DAY_VIEW_MODE); } protected void onPause() { super.onPause(); SharedPreferences.Editor ed = mPrefs.edit(); ed.putInt("view_mode", mCurViewMode); ed.commit(); } }

权限许可

当activity在manifest的 标签中进行了声明,就有能力进行启动。其他的应用程序为了能够启动这个activity,需要在他们自己的manifest资源文件中的元素中进行声明。

更多的权限和安全问题,可以参见Security Model 文档。

进程的生命周期

Android系统试图确保一个应用进程尽可能长久,但是在内存减少的时候最终要删除旧的进程。像Activity Lifecycle描述的一样,决定哪一个进程被删除是依据于和用户打交道的状态。一般来说,基于运行的activity的进程有四种状态,下面列出了重要的顺序,Android系统在杀掉重要进程之前先杀掉次要的进程。

前台的activity(activity在屏幕的最前面,正和用户进行交互)是最重要的,如果这个activity使用的内存超过了设备提供的内存,作为最后手段才杀掉这个activity的进程。通常在这一点上表明设备已经达到了memory paging state(?),因为需要确保用户界面的交互。

可见的activity(对用户可见,但不是在前台,如位于前台弹出对话框下面的界面)是很重要的,一般不会杀掉这个进程,除非为了确保前台activity的运行不得已而杀之。

后台的activity(对用户不可见,已经暂停)不再重要,系统可以安全杀掉这个进程,回收内存给其他前台或者可见的进程。当用户按下“返回”键浏览这个activity(使它重新在屏幕上可见),它的onCreate(Bundle)接口将被调用,在暂停的时候由于已经调用过onFreeze(Bundle)接口重置了状态,因此这个activity能够重新以相同的设置启动。

空进程是没有activity组件和其他应用程序组件(Service or IntentReceiver)的进程,在系统内存变低的时候很快就被删除了。出于这个原因,任何在activity之外的后台操作必须在IntentReceiver 或者Service的环境下执行,这样才能确保进程能够一直运行。

有时候activity希望能够执行一些长时间的操作,自立存在于activity的生命周期之外。例如:相机应用程序允许用户上传一幅图片到网站,上传将花费很长的时间,应用程序应该允许用户离开正在执行的程序。为了完成这些,activity应该启动一个Service来执行上传任务,在上传区间,系统能够给进程一个良好的优先级别(比那些不可见的进程更高的优先级别),而不用考虑源activity是否处于暂停,停止或者结束状态。

你可能感兴趣的:(launcher.apk 分析)