标签:tcl equal rip 技术分享 start dex protected simple 对象
App Widget是应用程序窗口小部件(Widget)是微型的应用程序视图,它可以被嵌入到其它应用程序中(比如桌面)并接收周期性的更新。
首先上一张图来给大家看一看效果。
Widget小部件,通常具备一定的功能;并且通常是和某个应用程序是关联的,通过点击手机桌面上的Widget小部件,会触发启动相对应的应用程序。Widget小部件,通常需要用户手动自行摆放到手机桌面(长按手机桌面,添加“小部件”,从小部件列表中选择)。
很多应用程序APP自带小部件,比如QQ音乐的“听音识曲”。安装了的朋友,长按手机桌面,添加“小部件”,会发现小部件列表中就会有QQ音乐的“听音识曲”。
详细介绍可以参考Android官方文本
AppWidgetProvider 继承自BroadcastReceiver,它能接收 widget 相关的广播,例如 widget 的更新、删除、开启和禁用等。我们的Android应用程序可以通过一个AppWidgetProvider来发布一个Widget。
通常我们的Android应用程序需要定义一个类,继承AppWidgetProvider。
AppWidgetProvider中的广播处理函数
(1)onUpdate()
当 widget 更新时被执行。同样,当用户首次添加 widget 时,onUpdate() 也会被调用,这样 widget 就能进行必要的设置工作(如果需要的话) 。但是,如果定义了widget 的 configure属性(即android:config,后面会介绍),那么当用户首次添加 widget 时,onUpdate()不会被调用;之后更新 widget 时,onUpdate才会被调用。
(2)onAppWidgetOptionsChanged()
当 widget 被初次添加 或者 当 widget 的大小被改变时,执行onAppWidgetOptionsChanged()。你可以在该函数中,根据widget 的大小来显示/隐藏某些内容。可以通过getAppWidgetOptions() 来返回 Bundle 对象以读取 widget 的大小信息,Bundle中包括以下信息:
OPTION_APPWIDGET_MIN_WIDTH – 包含 widget 当前宽度的下限,以dp为单位。
OPTION_APPWIDGET_MIN_HEIGHT – 包含 widget 当前高度的下限,以dp为单位。
OPTION_APPWIDGET_MAX_WIDTH – 包含 widget 当前宽度的上限,以dp为单位。
OPTION_APPWIDGET_MAX_HEIGHT – 包含 widget 当前高度的上限,以dp为单位。
onAppWidgetOptionsChanged() 是 Android 4.1 引入的。
(3)onDeleted(Context, int[])
当 widget 被删除时被触发。
(4)onEnabled(Context)
当第1个 widget 的实例被创建时触发。也就是说,如果用户对同一个 widget 增加了两次(两个实例),那么onEnabled()只会在第一次增加widget时触发。
(5)onDisabled(Context)
当最后1个 widget 的实例被删除时触发。
(6)onReceive(Context, Intent)
接收到任意广播时触发,并且会在上述的方法之前被调用。
总结,AppWidgetProvider 继承于 BroadcastReceiver。实际上,App Widge中的onUpdate()、onEnabled()、onDisabled()等方法都是在 onReceive()中分发调用的,是onReceive()对特定事件的响应。
AppWidgetProviderInfo描述一个App Widget元数据,比如App Widget的布局,更新频率,以及AppWidgetProvider 类, 这个文件是在res/xml中定义的,后缀为xml。下面以XML示例来对AppWidgetProviderInfo中常用的类型进行说明。
<!--?xml version="1.0"encoding="utf-8"?--> <!-- 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:initialKeyguardLayout: 加载到锁屏界面时对应的布局文件 --> </appwidget-provider>
(1) updatePeriodMillis
它定义了 widget 的更新频率。实际的更新时机不一定是精确的按照这个时间发生的。建议更新尽量不要太频繁,最好是低于1小时一次。 或者可以在配置 Activity 里面供用户对更新频率进行配置。实际上,当updatePeriodMillis的值小于30分钟时,系统会自动将更新频率设为30分钟!关于这部分,后面会详细介绍。
注意: 当更新时机到达时,如果设备正在休眠,那么设备将会被唤醒以执行更新。如果更新频率不超过1小时一次,那么对电池寿命应该不会造成多大的影响。 如果你需要比较频繁的更新,或者你不希望在设备休眠的时候执行更新,那么可以使用基于 alarm 的更新来替代 widget 自身的刷新机制。将 alarm 类型设置为 ELAPSED_REALTIME 或 RTC,将不会唤醒休眠的设备,同时请将 updatePeriodMillis 设为 0。
因此,我们若向动态的更新widget的某组件,最好通过service、AlarmManager、Timer等方式。
(2)initialLayout
指向 widget 的布局资源文件
(3)widgetCategory
指定了 widget 能显示的地方:能否显示在 home Screen 或 lock screen 或 两者都可以。它的取值包括:”home_screen”和 “keyguard”。Android 4.2 引入。
1.第一个xml是布局XML文件(如:res\layout\my_time_widget.xml),是这个widget的界面。一般来说如果用这个部件显示时间,那就只在这个布局XML中声明一个textview就OK了。
2.第二个xml是res\xml\my_time_widget_info.xml,主要是用于声明一个appwidget的。其中,Layout就是指定上面那个my_time_widget.xml。
3.第三个xml是AndroidManifest.xml,注册broadcastReceiver信息。android:name=".MyTimeWidget",MyTimeWidget就是自定义的Java类继承自AppWidgetProvider。
4.最后那个class用于做一些业务逻辑操作。新建MyTimeWidget类,让其继承类AppWidgetProvider。AppWidgetProvider中有许多回调方法。
实例:
1、 Widget界面布局res\layout\my_time_widget.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#09C" android:padding="@dimen/widget_margin"> <TextView android:id="@+id/appwidget_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#09C" android:contentDescription="@string/appwidget_text" android:text="@string/appwidget_text" android:textColor="#ffffff" android:textSize="24sp" android:textStyle="bold|italic" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginTop="106dp" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" /> <TextClock android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/appwidget_text" android:layout_centerHorizontal="true" android:id="@+id/textClock" /> </RelativeLayout>
2、 Widget描述文件res\xml\my_time_widget_info.xml
<?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:initialKeyguardLayout="@layout/my_time_widget" android:initialLayout="@layout/my_time_widget" android:minHeight="110dp" android:minWidth="250dp" android:previewImage="@drawable/example_appwidget_preview" android:resizeMode="horizontal|vertical" android:updatePeriodMillis="86400000" android:widgetCategory="home_screen"></appwidget-provider>
3、 清单文件AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.ljheee.mytimewidget"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <receiver android:name=".MyTimeWidget"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="com.ljheee.widget.UPDATE_TIME"/> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/my_time_widget_info" /> </receiver> <service android:name=".TimeService" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="android.appwidget.action.MY_APP_WIDGET_SERVICE" /> </intent-filter> </service> </application> </manifest>
4、 MyTimeWidget.java
package com.ljheee.mytimewidget; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.os.AsyncTask; import android.widget.RemoteViews; import java.text.SimpleDateFormat; import java.util.Date; public class MyTimeWidget extends AppWidgetProvider { static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); // 启动ExampleAppWidgetService服务对应的action private final Intent TIME_SERVICE_INTENT = new Intent("android.appwidget.action.MY_APP_WIDGET_SERVICE"); // 更新 widget 的广播对应的action private final String ACTION_UPDATE_ALL = "com.ljheee.widget.UPDATE_TIME"; Context mContext; GetDate getDate; static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { CharSequence widgetText = context.getString(R.string.appwidget_text); // Construct the RemoteViews object RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.my_time_widget); views.setTextViewText(R.id.appwidget_text, sdf.format(new Date())); // Instruct the widget manager to update the widget appWidgetManager.updateAppWidget(appWidgetId, views); } @Override public void onReceive(Context context, Intent intent) { if(mContext==null){ mContext = context; } final String action = intent.getAction(); if (ACTION_UPDATE_ALL.equals(action)) { // “更新”广播 // updateAppWidget(context, AppWidgetManager.getInstance(context)); // onUpdate(context,AppWidgetManager.getInstance(context), mAppWidgetIds); getDate = new GetDate(); getDate.execute(); } super.onReceive(context, intent); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // There may be multiple widgets active, so update all of them for (int appWidgetId : appWidgetIds) { updateAppWidget(context, appWidgetManager, appWidgetId); } } @Override public void onEnabled(Context context) { // 在第一个 widget 被创建时,开启服务 context.startService(TIME_SERVICE_INTENT); super.onEnabled(context); } @Override public void onDisabled(Context context) { // 在最后一个 widget 被删除时,终止服务 context.stopService(TIME_SERVICE_INTENT); super.onDisabled(context); } //请求数据 class GetDate extends AsyncTask { AppWidgetManager awm = null; ComponentName componentName = null; @Override protected void onPreExecute() { if(awm==null){ awm = AppWidgetManager.getInstance(mContext); } if(componentName==null){ componentName = new ComponentName(mContext, AppWidgetProvider.class); } super.onPreExecute(); } @Override protected Object doInBackground(Object[] params) { return null; } @Override protected void onPostExecute(Object o) { //更新界面 RemoteViews remoteViews = new RemoteViews(mContext.getPackageName(), R.layout.my_time_widget); remoteViews.setTextViewText(R.id.appwidget_text, sdf.format(new Date())); awm.updateAppWidget(componentName, remoteViews); super.onPostExecute(o); } } }
目前Android Studio 2.23版本,直接新建一个Android工程(No Activity),在空工程中,直接new-àWidget-àApp Widget即可。输入MyTimeWidget类名,相关的widget界面布局、Widget描述文件、清单文件注册一体化自动建好。
编译并运行程序,我们知道这种Widget程序,即使装完了也不会在程序列表中出现,因为它根本就没有main Activity,在桌面上长按,等待弹出对话框,选择“小部件”,从列表中选择拖拽带手机桌面。
完整工程:https://github.com/ljheee/MyTimeWidget
标签:tcl equal rip 技术分享 start dex protected simple 对象
原文地址:http://blog.csdn.net/ljheee/article/details/70138951