当前位置:   article > 正文

android中Appwidget的使用_action_appwidget_update

action_appwidget_update

我们常见的桌面小插件,例如一个桌面上系统setgings开关组合,可以控制蓝牙,wifi是否开启,例如一个桌面的小天气等等;这些都是Appwidget的使用例子。

下面介绍如何使用Appwidget;

在使用的过程中涉及到一些关键类,下面一一列举:

1.AppWidget provider:

该类是BroadcastReceiver的子类,里面的onReceive方法里实现了对几个常用的action的监听;
 例如:
 AppWidgetManager.ACTION_APPWIDGET_UPDATE
 AppWidgetManager.ACTION_APPWIDGET_DELETED
 AppWidgetManager.ACTION_APPWIDGET_OPTIONS_CHANGED
 AppWidgetManager.ACTION_APPWIDGET_ENABLED
 AppWidgetManager.ACTION_APPWIDGET_DISABLED
 AppWidgetManager.ACTION_APPWIDGET_RESTORED
 当接收到其中一个时,会调用对应的空的实现方法,你可以在你继承该AppWidgetProvider的类中
 有选择的重写如下方法:

onReceive(Context, Intent):

除了上面的几种action监听外,你还可以自己定义一些来监听。

void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds):

当需要提供RemoteViews时调用

void onDeleted(Context context, int[] appWidgetIds)

当widget实例被删除时调用

void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager,
            int appWidgetId, Bundle newOptions)

当widget的大小发生改变时调用,

void onEnabled(Context context)

当第一个widget被实例化时调用,

void onDisabled(Context context)

最后一个widget实例被删除时调用,

void onRestored(Context context, int[] oldWidgetIds, int[] newWidgetIds)

当widget实例备份恢复时调用,

2.AppWidgetManager:

用来更新widiget的状态和获取已经安装的widget的信息,AppWidgetManager getInstance(Context context)获取实例。

该类中也有一些方法可以看看

updateAppWidget(int[] appWidgetIds, RemoteViews views)可以在ACTION_APPWIDGET_UPDATE执行
 其中views里面的view持有的bitmap所占内存不能超过screen width x screen height x 4 x 1.5字节

 notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId)
 更新数据

 List<AppWidgetProviderInfo> getInstalledProviders()
 获取已经安装的AppWidget

 AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId)
 根据id获取Info 

3. AppWidgetProviderInfo:

用来描述widget的属性,在res/xml/定义如:

  1. <span style="font-size:14px;"><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|keyguard"
  10. android:initialKeyguardLayout="@layout/example_keyguard">
  11. </appwidget-provider></span>
一些常用属性介绍:
  1. <span style="font-size:14px;">resizeMode :RESIZE_NONE,RESIZE_HORIZONTAL,RESIZE_VERTICAL,RESIZE_BOTH:在某些方向上的大小是否可调
  2. widgetCategory:WIDGET_CATEGORY_HOME_SCREEN,WIDGET_CATEGORY_KEYGUARD:在桌面或者锁屏界面显示
  3. ComponentName:对应的是widget在manifest中的name属性
  4. minWidth,minHeight:最小宽和高,单位dp
  5. minResizeWidth 和 minResizeHeight :
  6. 使用这两个属性,可以允许用户重新调整 widget 的大小,使 widget 的大小可以小于 minWidth 和 minHeight。
  7. updatePeriodMillis,更新频率,单位ms,最好设置为不要比1小时更短的时间,如果短于30分钟,系统还是只会30分钟一次。这个使系统实现的更新机制。
  8. 如果我们要更短的话,就只有使用service,AlarmManager
  9. initialLayout,widget添加到桌面时的初始布局
  10. initialKeyguardLayout,widget在添加到锁屏界面的初始布局,只有当category是在锁屏类型时有效。
  11. configure:定义了 widget 的配置 Activity
  12. previewImage: 指定预览图,该预览图在用户选择 widget 时出现,如果没有提供,则会显示应用的图标</span>

一些关键说明:

默认情况下(即不设置android:widgetCategory属性),Android是将widget添加到 home screen 中。但在Android 4.2中,若用户希望 widget 可以被添加到lock screen中,可以通过设置 widget 的 android:widgetCategory 属性包含keyguard来完成。
当你把 widget 添加到lock screen中时,你可能对它进行定制化操作,以区别于添加到home screen中的情况。 你能够通过 getAppWidgetOptions() 来进行判断 widget 是被添加到lock screen中,还是home screen中。通过 getApplicationOptions() 获取 Bundle对象,然后读取 Bundle 的OPTION_APPWIDGET_HOST_CATEGORY值:若值为 WIDGET_CATEGORY_HOME_SCREEN, 则表示该 widget 被添加到home screen中; 若值为 WIDGET_CATEGORY_KEYGUARD,则表示该 widget 被添加到lock screen中。

布局中的问题:

布局时要留有widget的margin,padding

大小设置:70 × n − 30,n为多少行或列

 支持的根布局:

FrameLayout
LinearLayout
RelativeLayout
GridLayout

支持的控件:

AnalogClock
Button
Chronometer
ImageButton
ImageView
ProgressBar
TextView
ViewFlipper
ListView
GridView
StackView
AdapterViewFlipper

 使用例子:

首先要定义一个AppWidgetProvider ,这里继承该类;

ExampleAppWidgetProvider.java

  1. <span style="font-size:14px;">package com.example.sample;
  2. import java.util.HashSet;
  3. import java.util.Iterator;
  4. import java.util.Set;
  5. import android.annotation.SuppressLint;
  6. import android.app.PendingIntent;
  7. import android.appwidget.AppWidgetManager;
  8. import android.appwidget.AppWidgetProvider;
  9. import android.content.Context;
  10. import android.content.Intent;
  11. import android.net.Uri;
  12. import android.os.Bundle;
  13. import android.util.Log;
  14. import android.widget.RemoteViews;
  15. import android.widget.Toast;
  16. @SuppressLint("NewApi")
  17. public class ExampleAppWidgetProvider extends AppWidgetProvider {
  18. // 保存 widget 的id的HashSet,每新建一个 widget 都会为该 widget 分配一个 id。
  19. private static Set idsSet = new HashSet();
  20. // 按钮信息
  21. private static final int BUTTON_SHOW = 1;
  22. // 图片数组
  23. private static final int[] ARR_IMAGES = { R.drawable.sample_0,
  24. R.drawable.sample_1, R.drawable.sample_2, R.drawable.sample_3,
  25. R.drawable.sample_4, R.drawable.sample_5, R.drawable.sample_6,
  26. R.drawable.sample_7, };
  27. private static final String TAG = "Provider";
  28. private static Intent intent;
  29. // 第一个widget被创建时调用
  30. @Override
  31. public void onEnabled(Context context) {
  32. Log.d(TAG, "onEnabled");
  33. // 在第一个 widget 被创建时,开启服务
  34. intent = new Intent(context, ExampleAppWidgetService.class);
  35. context.startService(intent);
  36. }
  37. // 最后一个widget被删除时调用
  38. @Override
  39. public void onDisabled(Context context) {
  40. Log.d(TAG, "onDisabled");
  41. // 在最后一个 widget 被删除时,终止服务
  42. context.stopService(intent);
  43. }
  44. @Override
  45. public void onReceive(Context context, Intent intent) {
  46. super.onReceive(context, intent);
  47. final String action = intent.getAction();
  48. Log.d(TAG, "OnReceive:Action: " + action);
  49. if (ExampleAppWidgetService.UPDATE_WIDGET_ACTION.equals(action)) {
  50. // “更新”广播
  51. updateAllAppWidgets(context, AppWidgetManager.getInstance(context),
  52. idsSet);
  53. } else if (intent.hasCategory(Intent.CATEGORY_ALTERNATIVE)) {
  54. // “按钮点击”广播
  55. Uri data = intent.getData();
  56. int buttonId = Integer.parseInt(data.getSchemeSpecificPart());
  57. if (buttonId == BUTTON_SHOW) {
  58. Log.d(TAG, "Button wifi clicked");
  59. Toast.makeText(context, "Button Clicked", Toast.LENGTH_SHORT)
  60. .show();
  61. }
  62. }
  63. }
  64. // onUpdate() 在更新 widget 时,被执行,
  65. @Override
  66. public void onUpdate(Context context, AppWidgetManager appWidgetManager,
  67. int[] appWidgetIds) {
  68. Log.d(TAG, "onUpdate(): appWidgetIds.length=" + appWidgetIds.length);
  69. // 每次 widget 被创建时,对应的将widget的id添加到set中
  70. for (int appWidgetId : appWidgetIds) {
  71. idsSet.add(Integer.valueOf(appWidgetId));
  72. }
  73. prtSet();
  74. }
  75. // 当 widget 被初次添加 或者 当 widget 的大小被改变时,被调用
  76. @Override
  77. public void onAppWidgetOptionsChanged(Context context,
  78. AppWidgetManager appWidgetManager, int appWidgetId,
  79. Bundle newOptions) {
  80. super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId,
  81. newOptions);
  82. }
  83. // widget被删除时调用
  84. @Override
  85. public void onDeleted(Context context, int[] appWidgetIds) {
  86. Log.d(TAG, "onDeleted(): appWidgetIds.length=" + appWidgetIds.length);
  87. // 当 widget 被删除时,对应的删除set中保存的widget的id
  88. for (int appWidgetId : appWidgetIds) {
  89. idsSet.remove(Integer.valueOf(appWidgetId));
  90. }
  91. prtSet();
  92. }
  93. // 更新所有的 widget
  94. private void updateAllAppWidgets(Context context,
  95. AppWidgetManager appWidgetManager, Set set) {
  96. Log.d(TAG, "updateAllAppWidgets(): size=" + set.size());
  97. // widget 的id
  98. int appID;
  99. // 迭代器,用于遍历所有保存的widget的id
  100. Iterator it = set.iterator();
  101. while (it.hasNext()) {
  102. appID = ((Integer) it.next()).intValue();
  103. // 随机获取一张图片
  104. int index = (new java.util.Random().nextInt(ARR_IMAGES.length));
  105. Log.d(TAG, "onUpdate(): index=" + index);
  106. // 获取 example_appwidget.xml 对应的RemoteViews
  107. RemoteViews remoteView = new RemoteViews(context.getPackageName(),
  108. R.layout.example_appwidget);
  109. // 设置显示图片
  110. remoteView.setImageViewResource(R.id.iv_show, ARR_IMAGES[index]);
  111. // 设置点击按钮对应的PendingIntent:即点击按钮时,发送广播。
  112. remoteView.setOnClickPendingIntent(R.id.btn_show,
  113. getPendingIntent(context, BUTTON_SHOW));
  114. // 更新 widget
  115. appWidgetManager.updateAppWidget(appID, remoteView);
  116. }
  117. }
  118. private PendingIntent getPendingIntent(Context context, int buttonId) {
  119. Intent intent = new Intent();
  120. intent.setClass(context, ExampleAppWidgetProvider.class);
  121. intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
  122. intent.setData(Uri.parse("custom:" + buttonId));
  123. PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
  124. return pi;
  125. }
  126. // 调试用:遍历set
  127. private void prtSet() {
  128. int index = 0;
  129. int size = idsSet.size();
  130. Iterator it = idsSet.iterator();
  131. Log.d(TAG, "total:" + size);
  132. while (it.hasNext()) {
  133. Log.d(TAG, index + " -- " + ((Integer) it.next()).intValue());
  134. }
  135. }
  136. }
  137. </span>

接着在res下建立xml文件夹,在文件夹下定义一个文件来描述该provider

example_appwidget_info.xml

  1. <span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
  2. <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:initialLayout="@layout/example_appwidget"
  4. android:initialKeyguardLayout="@layout/example_appwidget"
  5. android:minHeight="180dp"
  6. android:minWidth="180dp"
  7. android:previewImage="@drawable/preview"
  8. android:resizeMode="horizontal|vertical"
  9. android:widgetCategory="home_screen|keyguard" >
  10. </appwidget-provider></span>

provider队友的布局;example_appwidget.xml

  1. <span style="font-size:14px;"><?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. </span>

接着定义一个服务service,来更新provider;

ExampleAppWidgetService.java

  1. <span style="font-size:14px;">package com.example.sample;
  2. import android.app.Service;
  3. import android.content.Intent;
  4. import android.os.IBinder;
  5. public class ExampleAppWidgetService extends Service {
  6. public static final String UPDATE_WIDGET_ACTION = "com.example.sample.ExampleAppWidgetProvider.UPDATE_ACTION";
  7. private Thread mUpdateThread;
  8. @Override
  9. public IBinder onBind(Intent intent) {
  10. return null;
  11. }
  12. @Override
  13. public void onCreate() {
  14. super.onCreate();
  15. updateWidget();
  16. }
  17. @Override
  18. public void onDestroy() {
  19. super.onDestroy();
  20. // 中断线程,即结束线程。
  21. if (mUpdateThread != null) {
  22. mUpdateThread.interrupt();
  23. }
  24. }
  25. private void updateWidget() {
  26. mUpdateThread = new Thread() {
  27. public void run() {
  28. while (true) {
  29. try {
  30. Thread.sleep(5 * 1000); //每隔5s更新一次
  31. } catch (InterruptedException e) {
  32. e.printStackTrace();
  33. }
  34. sendBroadcast(new Intent(UPDATE_WIDGET_ACTION));
  35. }
  36. };
  37. };
  38. mUpdateThread.start();
  39. }
  40. }
  41. </span>
接着在manifest里声明,provider,service

  1. <span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.example.sample"
  4. android:versionCode="1"
  5. android:versionName="1.0" >
  6. <uses-sdk
  7. android:minSdkVersion="14"
  8. android:targetSdkVersion="22" />
  9. <application
  10. android:allowBackup="true"
  11. android:icon="@drawable/ic_launcher"
  12. android:label="@string/app_name"
  13. android:theme="@style/AppTheme" >
  14. <activity
  15. android:name=".MainActivity"
  16. android:label="@string/app_name" >
  17. <intent-filter>
  18. <action android:name="android.intent.action.MAIN" />
  19. <category android:name="android.intent.category.LAUNCHER" />
  20. </intent-filter>
  21. </activity>
  22. <receiver android:name="com.example.sample.ExampleAppWidgetProvider" >
  23. <intent-filter>
  24. <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
  25. <action android:name="com.example.sample.ExampleAppWidgetProvider.UPDATE_ACTION"/>
  26. </intent-filter>
  27. <!-- 描述appwidget的属性信息-->
  28. <meta-data
  29. android:name="android.appwidget.provider"
  30. android:resource="@xml/example_appwidget_info" />
  31. </receiver>
  32. <service android:name="com.example.sample.ExampleAppWidgetService"></service>
  33. </application>
  34. </manifest></span>





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

闽ICP备14008679号