Android微件(续)
16lz
2021-12-04
Android微件(续)
Google 文档
几年前前写过一篇Android桌面小插件——Widget
重新梳理一下
温故知新
问:开发一个最简单的微件总共分几步?
答:总共分4步。
1、创建一个AppWidgetProvider
;
2、创建一个微件布局xml;
3、创建一个微件配置xml;
4、配置清单文件;
1、创建一个AppWidgetProvider
import android.appwidget.AppWidgetProviderclass SimpleWidget : AppWidgetProvider() {}
2、创建一个微件布局xml
res/layout/widget_simple.xml
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:layout_width="100dp" android:layout_height="100dp" android:background="#AAAAAA" android:gravity="center" android:text="我是微件" android:textColor="@android:color/black" android:textSize="15sp" />RelativeLayout>
3、创建一个微件配置xml
res/xml/widget_sample.xml
<?xml version="1.0" encoding="utf-8"?><appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:initialLayout="@layout/widget_simple" android:minWidth="100dp" android:minHeight="100dp" android:resizeMode="horizontal|vertical" android:previewImage="@mipmap/ic_launcher" android:updatePeriodMillis="86400000" android:widgetCategory="home_screen" />
常用的配置(更多详细配置见google文档)
- initialLayout :第2步创建的微件布局
- minWidth:微件最小宽度
- minHeight:微件最小高度
- resizeMode:是否可以横向或纵向拉伸
- previewImage:显示的预览样式
- updatePeriodMillis:更新频率,默认86400000为一天
- widgetCategory:声明应用微件是否可以显示在主屏幕 (home_screen) 和/或锁定屏幕 (keyguard) 上
4、配置清单文件
<receiver android:name=".widget.SimpleWidget" android:label="最简单的微件"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_sample" />receiver>
- receiver-name:第1步创建的AppWidgetProvider
- receiver-label:自定义的微件名称
- resource:第2步创建的微件配置xml
- 其他:固定写法
完成上述步骤,在微件中就可以看到我们刚刚创建的最简单的微件了,后续一些交互需要在我们第一步创建的AppWidgetProvider中实现。
微件布局
微件并不是支持所有布局和控件,目前支持的布局包括:
- FrameLayout
- LinearLayout
- RelativeLayout
- GridLayout
支持的控件包括:
- AnalogClock
- Button
- Chronometer
- ImageButton
- ImageView
- ProgressBar
- TextView
- ViewFlipper
- ListView
- GridView
- StackView
- AdapterViewFlipper
注意:能且仅能使用以上控件,包含任意其他控件都会导致
加载微件时出现问题
,包括AppCompatXXX等
生命周期
微件添加到桌面
- onEnabled
- onReceive :android.appwidget.action.APPWIDGET_ENABLED
- onUpdate
- onReceive :android.appwidget.action.APPWIDGET_UPDATE
微件从桌面移除
- onDeleted
- onReceive :android.appwidget.action.APPWIDGET_DELETED
- onDisabled
- onReceive :android.appwidget.action.APPWIDGET_DISABLED
定时更新
在配置xml中updatePeriodMillis属性配置的更新频率,单位为毫秒,按照官方文档的描述,该配置不能保证
onUpdate
正好准时回调,但是建议我们尽量降低频率,暂未验证其生命周期(其实是没收到回调)o(╥﹏╥)o,不负责任的推测应该是:[可怜]
- onUpdate
- onReceive :android.appwidget.action.APPWIDGET_UPDATE
重启APP
重启App对微件生命周期无影响
重启手机
- onEnabled
- onReceive :android.appwidget.action.APPWIDGET_ENABLED
- onUpdate
- onReceive :android.appwidget.action.APPWIDGET_UPDATE
单击事件
在onUpdate
中添加控件的点击监听。
我们给控件添加点击监听的常规做法是view.findviewbyid
,然后setOnclickListener
,在微件中稍有不同。微件中相当于是给控件的点击注册了一个广播,当控件被点击了以后,会发出一个广播,在onReceive
中接收。
代码大概长这个样子
class SimpleWidget : AppWidgetProvider() { companion object { // 这里给布局上的4个按钮分别准备4个广播的action private const val ACTION_1 = "com.kongqw.widght.btn1" private const val ACTION_2 = "com.kongqw.widght.btn2" private const val ACTION_3 = "com.kongqw.widght.btn3" private const val ACTION_4 = "com.kongqw.widght.btn4" } override fun onReceive(context: Context?, intent: Intent?) { super.onReceive(context, intent) // 收到广播,根据action来判断点击的是哪个控件 when (intent?.action) { ACTION_1 -> Toast.makeText(context, "点击了1", Toast.LENGTH_SHORT).show() ACTION_2 -> Toast.makeText(context, "点击了2", Toast.LENGTH_SHORT).show() ACTION_3 -> Toast.makeText(context, "点击了3", Toast.LENGTH_SHORT).show() ACTION_4 -> Toast.makeText(context, "点击了4", Toast.LENGTH_SHORT).show() } } override fun onUpdate(context: Context?, appWidgetManager: AppWidgetManager?, appWidgetIds: IntArray?) { super.onUpdate(context, appWidgetManager, appWidgetIds) // 找到微件布局 val remoteViews = RemoteViews(context?.packageName, R.layout.widget_simple) // 给布局的四个按钮绑定广播,相当于只要按钮点击,就会发一个我们设置的广播出来 remoteViews.setOnClickPendingIntent(R.id.btn_1, getPendingIntent(context, ACTION_1)) remoteViews.setOnClickPendingIntent(R.id.btn_2, getPendingIntent(context, ACTION_2)) remoteViews.setOnClickPendingIntent(R.id.btn_3, getPendingIntent(context, ACTION_3)) remoteViews.setOnClickPendingIntent(R.id.btn_4, getPendingIntent(context, ACTION_4)) // 更新微件 appWidgetManager?.updateAppWidget(appWidgetIds, remoteViews) } /** * 获取PendingIntent */ private fun getPendingIntent(context: Context?, action: String): PendingIntent? { if (null == context) { return null } val intent = Intent(action).apply { setClass(context, SimpleWidget::class.java) } return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) }}
PendingIntent.getBroadcast()中的flag参数说明,详见google文档-PendingIntent
更多相关文章
- Android(安卓)Layout文件的属性说明
- Android(安卓)selector 状态选择器
- Padding与绘制区域--android:clipToPadding和android:clipChildr
- Android(安卓)ListView拖动时背景变黑的解决方法
- Android其它新控件
- Android(安卓)学习之一
- Android(安卓)selector状态选择器的使用详解
- KJFrameForAndroid
- Android中webview加载的网页上的按钮点击失效