当前位置:   article > 正文

Android 之App Widget_android appwidgetprovider

android appwidgetprovider

1 App Widget简介

应用微件是可以嵌入其他应用(如主屏幕)并接收定期更新的微型应用视图。这些视图称为界面中的微件,您可以使用应用微件提供程序发布微件。能够容纳其他应用微件的应用组件称为应用微件托管应用。下面的屏幕截图显示了闹钟微件。

 2 App Widg

要创建应用微件,您需要:

AppWidgetProviderInfo 对象

描述应用微件的元数据,如应用微件的布局、更新频率和 AppWidgetProvider 类。此对象应在 XML 中定义。

AppWidgetProvider 类实现

定义允许您基于广播事件以编程方式与应用微件连接的基本方法。通过它,您会在更新、启用、停用和删除应用微件时收到广播。

桌面小部件的开发步骤

1.在应用的 AndroidManifest.xml 文件中声明AppWidgetProvider类。

例如:
  1. <receiver android:name=".ExampleAppWidgetProvider" >
  2. <intent-filter>
  3. <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
  4. <action android:name="com.skywang.widget.UPDATE_ALL"/>
  5. </intent-filter>
  6. <meta-data android:name="android.appwidget.provider"
  7. android:resource="@xml/example_appwidget_info" />
  8. </receiver>

<receiver>元素需要android:name属性,该属性指定应用微件使用的AppWidgetProvider 。
<intent-filter>元素必须包含一个具有 android:name属性的<action>元素。此属性指定AppWidgetProvider接受 ACTION_APPWIDGET_UPDATE广播。这是您必须明确声明的唯一一项广播。AppWidgetManager 会根据需要自动将其他所有应用微件广播发送到AppWidgetProvider。
<meta-data>元素指定AppWidgetProviderInfo资源,并且需要以下属性:
android: name-指定元数据名称。使用android.appwidget.provider将数据标识为AppWidgetProviderInfo 描述符。
android :resource-指定AppWidgetProviderInfo资源位置。

2. 编辑AppWidgetProviderInfo对应的资源文件

  1.   <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
  2.         android:minWidth="40dp"
  3.         android:minHeight="40dp"
  4.         android:updatePeriodMillis="86400000"
  5.         android:previewImage="@drawable/preview"
  6.         android:initialLayout="@layout/example_appwidget"
  7.         android:configure="com.example.android.ExampleAppWidgetConfigure"
  8.         android:resizeMode="horizontal|vertical"
  9.         android:widgetCategory="home_screen">
  10.     </appwidget-provider>
    
    <!--
    android:minWidth : 最小宽度
    android:minHeight : 最小高度
    android:updatePeriodMillis : 更新widget的时间间隔(ms),"86400000"为1个小时
    android:previewImage : 预览图片
    android:initialLayout : 加载到桌面时对应的布局文件
    android:resizeMode : widget可以被拉伸的方向。horizontal表示可以水平拉伸,vertical表示可以竖直拉伸
    android:widgetCategory : widget可以被显示的位置。home_screen表示可以将widget添加到桌面,keyguard表示widget可以被添加到锁屏界面。
    android:configure : 定义要在用户添加应用微件时启动以便用户配置应用微件属性的 Activity
     -->
    

3. 编辑example_appwidget.xml等资源文件

新建layout/example_appwidget.xml,代码如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical" >
  6. <LinearLayout
  7. android:layout_width="wrap_content"
  8. android:layout_height="wrap_content"
  9. android:layout_gravity="center"
  10. android:orientation="horizontal" >
  11. <TextView
  12. android:layout_width="wrap_content"
  13. android:layout_height="wrap_content"
  14. android:text="HomeScreen Widget" />
  15. <Button
  16. android:id="@+id/btn_show"
  17. android:layout_width="wrap_content"
  18. android:layout_height="wrap_content"
  19. android:text="Show" />
  20. </LinearLayout>
  21. <ImageView
  22. android:id="@+id/iv_show"
  23. android:layout_width="wrap_content"
  24. android:layout_height="wrap_content"
  25. android:layout_gravity="center"/>
  26. </LinearLayout>
  27. 4. 编辑ExampleAppWidgetProvider.java
  28. public class ExampleAppWidgetProvider extends AppWidgetProvider {
  29. private static final String TAG = "ExampleAppWidgetProvider";
  30. private boolean DEBUG = false;
  31. // 启动ExampleAppWidgetService服务对应的action
  32. private final Intent EXAMPLE_SERVICE_INTENT =
  33. new Intent("android.appwidget.action.EXAMPLE_APP_WIDGET_SERVICE");
  34. // 更新 widget 的广播对应的action
  35. private final String ACTION_UPDATE_ALL = "com.skywang.widget.UPDATE_ALL";
  36. // 保存 widget 的id的HashSet,每新建一个 widget 都会为该 widget 分配一个 id。
  37. private static Set idsSet = new HashSet();
  38. // 按钮信息
  39. private static final int BUTTON_SHOW = 1;
  40. // 图片数组
  41. private static final int[] ARR_IMAGES = {
  42. R.drawable.ic_launcher,
  43. R.drawable.sample_0,
  44. R.drawable.sample_1,
  45. R.drawable.sample_2,
  46. };
  47. // onUpdate() 在更新 widget 时,被执行,
  48. @Override
  49. public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
  50. Log.d(TAG, "onUpdate(): appWidgetIds.length="+appWidgetIds.length);
  51. // 每次 widget 被创建时,对应的将widget的id添加到set中
  52. for (int appWidgetId : appWidgetIds) {
  53. idsSet.add(Integer.valueOf(appWidgetId));
  54. }
  55. prtSet();
  56. }
  57. // 当 widget 被初次添加 或者 当 widget 的大小被改变时,被调用
  58. @Override
  59. public void onAppWidgetOptionsChanged(Context context,
  60. AppWidgetManager appWidgetManager, int appWidgetId,
  61. Bundle newOptions) {
  62. Log.d(TAG, "onAppWidgetOptionsChanged");
  63. super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId,
  64. newOptions);
  65. }
  66. // widget被删除时调用
  67. @Override
  68. public void onDeleted(Context context, int[] appWidgetIds) {
  69. Log.d(TAG, "onDeleted(): appWidgetIds.length="+appWidgetIds.length);
  70. // 当 widget 被删除时,对应的删除set中保存的widget的id
  71. for (int appWidgetId : appWidgetIds) {
  72. idsSet.remove(Integer.valueOf(appWidgetId));
  73. }
  74. prtSet();
  75. super.onDeleted(context, appWidgetIds);
  76. }
  77. // 第一个widget被创建时调用
  78. @Override
  79. public void onEnabled(Context context) {
  80. Log.d(TAG, "onEnabled");
  81. // 在第一个 widget 被创建时,开启服务
  82. context.startService(EXAMPLE_SERVICE_INTENT);
  83. super.onEnabled(context);
  84. }
  85. // 最后一个widget被删除时调用
  86. @Override
  87. public void onDisabled(Context context) {
  88. Log.d(TAG, "onDisabled");
  89. // 在最后一个 widget 被删除时,终止服务
  90. context.stopService(EXAMPLE_SERVICE_INTENT);
  91. super.onDisabled(context);
  92. }
  93. // 接收广播的回调函数
  94. @Override
  95. public void onReceive(Context context, Intent intent) {
  96. final String action = intent.getAction();
  97. Log.d(TAG, "OnReceive:Action: " + action);
  98. if (ACTION_UPDATE_ALL.equals(action)) {
  99. // “更新”广播
  100. updateAllAppWidgets(context, AppWidgetManager.getInstance(context), idsSet);
  101. } else if (intent.hasCategory(Intent.CATEGORY_ALTERNATIVE)) {
  102. // “按钮点击”广播
  103. Uri data = intent.getData();
  104. int buttonId = Integer.parseInt(data.getSchemeSpecificPart());
  105. if (buttonId == BUTTON_SHOW) {
  106. Log.d(TAG, "Button wifi clicked");
  107. Toast.makeText(context, "Button Clicked", Toast.LENGTH_SHORT).show();
  108. }
  109. }
  110. super.onReceive(context, intent);
  111. }
  112. // 更新所有的 widget
  113. private void updateAllAppWidgets(Context context, AppWidgetManager appWidgetManager, Set set) {
  114. Log.d(TAG, "updateAllAppWidgets(): size="+set.size());
  115. // widget 的id
  116. int appID;
  117. // 迭代器,用于遍历所有保存的widget的id
  118. Iterator it = set.iterator();
  119. while (it.hasNext()) {
  120. appID = ((Integer)it.next()).intValue();
  121. // 随机获取一张图片
  122. int index = (new java.util.Random().nextInt(ARR_IMAGES.length));
  123. if (DEBUG) Log.d(TAG, "onUpdate(): index="+index);
  124. // 获取 example_appwidget.xml 对应的RemoteViews
  125. RemoteViews remoteView = new RemoteViews(context.getPackageName(), R.layout.example_appwidget);
  126. // 设置显示图片
  127. remoteView.setImageViewResource(R.id.iv_show, ARR_IMAGES[index]);
  128. // 设置点击按钮对应的PendingIntent:即点击按钮时,发送广播。
  129. remoteView.setOnClickPendingIntent(R.id.btn_show, getPendingIntent(context,
  130. BUTTON_SHOW));
  131. // 更新 widget
  132. appWidgetManager.updateAppWidget(appID, remoteView);
  133. }
  134. }
  135. private PendingIntent getPendingIntent(Context context, int buttonId) {
  136. Intent intent = new Intent();
  137. intent.setClass(context, ExampleAppWidgetProvider.class);
  138. intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
  139. intent.setData(Uri.parse("custom:" + buttonId));
  140. PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0 );
  141. return pi;
  142. }
  143. // 调试用:遍历set
  144. private void prtSet() {
  145. if (DEBUG) {
  146. int index = 0;
  147. int size = idsSet.size();
  148. Iterator it = idsSet.iterator();
  149. Log.d(TAG, "total:"+size);
  150. while (it.hasNext()) {
  151. Log.d(TAG, index + " -- " + ((Integer)it.next()).intValue());
  152. }
  153. }
  154. }
  155. }
AppWidgetProvider重要的几个重写方法,比如onDeleted、onEnabled、onDisabled、onReceive、onUpdate方法的作用已经在代码里面做了注释

5. 编辑ExampleAppWidgetService.java

  1. public class ExampleAppWidgetService extends Service {
  2. private static final String TAG="ExampleAppWidgetService";
  3. // 更新 widget 的广播对应的action
  4. private final String ACTION_UPDATE_ALL = "com.skywang.widget.UPDATE_ALL";
  5. // 周期性更新 widget 的周期
  6. private static final int UPDATE_TIME = 5000;
  7. // 周期性更新 widget 的线程
  8. private UpdateThread mUpdateThread;
  9. private Context mContext;
  10. // 更新周期的计数
  11. private int count=0;
  12. @Override
  13. public void onCreate() {
  14. // 创建并开启线程UpdateThread
  15. mUpdateThread = new UpdateThread();
  16. mUpdateThread.start();
  17. mContext = this.getApplicationContext();
  18. super.onCreate();
  19. }
  20. @Override
  21. public void onDestroy(){
  22. // 中断线程,即结束线程。
  23. if (mUpdateThread != null) {
  24. mUpdateThread.interrupt();
  25. }
  26. super.onDestroy();
  27. }
  28. @Override
  29. public IBinder onBind(Intent intent) {
  30. return null;
  31. }
  32. /*
  33. * 服务开始时,即调用startService()时,onStartCommand()被执行。
  34. * onStartCommand() 这里的主要作用:
  35. * (01) 将 appWidgetIds 添加到队列sAppWidgetIds中
  36. * (02) 启动线程
  37. */
  38. @Override
  39. public int onStartCommand(Intent intent, int flags, int startId) {
  40. Log.d(TAG, "onStartCommand");
  41. super.onStartCommand(intent, flags, startId);
  42. return START_STICKY;
  43. }
  44. private class UpdateThread extends Thread {
  45. @Override
  46. public void run() {
  47. super.run();
  48. try {
  49. count = 0;
  50. while (true) {
  51. Log.d(TAG, "run ... count:"+count);
  52. count++;
  53. Intent updateIntent=new Intent(ACTION_UPDATE_ALL);
  54. mContext.sendBroadcast(updateIntent);
  55. Thread.sleep(UPDATE_TIME);
  56. }
  57. } catch (InterruptedException e) {
  58. // 将 InterruptedException 定义在while循环之外,意味着抛出 InterruptedException 异常时,终止线程。
  59. e.printStackTrace();
  60. }
  61. }
  62. }
  63. }

(01) onCreate() 在创建服务时被执行。它的作用是创建并启动线程UpdateThread()。
(02) onDestroy() 在销毁服务时被执行。它的作用是注销线程UpdateThread()。
(03) 服务UpdateThread 每隔5秒,发送1个广播ACTION_UPDATE_ALL。广播ACTION_UPDATE_ALL在ExampleAppWidgetProvider被处理:用来更新widget中的图片。

6.编译代码生成apk文件,将其安装到手机

7.长按手机的桌面(不同品牌手机可能操作方式不一样)会弹出桌面设置界面,选择添加工具

widget在添加到桌面前的效果图

widget在添加到桌面后的效果图

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/313073
推荐阅读
相关标签
  

闽ICP备14008679号