本文节选于机械工业出版社推出的《Android应用开发揭秘》一书,作者为杨丰盛。本书内容全面,详细讲解了Android框架、Android组件、用户界面开发、游戏开发、数据存储、多媒体开发和网络开发等基础知识,而且还深入阐述了传感器、语音识别、桌面组件开发、Android游戏引擎设计、Android应用优化、OpenGL等高级知识。另外,本书还全面介绍了如何利用原生的C/C++(NDK)和Python、Lua等脚本语言(Android Scripting Environment)来开发Android应用,并以迭代的方式重现了各种常用的Android应用和经典Android游戏的开发全过程。

9.4  桌面组件

第一次启动Android模拟器时,可以看到在桌面上有很多图标,如图9-18所示的Google搜索框、时钟、联系人、浏览器等,点击这些图标,系统就会执行相应的程序,与PC操作系统桌面上的快捷方式很像,但是它不完全是快捷方式,还包括了实时文件夹(Live Folder)和桌面插件(Widget),这样既美观又方便用户操作。本节将学习这每一种桌面组件的开发,让我们自己的应用程序也能轻松地放置到桌面上。

图9-18 Android桌面组件

9.4.1  快捷方式

首先我们学习最基本的桌面组件快捷方式,它和PC上的快捷方式一样,用于启动某一应用程序的某个组件(如Activity、Service等)。其实要在桌面上添加一个快捷方式很简单,只需要长按桌面或者点击“Menu”按键(如图9-19所示),就可以弹出添加桌面组件的选项,如图9-20所示,“Shortcuts”为添加快捷方式,“Widgets”为Widget开发的桌面插件,“Folders”为实时文件夹,进入相应的选项后即可添加相应的桌面组件。

图9-19  Menu菜单 图9-20  添加桌面组件

本小节重点介绍在应用程序中通过代码来将一个应用程序添加到图9-20的Shortcuts列表中,这里添加一个发送邮件的应用到快捷方式列表上去(参见本书所附代码:第9章\Examples_09_05)。
首先需要在Activity注册时添加一个Action为android.intent.action.CREATE_SHORTCUT的IntentFilter,如代码清单9-7所示,添加之后列表中就会出现该应用的图标和名字了。
代码清单9-7  第9章\Examples_09_05\AndroidManifest.xml

            
  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android" 
  3.    package="com.yarin.android.Examples_09_05" 
  4.    android:versionCode="1" 
  5.    android:versionName="1.0"> 
  6.  <application android:icon="@drawable/icon" android:label="@string/app_name"> 
  7.      <activity android:name=".Activity01" 
  8.                android:label="@string/app_name"> 
  9.          <intent-filter> 
  10.            <action android:name="android.intent.action.MAIN" /> 
  11.            <category android:name="android.intent.category.LAUNCHER" /> 
  12.         <action android:name="android.intent.action.CREATE_SHORTCUT"/>   
  13.          intent-filter> 
  14.      activity> 
  15.  application> 
  16.  <uses-sdk android:minSdkVersion="5" /> 
  17. manifest> 

接下来还要为快捷方式设置名字、图标、事件等属性。Intent.EXTRA_SHORTCUT_NAME对应快捷方式的名字;Intent.EXTRA_SHORTCUT_ICON_RESOURCE对应快捷方式的图标;Intent. EXTRA_SHORTCUT_INTENT对应快捷方式执行的事件。需要说明的是,Android专门提供了Intent.ShortcutIconResource.fromContext来创建快捷方式的图标,最后通过setResult来返回,构建一个快捷方式,如代码清单9-8所示。
代码清单9-8  第9章\Examples_09_05\src\com\yarin\android\Examples_09_05\Activity01.java

            
  1. public class Activity01 extends Activity  
  2. {  
  3. public void onCreate(Bundle savedInstanceState)  
  4. {  
  5.     super.onCreate(savedInstanceState);  
  6.     //要添加的快捷方式的Intent  
  7.     Intent addShortcut;   
  8.     //判断是否要添加快捷方式  
  9.     if (getIntent().getAction().equals(Intent.ACTION_CREATE_SHORTCUT))  
  10.     {  
  11.         addShortcut = new Intent();   
  12.         //设置快捷方式的名字  
  13.         addShortcut.putExtra(Intent.EXTRA_SHORTCUT_NAME,"发送邮件");  
  14.         //构建快捷方式中专门的图标  
  15.         Parcelable icon = Intent.ShortcutIconResource.fromContext(this,R.drawable.mail_edit);    
  16.         //添加快捷方式图标  
  17.         addShortcut.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,icon);  
  18.         //构建快捷方式执行的Intent  
  19.         Intent mailto=new  Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:xxx@xxx.com" ));   
  20.         //添加快捷方式Intent  
  21.         addShortcut.putExtra(Intent.EXTRA_SHORTCUT_INTENT,mailto);    
  22.         //正常  
  23.         setResult(RESULT_OK,addShortcut);    
  24.     }  
  25.     else 
  26.     {  
  27.         //取消  
  28.         setResult(RESULT_CANCELED);    
  29.     }  
  30.     //关闭  
  31.     finish();    
  32. }  
  33. }    

现在我们启动模拟器,就可以在Shortcuts列表中找到所添加的快捷方式,将其添加到桌面,如图9-21所示。

图9-21  桌面快捷方式

9.4.2  实时文件夹

在Android 1.5中,Live Folders无疑是一个备受关注的新功能。简单地说,Live Folders就是一个查看你的手机中所有电子书、电子邮件、rss订阅、播放列表的快捷方式,并且这些内容是实时更新的。比如你不再需要单独打开电子邮件软件查看邮件,打开通讯录找联系人等。Live Folders自带了列出所有联系人、所有有电话号码的联系人以及Starred联系人的功能,我们还可以使用Live Folders API开发出更多的新颖应用。
由于Live Folders本身不存储任何信息,都是以映射的方式查看其ContentProvider所指向的数据信息,并可以自定义显示格式,所以当源数据发生改变后,Live Folders可以实时更新显示内容。那么在开发时,我们要确保所指定数据信息URI的ContentProvider支持实时文件夹的查询。
其添加方式和添加快捷方式一样,只是在选择时要选择“Folders”。本小节我们通过Live Folders调用电话本中的信息,当点击其中一条信息时,便执行呼叫该联系人的动作(本书所附代码:第9章\ Examples_09_06)。
和创建快捷方式一样,我们需要在Activity注册时添加一个Action动作为android.intent.action. CREATE_LIVE_FOLDER的IntentFilter。代码如下:

            
  1. <intent-filter> 
  2.      <action android:name"android.intent.action.CREATE_LIVE_FOLDER" />   
  3.      <category android:name"android.intent.category.DEFAULT" />   
  4. intent-filter> 

我们需要在程序中设置该实时文件夹的数据源、图标、名字的信息。可以通过intent.setData方法来设置要读取的数据源,该例中我们设置数据源为“content://contacts/live_folders/people”,即联系人信息。其他信息的设置如表9-2所示。
表9-2  Live Folders的常用属性

在设置图标时,Android专门提供了Intent.ShortcutIconResource.fromContext来设置实时文件夹的图标。下面我们将实时文件夹添加到桌面(如图9-22所示),运行效果如图9-23所示。

图9-22 “电话本”实时文件夹

图9-23  实时文件夹运行效果
下面需要在onCreate方法中将实时文件夹的相关信息装入Intent对象,并通过setResult方法设置为结果Intent,最后调用finish方法结束Activity,把结果返回给Home应用程序,以添加实时文件夹,如代码清单9-9所示。
代码清单9-9  第9章\Examples_09_06\src\com\yarin\android\Examples_09_06\Activity01.java

            
  1. public class Activity01 extends Activity  
  2. {  
  3. public void onCreate(Bundle savedInstanceState)  
  4. {  
  5.     super.onCreate(savedInstanceState);  
  6.     // setContentView(R.layout.main);  
  7.     // 判断是否创建实时文件夹  
  8.     if (getIntent().getAction().equals(LiveFolders.ACTION_CREATE_LIVE_FOLDER))  
  9.     {  
  10.         Intent intent = new Intent();  
  11.         // 设置数据地址  
  12.         intent.setData(Uri.parse("content://contacts/live_folders/people"));  
  13.         // 设置单击之后的事件,这里单击一个联系人后,呼叫  
  14.         intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_BASE_INTENT,new Intent(Intent.ACTION_CALL,Contacts.People.CONTENT_URI));  
  15.         // 设置实时文件夹的名字  
  16.         intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME,"电话本");  
  17.         // 设置实施文件夹的图标  
  18.         intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON, Intent.  
  19.         ShortcutIconResource.fromContext(this,R.drawable.contacts));  
  20.         // 设置显示模式为列表  
  21.         intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_DISPLAY_MODE,LiveFolders.DISPLAY_MODE_LIST);  
  22.         // 完成  
  23.         setResult(RESULT_OK, intent);  
  24.     }  
  25.     else 
  26.     {  
  27.         setResult(RESULT_CANCELED);  
  28.     }  
  29.     finish();  
  30. }  

9.4.3  Widget开发

Widget是一种很小的应用程序,主要作为Web 2.0服务或互联网内容的前端。Web设计人员与开发者可以使用Widget来创造最受欢迎的互联网体验。在Android 1.5中加入了AppWidget framework框架,开发者可以使用该框架开发Widget,这些Widget可以拖到用户的桌面并且可以交互。Widget可以提供一个full-featured apps的预览,例如可以显示即将到来的日历事件,或者一首后台播放的歌曲的详细信息。当Widget被拖到桌面上时,指定一个保留的空间来显示应用提供的自定义内容。用户可以通过这个Widget来和应用交互,例如暂停或切换歌曲。如果你有一个后台服务,可以按照你自己的Schedule更新你的Widget,或者使用AppWidget framework提供一个自动的更新机制。
每个Widget就是一个BroadcastReceiver,它们用XML metadata来描述Widget的细节。AppWidget framework通过Broadcast intents和Widget通信, Widget的更新使用RemoteViews来发送。RemoteViews被包装成一个layout和特定内容来显示到桌面上。下面我们通过一个示例来学习Widget开发(本书所附代码:第9章\Examples_09_07)。
首先需要在res\layout目录下创建桌面组件的布局文件appwidget_provider.xml,用来显示桌面布局,这里我们创建一个TextView用来显示一段文字,如代码清单9-10所示。
代码清单9-10  第9章\Examples_09_07\res\layout\appwidget_provider.xml

            
  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <TextView xmlns:android="http://schemas.android.com/apk/res/android" 
  3.  android:id="@+id/appwidget_text"   
  4.  android:textColor="#ff000000" 
  5.  android:layout_width="wrap_content" 
  6.  android:layout_height="wrap_content" 
  7. /> 

然后需要创建一个描述这个桌面组件属性的文件,存放到res\xml文件夹下,如代码清单9-11所示。
代码清单9-11  第9章\Examples_09_07\res\xmlappwidget_provider.xml

            
  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" 
  3.  android:minWidth="100dp" 
  4.  android:minHeight="50dp" 
  5.  android:updatePeriodMillis="86400000" 
  6.  android:initialLayout="@layout/appwidget_provider" 
  7.  android:configure="com.yarin.android.Examples_09_07.Activity01" 
  8.  > 
  9. appwidget-provider> 

其中android:minWidth和android:minHeight分别指定了桌面组件的最小宽度和最小高度,其值可以根据期望的单元格数量并使用前面介绍过的公式来计算(最小尺寸=(单元格数×74)?2),android:updatePeriodMillis是自动更新的时间间隔,android:initialLayout是Widget的界面描述文件。Android:configure是可选的,如果你的Widget需要在启动前先启动一个Activity,则需要设定该项为你的Activity。这里我们需要先输入一段文字,然后显示在Widget上。
然后要建立一个Widget,创建一个类,让其继承类AppWidgetProvider。在AppWidgetProvider中有许多方法,包括onUpdate(周期更新时调用)、onDeleted(删除组件时调用)、onEnabled(当第一个组件创建时调用)、onDisabled(当最后一个组件删除时调用),如代码清单9-12所示。
代码清单9-12  第9章\Examples_09_07\src\com\yarin\android\Examples_09_07\ExampleAppWidget- Provider.java

            
  1. public class ExampleAppWidgetProvider extends AppWidgetProvider  
  2. {  
  3. //周期更新时调用  
  4. public void onUpdate(Context context,AppWidgetManager appWidgetManager,int[] appWidgetIds)  
  5. {  
  6.     final int N = appWidgetIds.length;  
  7.     for (int i = 0; i < N; i++)  
  8.     {  
  9.         int appWidgetId = appWidgetIds[i];  
  10.         String titlePrefix=Activity01.loadTitlePref(context,appWidgetId);  
  11.         updateAppWidget(context, appWidgetManager, appWidgetId, titlePrefix);  
  12.     }  
  13. }  
  14. //当桌面组件删除时调用  
  15. public void onDeleted(Context context, int[] appWidgetIds)  
  16. {  
  17.     //删除appWidget  
  18.     final int N = appWidgetIds.length;  
  19.     for (int i = 0; i < N; i++)  
  20.     {  
  21.         Activity01.deleteTitlePref(context, appWidgetIds[i]);  
  22.     }  
  23. }  
  24. //当AppWidgetProvider提供的第一个组件创建时调用  
  25. public void onEnabled(Context context)  
  26. {  
  27.     PackageManager pm = context.getPackageManager();  
  28.     pm.setComponentEnabledSetting(new ComponentName("com.yarin.android.Examples_09_07"".ExampleBroadcastReceiver"),  
  29.         PackageManager.COMPONENT_ENABLED_STATE_ENABLED,   
  30.         PackageManager.DONT_KILL_APP);  
  31. }  
  32. //当AppWidgetProvider提供的最后一个组件删除时调用  
  33. public void onDisabled(Context context)  
  34. {  
  35.     PackageManager pm = context.getPackageManager();  
  36.     pm.setComponentEnabledSetting(new ComponentName("com.yarin.  
  37.     android.Examples_09_07", ".ExampleBroadcastReceiver"),  
  38.         PackageManager.COMPONENT_ENABLED_STATE_ENABLED,   
  39.         PackageManager.DONT_KILL_APP);  
  40. }  
  41. //更新  
  42. static void updateAppWidget(Context context, AppWidgetManager   
  43. appWidgetManager, int appWidgetId, String titlePrefix)  
  44. {  
  45.     //构建RemoteViews对象来对桌面组件进行更新  
  46.     RemoteViews views = new RemoteViews(context.getPackageName(),   
  47.     R.layout.appwidget_provider);  
  48.     //更新文本内容,指定布局的组件  
  49.     views.setTextViewText(R.id.appwidget_text, titlePrefix);  
  50.     //将RemoteViews的更新传入AppWidget进行更新  
  51.     appWidgetManager.updateAppWidget(appWidgetId, views);  
  52. }  

其中,在updateAppWidget方法中我们构建了一个RemoteViews对象来对桌面组件进行更新,通过setTextViewText方法来更新一个文本的显示,然后通过updateAppWidget方法来将更新提供给AppWidget使其更新到桌面。在onDisabled和onEnabled方法中我们用ComponentName来表示应用程序中某个组件的完整名字。
最后,创建一个BroadcastReceiver类来接收更新的信息,在收到更新的信息之后就更新这个桌面Widget组件,如代码清单9-13所示。
代码清单9-13  第9章\Examples_09_07\src\com\yarin\android\Examples_09_07\ExampleBroadcast- Receiver.java

            
  1. public class ExampleBroadcastReceiver extends BroadcastReceiver  
  2. {  
  3. public void onReceive(Context context, Intent intent)  
  4. {  
  5.     //通过BroadcastReceiver来更新AppWidget  
  6.     String action = intent.getAction();  
  7.     if (action.equals(Intent.ACTION_TIMEZONE_CHANGED) || action.equals(Intent.ACTION_TIME_CHANGED))  
  8.     {  
  9.         AppWidgetManager gm = AppWidgetManager.getInstance(context);  
  10.         ArrayList appWidgetIds = new ArrayList();  
  11.         ArrayList texts = new ArrayList();  
  12.         Activity01.loadAllTitlePrefs(context, appWidgetIds, texts);  
  13.         //更新所有AppWidget  
  14.         final int N = appWidgetIds.size();  
  15.         for (int i = 0; i < N; i++)  
  16.         {  
  17.             ExampleAppWidgetProvider.updateAppWidget(context,gm, appWidgetIds.get(i), texts.get(i));  
  18.         }  
  19.     }  
  20. }  

接下来,处理Android:configure指定的类,用来输入信息,在该类中我们监听这个按钮,当点击按钮之后,创建一个AppWidgetManager实例,然后调用ExampleAppWidgetProvider.updateAppWidget方法来更新这个Widget,通过以下代码可以取得一个AppWidgetManager实例:
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
注意,还需要在AndroidManifest.xml中注册AppWidget、BroadcastReceiver和用来输入信息的Activity,如代码清单9-14所示。
代码清单9-14  第9章\Examples_09_07\AndroidManifest.xml

            
  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android" 
  3.    package="com.yarin.android.Examples_09_07" 
  4.    android:versionCode="1" 
  5.    android:versionName="1.0"> 
  6.  <application android:icon="@drawable/icon" android:label="@string/app_name"> 
  7.      <receiver android:name=".ExampleAppWidgetProvider"> 
  8.          <meta-data android:name="android.appwidget.provider" 
  9.                  android:resource="@xml/appwidget_provider" /> 
  10.          <intent-filter> 
  11.              <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> 
  12.          intent-filter> 
  13.      receiver> 
  14.      <activity android:name=".Activity01"> 
  15.          <intent-filter> 
  16.              <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" /> 
  17.          intent-filter> 
  18.      activity> 
  19.      <receiver android:name=".ExampleBroadcastReceiver" android:enabled="false"> 
  20.          <intent-filter> 
  21.              <action android:name="android.intent.ACTION_TIMEZONE_CHANGED" /> 
  22.              <action android:name="android.intent.ACTION_TIME" /> 
  23.          intent-filter> 
  24.      receiver> 
  25.  application> 
  26.  <uses-sdk android:minSdkVersion="5" /> 
  27. manifest> 

下面将该Widget添加到桌面上,和添加快捷方式一样,如图9-24所示,然后输入要显示的文字,如图9-25所示,点击“确定”按钮之后,桌面即显示我们输入的信息,如图9-26所示。

更多相关文章

  1. Android面试题合集【上】
  2. Android(安卓)开发文档
  3. Android(安卓)客户端与PC服务端socket通信接收与发送图片(终结者
  4. Android中Activity切换时共享视图元素的切换动画(4.x兼容方案)
  5. Android(安卓)SystemUI源代码分析和修改
  6. Android(安卓)高仿微信头像截取 打造不一样的自定义控件
  7. Android篮球计分器App
  8. Android(安卓)Studio目录结构浅析
  9. Android用代码完成颜色渐变处理

随机推荐

  1. 理解Git Submodules
  2. PreferenceActivity用法简介【转】
  3. 单例模式的十种写法,你会几个?(修补了几个错
  4. Lottie动画简介
  5. ym——Android从零开始(5)(文件操作+日记
  6. Android轻松集成Camera拍照
  7. 停更大半年了,开始新一段旅程
  8. :Android和j2me的初级对比
  9. SQL学习笔记之数据库专题(三):Android下Sqli
  10. 看完这篇Linux基本的操作就会了