您的位置:首页 > 移动开发

Android中AppWidget的学习整理(附demo)

2016-02-16 21:03 369 查看
今天写的是AppWidget,这是我工作之后接触的第一个模块。乘着有时间整理下知识点。

先附上DEMO:http://download.csdn.net/detail/violetjack0808/9433218

这里实现的是一个用来计数的AppWidget桌面小部件。效果图如下:



下面是实现步骤

1.创建AppWidget配置文件

在res/xml目录下创建app_widget_config.xml文件,用来配置widget属性。

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/widget_ui"
android:minHeight="140dip"
android:minWidth="140dip"
android:updatePeriodMillis="6890000" >
</appwidget-provider>


这个xml是用来描述所要创建的appWidget的一些描述信息的,所描述的属性分别有最小高度、最小宽度、刷新间隔和关联布局文件布局文件。

特别要说的是AppWidget的大小是以格为单位来计算的,手机屏幕被分为一个4*4的格阵,当宽高到达一定值时就会显示并占满相应的格数,不会出现自定义不规则的大小的。网上资料显示说N格的长宽为(74*N)-2。我设定的140*140显示的是2*2的界面。

2.创建布局文件
在res/layout中创建widget_ui.xml这个布局文件。这里画的布局就会是我们在手机桌面上看到的widget的样子啦~

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="this is a widget" />

<TextView
android:id="@+id/tvResult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="result = 0"/>

<Button
android:id="@+id/btnAdd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="add one"/>

</LinearLayout>


3.创建AppWidgetProvider

在src目录下创建AppWidget类继承自AppWidgetProvider,用以实现widget的交互。

当我看到onReceive方法觉得奇怪,这不是广播接收器吗?结果进去一看发现AppWidgetProvider就是继承自BroadcastReceiver的

public class AppWidgetProvider extends BroadcastReceiver

所以,widget的工作原理就是通过广播来实现对它的控制的。

3.1 AppWidgetProvider的生命周期:

onEnabled
当AppWidget实例第一次被创建时调用。

onReceive
接收广播事件。

onUpdate
到达指定的更新时间或用户向桌面添加widget时候调用。

onDeleted
当AppWidget被删除时调用。

onDisabled
当最后一个AppWidget被删除时调用。

3.2.RemoteViews和PendingIntent

在onUpDate方法中用到了RemoteViews与PendingIntent, 是因为AppWidget和其原本的App并不在同一个进程中,而是运行在HomeScreen进程当中,因此,在控件监听器的绑定,更新等操作都会与以前基本的方法有所不同。

PendingIntent是一个特殊的Intent,实际上它像一个邮包,其中包裹着真正的Intent,当邮包未打开时,Intent是被“挂起”的,所以并不执行,只有当邮包拆开时才会执行。它与Intent的区别在于:Intent 是及时启动,intent 随所在的activity 消失而消失。 进程A创建PendingIntent,发送给进程B,进程B此事并不执行,直到用户出发某一事件时,包裹被拆开,里面的Intent真正执行。所以Intent什么时候被执行是不知道的,由用户出发事件来决定。

RemoteViews表示了一系列view对象,即AppWidget所有的控件。它的应用方法如下源码所示,使用了views.setOnClickPendingIntent(所需控件的ID,定义的pendingintent)方法来为控件绑定监听器。

3.3 源码

/**
* AppWidget学习demo
* 个人心得:
* onUpDate方法用于创建和更新AppWidget,将所需的ID通过intent进行传递。
* onReceive方法通过接收intent传送的广播事件实现AppWidget的变化操作。
*/
public class AppWidget extends AppWidgetProvider {

private static int i = 1;
private static final String ACTION = "click";

//当AppWidget实例第一次被创建时调用。
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
}

//接收广播事件。
@Override
public void onReceive(Context context, Intent intent) {
Log.e("widget", "onReceive + " + intent.getAction());
super.onReceive(context, intent);
ComponentName thisWidget = new ComponentName(context,AppWidget.class);//定义容器
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_ui);//定义RemoteViews
//定义AppWidgetManager,用于之后更新AppWidget
AppWidgetManager appWidgetManager = AppWidgetManager
.getInstance(context);

//通过接收广播的Intent来进行widget的UI操作
if (intent.getAction().equals(ACTION)) {
views.setTextViewText(R.id.tvResult, "result = " + i);
i++;
}

//更新AppWidget
appWidgetManager.updateAppWidget(thisWidget, views);
}

//到达指定的更新时间或用户向桌面添加widget时候调用。
public void onUpdate(Context context, AppWidgetManager appWidgetManager,int[] appWidgetIds) {
Log.e("widget", "onUpdate");
for (int id : appWidgetIds) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_ui);
Intent intent1 = new Intent("click");//定义intent
PendingIntent pendingIntentOne = PendingIntent.getBroadcast(context, 0, intent1, 0);//用PendingIntent将Intent包裹起来
views.setOnClickPendingIntent(R.id.btnAdd, pendingIntentOne);//按钮点击事件监听
//更新AppWidget
appWidgetManager.updateAppWidget(id, views);
}
}

//当AppWidget被删除时调用。
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
}

//当最后一个AppWidget被删除时调用。
@Override
public void onDisabled(Context context) {
super.onDisabled(context);
}
}


4.注册广播

上面提到了,AppWidgetProvider其实就是广播,所以我们需要在Manifest文件中注册广播。

这里注意Action的一致。关于广播的知识可以看我的Blog:Android广播Broadcast的学习(附demo)

代码:

<application
.... >
.....
<receiver android:name=".AppWidget" >
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/app_widget_config" />
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="click" />
</intent-filter>
</receiver>
....
</application>

注意:resource要关联我们之前写的app_widget_provider.xml文件;action中第一个必须写,第二个就是自定义action了。

这样一个计数的桌面小部件就完成啦~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: