• Android桌面控件Widget解析


    一:简介

        App Widgets(微型应用视图)它能够嵌入到其他应用程序(如 系统桌面/其他应用的Activity)并接受定期更新,主要用于展现程序的快捷入口。

    1.1 :AppWidgetProvider 

         AppWidgetProvider接口基于BroadcastReceiver,通过定义这个接口,当App Widget update据发送改变,启动(enabled) ,disabled(禁用), deleted(删除)动作时,AppWidgetProvider 将会收到广播。

    1.2: View Layout

        定义App Widget 的初始化XML布局文件,另外,可以在App Widget 启动前,添加一个Activity用于配置Widget的一些参数

    二:使用

    2.1 : 在AndroidMainfest.xml清单文件声明我们定义的 AppWidgetProvider类

    1. <receiver android:name="ExampleAppWidgetProvider" >
    2. <intent-filter>
    3. <--!指定AppWidgetProvider接受系统的APPWIDGET_UPDATE广播-->
    4. <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    5. </intent-filter>
    6. <--!指定Meta_data名称,使用android.appwidgetb必须确定AppWidgetProviderInfo描述符的数据-->
    7. <--!指定AppWidgetProviderInfo资源XML文件-->
    8. <meta-data android:name="android.appwidget.provider"
    9. android:resource="@xml/example_appwidget_info" />
    10. </receiver>

    2.2 :创建AppWidgetProviderInfo  XML文件

    该XML文件定义 App Widget 的基本属性,在 res/xml/ 目录下创建 appwidget-provider 标签的XML文件

    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>

    1:如果定义的minWidth 和 minHeight不匹配当前屏幕,会自动缩放到合适大小
    2:如果定义的AppWidght想跨设备、最小宽高不应超过4*4单元格.
    3:如果设备到了更新时间(updatePeriodMillis)时处于睡眠状态,设备将会被唤醒更新,体验不好,建议要么设置一个按钮让用户手动刷新,要么设置updatePeriodMillis为0,使用AlarmManager设置警报Intent让AppwidgetProvider类接受,将报警类型设置为ELAPSED_REALTIM或RTC,只有设备唤醒时才会发出警报
    4:minResizeHeight属性指定小部件可以调整大小的最小高度.如果该字段大于minHeight,或者resizeMode的取值不包括vertical时,则该字段不起作用;
    5:minResizeWidth属性指定小部件可以调整大小的最小宽度.如果该字段大于minWidth,或者resizeMode的取值不包括horizontal时,则此字段无效
    6:AppWidget只有低于Android 5.0才能锁屏显示,高于5.0只能主屏显示

    2.3:定义App Widget XML布局文件

    由于widget的布局需要 RemoteViews 支持,因此不能随便定义或自定义View

    三:定义AppWidgetProvider类

    3.1 :onUpdate()

        当widget更新时被执行.(包含首次添加),如果在 AppWidgetProviderInfo 调用android:config,那么当用户首次添加widget时,onUpdate()不会被调用,之后更新widget时,onUpdate才会被调用.

    3.2 :  onAppWidgetOptionsChanged()

       Android 4.1引入的,当 widget 被初次添加 或者 当 widget 的大小被改变时,执行onAppWidgetOptionsChanged().你可以在该函数中,根据 widget 的大小来显示/隐藏某些内容.可以通过 getAppWidgetOptions() 来返回 Bundle 对象以读取 widget 的大小信息,Bundle中包括以下信息

    3.3:  onDeleted()

       当 widget 被删除时被触发.

    3.4: onEnabled()

    当第一次创建widget实例时触发.如果用户对同一个widget增加了两次(两个实例),那么onEnabled()只会在第一次添加widget时触发.

    3.5 : onDisabled();

    最后一个widget删除时被触发

    3.6: onReceive(Context, Intent)

    接收到任意广播时触发,并且会在上述的方法之前被调用.实际上,App Widge中的onUpdate()、onEnabled()、onDisabled()等方法都是在 onReceive()中调用的;是onReceive()对特定事情的响应函数

    3.7 : onRestored(Context context, int[] oldWidgetIds, int[] newWidgetIds)

    在从备份还原此AppWidget提供程序的实例时,响应ACTION_APPWIDGET_RESTORED广播调用.

    如果您的提供商维护有关其窗口小部件实例的任何持久性数据,请覆盖此方法以将旧的AppWidgetIds重新映射到新值,并更新可能相关的任何其他应用程序状态.

    这个回调函数将立即通过调用onUpdate(Context,AppWidgetManager,int [])来实现,因此您的提供者可以立即生成适用于新恢复的实例集的新RemoteView.
     

    1. public class ExampleAppWidget extends AppWidgetProvider {
    2. static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
    3. int appWidgetId) {
    4. CharSequence widgetText = context.getString(R.string.appwidget_text);
    5. // Construct the RemoteViews object
    6. RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
    7. views.setTextViewText(R.id.appwidget_text, widgetText);
    8. // Instruct the widget manager to update the widget
    9. appWidgetManager.updateAppWidget(appWidgetId, views);
    10. }
    11. @Override
    12. public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    13. // There may be multiple widgets active, so update all of them
    14. for (int appWidgetId : appWidgetIds) {
    15. updateAppWidget(context, appWidgetManager, appWidgetId);
    16. }
    17. }
    18. @Override
    19. public void onEnabled(Context context) {
    20. // Enter relevant functionality for when the first widget is created
    21. }
    22. @Override
    23. public void onDisabled(Context context) {
    24. // Enter relevant functionality for when the last widget is disabled
    25. }
    26. @Override
    27. public void onReceive(Context context, Intent intent) {
    28. //用于接收指定意图,处理相关需求,可以重写onRecrive(),如我们收到一个toast的动作时,显示一条Toast
    29. }
    30. }

    四: 给App Widget设置点击事件 

    在AppWidgetProvider中最重要的回调是onUpate(),除非使用 configuration Activity ,不然每个 App Widget 添加到主机Host时都会调用onUpdate().

    那么如果你的App Widget不需要创建临时文件或数据库,或需要执行清理其他工作,那么其他的逻辑业务基本在onUpate()中实现即可

    onUpdate

    1. public class ExampleAppWidgetProvider extends AppWidgetProvider {
    2. public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    3. final int N = appWidgetIds.length;
    4. // Perform this loop procedure for each App Widget that belongs to this provider
    5. for (int i=0; i<N; i++) {
    6. int appWidgetId = appWidgetIds[i];
    7. // Create an Intent to launch ExampleActivity
    8. Intent intent = new Intent(context, ExampleActivity.class);
    9. intent.setAction("TOAST_ACTION");
    10. PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    11. // Get the layout for the App Widget and attach an on-click listener
    12. // to the button
    13. RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout);
    14. views.setOnClickPendingIntent(R.id.button, pendingIntent);
    15. // Tell the AppWidgetManager to perform an update on the current app widget
    16. appWidgetManager.updateAppWidget(appWidgetId, views);
    17. }
    18. }
    19. }

    重写onReceive() ,用于接受意图,处理相关需求

    1. @Override
    2. public void onReceive(Context context, Intent intent) {
    3. super.onReceive(context, intent);
    4. if (intent.getAction().equals("TOAST_ACTION")) {
    5. Toast.makeText(context, "Touched view ", Toast.LENGTH_SHORT).show();
    6. }
    7. }

    五: 注意事项

    1: appWidgetIds是一个ID数组,用于标识此提供程序创建的每个App Widget。 这样,如果用户创建了多个App Widget实例,那么它们都将同时更新。 但是,如果多个App Widget 设置了updatePeriodMillis,那么只会调用第一个App Widget 实例的

    2: 由于AppWidgetProvider继承处于BroadcastReceiver,生命周期非常短,如果需要执行耗时操作会发生ANR异常,因此我们可以在onUpdate()方法中启动Service,然后在Service数据处理,个人建议在onRnable()启动服务,onDisable()关闭Service
     

  • 相关阅读:
    基于django的网络隐私检测系统
    T-SQL——将字符串转为单列
    Redis学习
    A × B Problem(高精度计算)
    理解case when then else end 的使用,基础概念,建表语句,用例讲解
    Matlab生成visio可导入的矢量图
    vscode 设置代理
    Matlab在同一张图中如何加入多个图例
    管道和FIFO
    C语言 | Leetcode C语言题解之第513题找树左下角的值
  • 原文地址:https://blog.csdn.net/u013620306/article/details/126784433