本文将www.bangchui.org网络中的《android手把手教你开发launcher》系列文章进行了整理。这篇文章对lancher的基本功能点的实现做了简单介绍,看完后会对lancher有比较深刻的认识。

1、launcher最简单实例

launcher,也就是android的桌面应用程序。下图是android2.3的launcher应用程序:


接下来我们要开发一个自己的launcher,使其替代系统的默认launcher。
怎样使我们的应用程序成为一个launcher?

下面我们就新建一个叫做MyHome的工程,具体步骤略。创建完工程后整个目录结构如下图:

android Launcher基础知识_第1张图片

现在我们的AndroidManifest.xml文件这样的:

[java] view plain copy
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <manifestxmlns:android="http://schemas.android.com/apk/res/android"
  3. package="org.bangchui.myhome"
  4. android:versionCode="1"
  5. android:versionName="1.0">
  6. <applicationandroid:icon="@drawable/icon"android:label="@string/app_name">
  7. <activityandroid:name=".MyHome"
  8. android:label="@string/app_name">
  9. <intent-filter>
  10. <actionandroid:name="android.intent.action.MAIN"/>
  11. <categoryandroid:name="android.intent.category.LAUNCHER"/>
  12. </intent-filter>
  13. </activity>
  14. </application>
  15. </manifest>
请注意<intent-filter>
</intent-filter>里面的内容。
下面我们在其中添加上以下两行:
[java] view plain copy
  1. <categoryandroid:name="android.intent.category.HOME"/>
  2. <categoryandroid:name="android.intent.category.DEFAULT"/>
此时AndroidManifest.xml文件是这样: [html] view plain copy
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <manifestxmlns:android="http://schemas.android.com/apk/res/android"
  3. package="org.bangchui.myhome"
  4. android:versionCode="1"
  5. android:versionName="1.0">
  6. <applicationandroid:icon="@drawable/icon"android:label="@string/app_name">
  7. <activityandroid:name=".MyHome"
  8. android:label="@string/app_name">
  9. <intent-filter>
  10. <actionandroid:name="android.intent.action.MAIN"/>
  11. <categoryandroid:name="android.intent.category.LAUNCHER"/>
  12. <categoryandroid:name="android.intent.category.HOME"/>
  13. <categoryandroid:name="android.intent.category.DEFAULT"/>
  14. </intent-filter>
  15. </activity>
  16. </application>
  17. </manifest>
此时运行程序,我们看不到任何特别之处。当按下home键时(模拟器上按下home会调出桌面应用),程序如图:

我们看到了,我们开发的Myhome跟Launcher出现在了一起。
重启模拟器,我们看到我们自己的程序已经可以作为home来运行了。
ok。 第一步完成了:把我们的应用程序作为home。
总结一下:要把我们的应用程序作为home,只需要在AndroidManifest.xml中添加:

[java] view plain copy
  1. <categoryandroid:name="android.intent.category.HOME"/>
  2. <categoryandroid:name="android.intent.category.DEFAULT"/>

2、列出安装的应用程序

列出已经安装的应用程序是作为launcher必不可少的功能。下面我们就讲解怎样将应用程序列出来。程序运行后的样子如下:

android Launcher基础知识_第2张图片

一. 修改main.xml,在其中添加一个GridView用来显示应用程序列表。
修改后如下:

[html] view plain copy
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"android:layout_width="fill_parent"
  4. android:layout_height="fill_parent">
  5. <GridViewandroid:layout_width="match_parent"
  6. android:id="@+id/apps_list"
  7. android:numColumns="4"
  8. android:layout_height="wrap_content">
  9. </GridView>
  10. </LinearLayout>
二 . 通过PackageManager的api 查询已经安装的apk
我们写一个叫做loadApps的方法将活得的应用程序列表放到private List<ResolveInfo> mApps; 中,如下:
[java] view plain copy
  1. privatevoidloadApps(){
  2. IntentmainIntent=newIntent(Intent.ACTION_MAIN,null);
  3. mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
  4. mApps=getPackageManager().queryIntentActivities(mainIntent,0);
  5. }
三. 实现用于显示Gridview的Adapter,使其显示获得的应用程序列表
最后整个Activity的代码如下
[java] view plain copy
  1. packageorg.bangchui.myhome;
  2. importjava.util.List;
  3. importandroid.app.Activity;
  4. importandroid.content.Intent;
  5. importandroid.content.pm.ResolveInfo;
  6. importandroid.os.Bundle;
  7. importandroid.view.View;
  8. importandroid.view.ViewGroup;
  9. importandroid.widget.BaseAdapter;
  10. importandroid.widget.GridView;
  11. importandroid.widget.ImageView;
  12. publicclassMyHomeextendsActivity
  13. {
  14. GridViewmGrid;
  15. /**Calledwhentheactivityisfirstcreated.*/
  16. @OverridepublicvoidonCreate(BundlesavedInstanceState){
  17. super.onCreate(savedInstanceState);
  18. loadApps();
  19. setContentView(R.layout.main);
  20. mGrid=(GridView)findViewById(R.id.apps_list);
  21. mGrid.setAdapter(newAppsAdapter());
  22. }
  23. privateList<ResolveInfo>mApps;
  24. privatevoidloadApps(){
  25. IntentmainIntent=newIntent(Intent.ACTION_MAIN,null);
  26. mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
  27. mApps=getPackageManager().queryIntentActivities(mainIntent,0);
  28. }
  29. publicclassAppsAdapterextendsBaseAdapter
  30. {
  31. publicAppsAdapter(){}
  32. publicViewgetView(intposition,ViewconvertView,ViewGroupparent){
  33. ImageViewi;
  34. if(convertView==null){
  35. i=newImageView(MyHome.this);
  36. i.setScaleType(ImageView.ScaleType.FIT_CENTER);
  37. i.setLayoutParams(newGridView.LayoutParams(50,50));
  38. }else{
  39. i=(ImageView)convertView;
  40. }
  41. ResolveInfoinfo=mApps.get(position);
  42. i.setImageDrawable(info.activityInfo.loadIcon(getPackageManager()));
  43. returni;
  44. }
  45. publicfinalintgetCount(){
  46. returnmApps.size();
  47. }
  48. publicfinalObjectgetItem(intposition){
  49. returnmApps.get(position);
  50. }
  51. publicfinallonggetItemId(intposition){
  52. returnposition;
  53. }
  54. }
  55. }
3、启动安装的应用程序
1. 监听GridView的onItemClick事件
设置一个监听器是为了当gridView的某项被点击时,会有一个回调函数通知我们。
我们调用mGrid.setOnItemClickListener(listener); 设置一个监听器
mGrid.setOnItemClickListener(listener)中的listener是一个接口,其类型为:android.widget.AdapterView.OnItemClickListener,如下图所示:

下面我们new一个android.widget.AdapterView.OnItemClickListener类型的对象作为参数。我们直接使用eclipde的自动补全功能来完成OnItemClickListener 的定义: [java] view plain copy
  1. privateOnItemClickListenerlistener=newOnItemClickListener()
  2. {
  3. @OverridepublicvoidonItemClick(AdapterView<?>parent,Viewview,intposition,longid){}
  4. };
接口OnItemClickListener 中有一个方法叫做onItemClick,我们实现它即可。下面我对onItemClick的几个参数略作说明:
parent 略
view 被点击的view
position 被点击项的位置
id 被点击项的id
2.启动被点击应用的activity
一般来讲,我们根据position即可知道被点击的项目是哪一项了。现在我们根据被点击的项目,取出对应的应用程序数据(主要是其中的主activity),然后启动activity。用下面代码实现: [java] view plain copy
  1. @OverridepublicvoidonItemClick(AdapterView<?>parent,Viewview,intposition,longid){
  2. ResolveInfoinfo=mApps.get(position);
  3. //该应用的包名Stringpkg=info.activityInfo.packageName;
  4. //应用的主activity类Stringcls=info.activityInfo.name;
  5. ComponentNamecomponet=newComponentName(pkg,cls);
  6. Intenti=newIntent();
  7. i.setComponent(componet);
  8. startActivity(i);
  9. }
例如,我们点击计算器时,启动了计算器,如下图:
android Launcher基础知识_第3张图片
现在整个类代码如下:
[java] view plain copy
  1. packageorg.bangchui.myhome;
  2. importjava.util.List;
  3. importandroid.app.Activity;
  4. importandroid.content.ComponentName;
  5. importandroid.content.Intent;
  6. importandroid.content.pm.ResolveInfo;
  7. importandroid.os.Bundle;
  8. importandroid.view.View;
  9. importandroid.view.ViewGroup;
  10. importandroid.widget.AdapterView;
  11. importandroid.widget.BaseAdapter;
  12. importandroid.widget.GridView;
  13. importandroid.widget.ImageView;
  14. importandroid.widget.AdapterView.OnItemClickListener;
  15. publicclassMyHomeextendsActivity{
  16. privateList<ResolveInfo>mApps;
  17. GridViewmGrid;
  18. privateOnItemClickListenerlistener=newOnItemClickListener(){
  19. @Override
  20. publicvoidonItemClick(AdapterView<?>parent,Viewview,intposition,longid){
  21. ResolveInfoinfo=mApps.get(position);
  22. //该应用的包名
  23. Stringpkg=info.activityInfo.packageName;
  24. //应用的主activity类
  25. Stringcls=info.activityInfo.name;
  26. ComponentNamecomponet=newComponentName(pkg,cls);
  27. Intenti=newIntent();
  28. i.setComponent(componet);
  29. startActivity(i);
  30. }
  31. };
  32. /**Calledwhentheactivityisfirstcreated.*/
  33. @Override
  34. publicvoidonCreate(BundlesavedInstanceState){
  35. super.onCreate(savedInstanceState);
  36. loadApps();
  37. setContentView(R.layout.main);
  38. mGrid=(GridView)findViewById(R.id.apps_list);
  39. mGrid.setAdapter(newAppsAdapter());
  40. mGrid.setOnItemClickListener(listener);
  41. }
  42. privatevoidloadApps(){
  43. IntentmainIntent=newIntent(Intent.ACTION_MAIN,null);
  44. mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
  45. mApps=getPackageManager().queryIntentActivities(mainIntent,0);
  46. }
  47. publicclassAppsAdapterextendsBaseAdapter{
  48. publicAppsAdapter(){
  49. }
  50. publicViewgetView(intposition,ViewconvertView,ViewGroupparent){
  51. ImageViewi;
  52. if(convertView==null){
  53. i=newImageView(MyHome.this);
  54. i.setScaleType(ImageView.ScaleType.FIT_CENTER);
  55. i.setLayoutParams(newGridView.LayoutParams(50,50));
  56. }else{
  57. i=(ImageView)convertView;
  58. }
  59. ResolveInfoinfo=mApps.get(position);
  60. i.setImageDrawable(info.activityInfo.loadIcon(getPackageManager()));
  61. returni;
  62. }
  63. publicfinalintgetCount(){
  64. returnmApps.size();
  65. }
  66. publicfinalObjectgetItem(intposition){
  67. returnmApps.get(position);
  68. }
  69. publicfinallonggetItemId(intposition){
  70. returnposition;
  71. }
  72. }
  73. }
4、显示widget

我们要达到这样的效果:点击“add widget” 后弹出widget列表,之后选择一个widget后显示在界面上,如下:

android Launcher基础知识_第4张图片

1. 获取widget信息
获取widget其实非常简单,我们只需要发送一个请求到系统,系统就会打开widget的列表,然后我们选择一个即可。代码如下:

[java] view plain copy
  1. voidaddWidget(){
  2. intappWidgetId=mAppWidgetHost.allocateAppWidgetId();
  3. IntentpickIntent=newIntent(AppWidgetManager.ACTION_APPWIDGET_PICK);
  4. pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,appWidgetId);
  5. //startthepickactivity
  6. startActivityForResult(pickIntent,[b]REQUEST_PICK_APPWIDGET[/b]);
  7. }
2. 添加widget的view到layout中
当选择一个widget后会通过onActivityResult 通知到activity,widget的信息被包含在 Intent data中,详情看代码注释 [java] view plain copy
  1. @OverrideprotectedvoidonActivityResult(intrequestCode,intresultCode,Intentdata){
  2. //ThepatternusedhereisthatauserPICKsaspecificapplication,
  3. //which,dependingonthetarget,mightneedtoCREATEtheactual
  4. //target.
  5. //Forexample,theuserwouldPICK_SHORTCUTfor"Musicplaylist",and
  6. //we
  7. //launchovertotheMusicapptoactuallyCREATE_SHORTCUT.
  8. if(resultCode==RESULT_OK){
  9. switch(requestCode){
  10. caseREQUEST_PICK_APPWIDGET:
  11. addAppWidget(data);
  12. break;
  13. caseREQUEST_CREATE_APPWIDGET:
  14. completeAddAppWidget(data);
  15. break;
  16. }
  17. }
  18. }
  19. voidaddAppWidget(Intentdata){
  20. //TODO:catchbadwidgetexceptionwhensent
  21. intappWidgetId=data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,-1);
  22. AppWidgetProviderInfoappWidget=mAppWidgetManager.getAppWidgetInfo(appWidgetId);
  23. //widget包含设置信息不为空,则启动widget的设置界面
  24. if(appWidget.configure!=null){
  25. //Launchovertoconfigurewidget,ifneeded
  26. Intentintent=newIntent(
  27. AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
  28. intent.setComponent(appWidget.configure);
  29. intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,appWidgetId);
  30. startActivityForResultSafely(intent,REQUEST_CREATE_APPWIDGET);
  31. }else{
  32. //widget包含设置信息为空,直接添加widget到layout中
  33. //Otherwisejustaddit
  34. onActivityResult(REQUEST_CREATE_APPWIDGET,Activity.RESULT_OK,data);
  35. }
  36. }
  37. voidstartActivityForResultSafely(Intentintent,intrequestCode){
  38. try{
  39. startActivityForResult(intent,requestCode);
  40. }catch(ActivityNotFoundExceptione){
  41. Toast.makeText(this,"activity_not_found",Toast.LENGTH_SHORT).show();
  42. }catch(SecurityExceptione){
  43. Toast.makeText(this,"activity_not_found",Toast.LENGTH_SHORT).show();
  44. }
  45. }
  46. /***添加widget信息到layout中
  47. **@paramdata包含了widget的信息*/
  48. privatevoidcompleteAddAppWidget(Intentdata){
  49. Bundleextras=data.getExtras();
  50. intappWidgetId=extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,-1);
  51. Log.d(TAG,"dumpingextrascontent="+extras.toString());
  52. AppWidgetProviderInfoappWidgetInfo=mAppWidgetManager.getAppWidgetInfo(appWidgetId);
  53. //Performactualinflationbecausewe'relive
  54. synchronized(mLock){
  55. //获取显示widget的view
  56. mHostView=mAppWidgetHost.createView(this,appWidgetId,appWidgetInfo);
  57. mHostView.setAppWidget(appWidgetId,appWidgetInfo);
  58. //将获取的view添加早layout中
  59. LayoutParamslp=newLinearLayout.LayoutParams(appWidgetInfo.minWidth,appWidgetInfo.minHeight);
  60. mainLayout.addView(mHostView,lp);
  61. mHostView.requestLayout();
  62. }
  63. }
5、显示和设置壁纸

显示壁纸也是launcher必不可少的功能,下面我们看看如何让我们开发的launcher来显示壁纸。
新建一个叫做ShowWallpaper的工程,具体步骤略。
一. 显示壁纸
要在我们的activity里显示一个壁纸非常简单(包括动态壁纸也如此),我们只需要定义一个theme使其继承自android:Theme.Wallpaper,然后在activity中使用这个theme就ok了。
在res/valuse下面增加一个xml文件,其名称为styles.xml ,内容如下:

[html] view plain copy
  1. <resources>
  2. <stylename="Theme"parent="android:Theme.Wallpaper">
  3. <!--windowNoTitle设置为true,去掉标题栏-->
  4. <itemname="android:windowNoTitle">true</item>
  5. </style>
  6. </resources>
此时整个工程的结果如下:

android Launcher基础知识_第5张图片

下面在AndroidManifest.xml中使用这个theme,如下代码所示:

[html] view plain copy
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <manifestxmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.test"
  4. android:versionCode="1"
  5. android:versionName="1.0">
  6. <applicationandroid:icon="@drawable/icon"android:label="@string/app_name">
  7. <activityandroid:name=".ShowWallpaper"
  8. android:theme="@style/Theme"
  9. android:label="@string/app_name">
  10. <intent-filter>
  11. <actionandroid:name="android.intent.action.MAIN"/>
  12. <categoryandroid:name="android.intent.category.LAUNCHER"/>
  13. </intent-filter>
  14. </activity>
  15. </application>
  16. </manifest>
好了,运行程序,可以看到壁纸的显示效果了:(显示的是预设置的动态壁纸:星系)

android Launcher基础知识_第6张图片

用代码设置壁纸也是非常地简单的事,我们只需要向系统发送一个“设置请求”就足够了,其它的事情系统处理。

用下面代码表示:

[java] view plain copy
  1. publicvoidonSetWallpaper(Viewview){
  2. //生成一个设置壁纸的请求
  3. finalIntentpickWallpaper=newIntent(Intent.ACTION_SET_WALLPAPER);
  4. Intentchooser=Intent.createChooser(pickWallpaper,"chooser_wallpaper");
  5. //发送设置壁纸的请求
  6. startActivity(chooser);
  7. }
为了调用上面这段代码,我们在xml中添加一个button,并设置回调函数,如下图:
[html] view plain copy
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:orientation="vertical">
  6. <TextView
  7. android:layout_width="fill_parent"
  8. android:layout_height="wrap_content"
  9. android:text="@string/hello"/>
  10. <Button
  11. android:id="@+id/button1"
  12. android:layout_width="wrap_content"
  13. android:layout_height="wrap_content"
  14. android:text="setWallpaper"
  15. android:onClick="onSetWallpaper"/>
  16. </LinearLayout>
最后运行代码,步骤如下图所示:
android Launcher基础知识_第7张图片

设置壁纸后:
android Launcher基础知识_第8张图片

参考资料:

更多相关文章

  1. Android代码内存优化建议-OnTrimMemory优化
  2. android.uid.system Android中如何修改系统时间(应用程序获得系
  3. 如何修改Android应用程序能够使用的默认最大内存值
  4. Gears Android WIFI/基站定位源代码分析
  5. 安卓学习(初)第三章(2)(《第一行代码》)
  6. Android应用程序中Manifest.java文件的介绍
  7. Android 2.3禁止系统弹出应用程序强制退出对话框

随机推荐

  1. [记录点滴] 小心 Hadoop Speculative 调
  2. [白话解析] 用水浒传为例学习条件随机场
  3. [记录点滴] OpenResty中Redis操作总结
  4. [源码分析] 从实例和源码入手看 Flink 之
  5. [记录点滴] 一个解决Lua 随机数生成问题
  6. [读史思考]为何此大神可以同时进入文庙和
  7. [源码分析] 从FlatMap用法到Flink的内部
  8. [业界方案] 智能运维AIOps-学习笔记
  9. [白话解析] 通俗解析集成学习之bagging,bo
  10. [白话解析] 深入浅出边缘计算