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

一个android应用向Home screen添加多个Widget

2012-01-30 17:30 591 查看
如Twitter客户端或者HTC的日历应用,可以添加大小不同的Widget。此疑问。

原来如此简单,只是我原来不会罢了。

首先在AndroidManifest.xml中太假多个接收器:

Xml代码


<receiver android:name="com.jftt.widget.MyWidgetProvider1" android:label="天气 4 x 1">

<meta-data android:name="android.appwidget.provider"

android:resource="@xml/my_widget1" />

<intent-filter>

<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />

</intent-filter>

</receiver>

<receiver android:name="com.jftt.widget.MyWidgetProvider" android:label="全部 4 x 2">

<meta-data android:name="android.appwidget.provider"

android:resource="@xml/my_widget" />

<intent-filter>

<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />

</intent-filter>

</receiver>

<receiver android:name="com.jftt.widget.MyWidgetProvider2" android:label="步数 4 x 1">

<meta-data android:name="android.appwidget.provider"

android:resource="@xml/my_widget2" />

<intent-filter>

<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />

</intent-filter>

</receiver>

CreateWidget.java文件内容如下:

Java代码


package com.jftt.activity;

import android.app.Activity;

import android.appwidget.AppWidgetManager;

import android.content.Intent;

import android.os.Bundle;

import android.util.Log;

import com.jftt.widget.R;

public class CreateWidget extends Activity {

private static final String TAG = "CreateWidget";

int mAppWidgetId;

@Override
protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

Log.i(TAG, " on WidgetConf ... ");

setResult(RESULT_CANCELED);
// Find the widget id from the intent.

Intent intent = getIntent();
Bundle extras = intent.getExtras();
if (extras != null) {

mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);

}

// If they gave us an intent without the widget id, just bail.

if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {

finish();
}

// return OK

Intent resultValue = new Intent();

resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);

setResult(RESULT_OK, resultValue);
finish();
}
}

MyWidgetProvider.java内容如下:

Java代码


package com.jftt.widget;

import android.app.PendingIntent;

import android.appwidget.AppWidgetManager;

import android.appwidget.AppWidgetProvider;

import android.content.ComponentName;

import android.content.Context;

import android.content.Intent;

import android.content.pm.PackageManager;

import android.util.Log;

import android.view.View;

import android.widget.RemoteViews;

import com.jftt.activity.WidgetSetting;

public class MyWidgetProvider extends AppWidgetProvider {

private static final String TAG = "MyWidgetProvider";

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {

super.onUpdate(context, appWidgetManager, appWidgetIds);

Log.i(TAG, "onUpdate");

final int N = appWidgetIds.length;

for (int i = 0; i < N; i++) {

int appWidgetId = appWidgetIds[i];

Log.i(TAG, "this is [" + appWidgetId + "] onUpdate!");

Intent intent = new Intent(context, WidgetSetting.class);

PendingIntent pending = PendingIntent.getActivity(context, 0, intent, 0);

Intent intent2 = new Intent(context, MyWidgetProvider.class);

intent2.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);

Log.i(TAG, "appWidgetId "+appWidgetId);

PendingIntent doubleClick = PendingIntent.getBroadcast(context, appWidgetId, intent2, PendingIntent.FLAG_UPDATE_CURRENT);

RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);

remoteViews.setOnClickPendingIntent(R.id.pic5, pending);

remoteViews.setOnClickPendingIntent(R.id.widget, doubleClick);

appWidgetManager.updateAppWidget(appWidgetId, remoteViews);

}
}

@Override
public void onDeleted(Context context, int[] appWidgetIds) {

super.onDeleted(context, appWidgetIds);

Log.i(TAG, "onDeleted");

final int N = appWidgetIds.length;

for (int i = 0; i < N; i++) {

int appWidgetId = appWidgetIds[i];

Log.i(TAG, "this is [" + appWidgetId + "] onDelete!");

}
}

@Override
public void onDisabled(Context context) {

super.onDisabled(context);

Log.i(TAG, "onDisabled");

PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(new ComponentName("com.jftt.widget", "com.jftt.widget.MyWidgetProvider"), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);

}

@Override
public void onEnabled(Context context) {

super.onEnabled(context);

Log.i(TAG, "onEnabled");

PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(new ComponentName("com.jftt.widget", "com.jftt.widget.MyWidgetProvider"), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);

}

static long start = 0;

@Override
public void onReceive(Context context, Intent intent) {

super.onReceive(context, intent);

if ((System.currentTimeMillis() - start) < 500) {

AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);

RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);

remoteViews.setViewVisibility(R.id.setting, View.VISIBLE);

int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 0);

appWidgetManager.updateAppWidget(appWidgetId, remoteViews);

} else {
start = System.currentTimeMillis();
}
}
}



效果如图。

Android AppWidget 开发中PendingIntent传送数据丢失解决办法

AppWidget要向外部发送数据,可以把数据放在Intent里,再用intent对象生成一个PendingIntent对象,然后用RemoteViews的setOnClickPendingIntent绑定到相应控件上,具体代码如下:

1 2 3 4 5 6 7 8 9 10

[java]
view plaincopyprint?

RemoteViews updateViews <SPAN style="COLOR: #339933">=</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #000000">new</SPAN> RemoteViews<SPAN style="COLOR: #009900">(</SPAN>context.<SPAN style="COLOR: #006633">getPackageName</SPAN><SPAN style="COLOR: #009900">(</SPAN><SPAN style="COLOR: #009900">)</SPAN>, R.<SPAN style="COLOR: #006633">layout</SPAN>.<SPAN style="COLOR: #006633">widget</SPAN><SPAN style="COLOR: #009900">)</SPAN><SPAN style="COLOR: #339933">;</SPAN> ComponentName thisWidget <SPAN style="COLOR: #339933">=</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #000000">new</SPAN> ComponentName<SPAN style="COLOR: #009900">(</SPAN>context,Widget.<SPAN style="FONT-WEIGHT: bold; COLOR: #000000">class</SPAN><SPAN style="COLOR: #009900">)</SPAN><SPAN style="COLOR: #339933">;</SPAN> AppWidgetManager manager <SPAN style="COLOR: #339933">=</SPAN> AppWidgetManager.<SPAN style="COLOR: #006633">getInstance</SPAN><SPAN style="COLOR: #009900">(</SPAN>context<SPAN style="COLOR: #009900">)</SPAN><SPAN style="COLOR: #339933">;</SPAN> Intent intent<SPAN style="COLOR: #339933">=</SPAN><SPAN style="FONT-WEIGHT: bold; COLOR: #000000">new</SPAN> Intent<SPAN style="COLOR: #009900">(</SPAN>context,Main.<SPAN style="FONT-WEIGHT: bold; COLOR: #000000">class</SPAN><SPAN style="COLOR: #009900">)</SPAN><SPAN style="COLOR: #339933">;</SPAN> Bundle extras<SPAN style="COLOR: #339933">=</SPAN><SPAN style="FONT-WEIGHT: bold; COLOR: #000000">new</SPAN> Bundle<SPAN style="COLOR: #009900">(</SPAN><SPAN style="COLOR: #009900">)</SPAN><SPAN style="COLOR: #339933">;</SPAN> extras.<SPAN style="COLOR: #006633">putInt</SPAN><SPAN style="COLOR: #009900">(</SPAN><SPAN style="COLOR: #0000ff">"appWidgetId"</SPAN>, appWidgetIds<SPAN style="COLOR: #009900">[</SPAN><SPAN style="COLOR: #cc66cc">0</SPAN><SPAN style="COLOR: #009900">]</SPAN><SPAN style="COLOR: #009900">)</SPAN><SPAN style="COLOR: #339933">;</SPAN> intent.<SPAN style="COLOR: #006633">putExtras</SPAN><SPAN style="COLOR: #009900">(</SPAN>extras<SPAN style="COLOR: #009900">)</SPAN><SPAN style="COLOR: #339933">;</SPAN> PendingIntent pendingIntent<SPAN style="COLOR: #339933">=</SPAN>PendingIntent.<SPAN style="COLOR: #006633">getActivity</SPAN><SPAN style="COLOR: #009900">(</SPAN>context,<SPAN style="COLOR: #cc66cc">0</SPAN>, intent,PendingIntent.0<SPAN style="COLOR: #009900">)</SPAN><SPAN style="COLOR: #339933">;</SPAN> updateViews.<SPAN style="COLOR: #006633">setOnClickPendingIntent</SPAN><SPAN style="COLOR: #009900">(</SPAN>R.<SPAN style="COLOR: #006633">id</SPAN>.<SPAN style="COLOR: #006633">abs</SPAN>,pendingIntent<SPAN style="COLOR: #009900">)</SPAN><SPAN style="COLOR: #339933">;</SPAN> manager.<SPAN style="COLOR: #006633">updateAppWidget</SPAN><SPAN style="COLOR: #009900">(</SPAN>thisWidget, updateViews<SPAN style="COLOR: #009900">)</SPAN><SPAN style="COLOR: #339933">;</SPAN>

RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.widget); ComponentName thisWidget = new ComponentName(context,Widget.class); AppWidgetManager manager = AppWidgetManager.getInstance(context); Intent intent=new Intent(context,Main.class); Bundle extras=new Bundle(); extras.putInt("appWidgetId", appWidgetIds[0]); intent.putExtras(extras); PendingIntent pendingIntent=PendingIntent.getActivity(context,0, intent,PendingIntent.0); updateViews.setOnClickPendingIntent(R.id.abs,pendingIntent); manager.updateAppWidget(thisWidget, updateViews);
网上的例子代码基本上是这样的,但是如果在启动的Activity接收Intent过来的数据,你会发现得到的Bundle其实是空的,也就是说,根本没有数据传过来。

这里我们需要改一下第8行代码,getActivity方法的最后一个参数是int flag,根据官方开发指南,这个值可以是FLAG_ONE_SHOT, FLAG_NO_CREATE, FLAG_CANCEL_CURRENT, FLAG_UPDATE_CURRENT

简单翻译一下:

int FLAG_CANCEL_CURRENT:如果该PendingIntent已经存在,则在生成新的之前取消当前的。

int FLAG_NO_CREATE:如果该PendingIntent不存在,直接返回null而不是创建一个PendingIntent.

int FLAG_ONE_SHOT:该PendingIntent只能用一次,在send()方法执行后,自动取消。

int FLAG_UPDATE_CURRENT:如果该PendingIntent已经存在,则用新传入的Intent更新当前的数据。

我们需要把最后一个参数改为PendingIntent.FLAG_UPDATE_CURRENT,这样在启动的Activity里就可以用接收Intent传送数据的方法正常接收。

AppWidget开发中主屏幕多个Widget,PendingIntent的处理(只能取到最后一个PendingIntent)

前面说到PendingIntent传送数据丢失解决办法,但是如果主屏幕上有多个Widget,而PendingIntent在不同的Widget有不同的Bundle参数时,你会发现,不管在哪个Widget上点击,启动的Activity或者Service接收到的参数都是最后一个Widget的,后面在添加PendingIntent时,把前面的PendingIntent也替换了。

其实解决方法很简单,还是如前文一样,修改getActivity方法的参数,不过这次改的是第二个参数,

1

[java]
view plaincopyprint?

PendingIntent pendingIntent<SPAN style="COLOR: #339933">=</SPAN>PendingIntent.<SPAN style="COLOR: #006633">getActivity</SPAN><SPAN style="COLOR: #009900">(</SPAN>context,<SPAN style="COLOR: #cc66cc">0</SPAN>, intent,PendingIntent.<SPAN style="COLOR: #006633">FLAG_UPDATE_CURRENT</SPAN><SPAN style="COLOR: #009900">)</SPAN><SPAN style="COLOR: #339933">;</SPAN>

PendingIntent pendingIntent=PendingIntent.getActivity(context,0, intent,PendingIntent.FLAG_UPDATE_CURRENT);
如上面的代码,第二个参数是固定的0,Android开发文档里称为request Code,英文原文为”Private request code for the sender”,直译为发送器的私有请求代码。其实这个int值就相当于PendingIntent的一个ID,PendingIntent会根据这个ID来查看是否已存在该PendingIntent,然后根据第四个参数来作相应的操作,关于第四个参数的含义,请参考PendingIntent传送数据丢失解决办法一文。

如果在生成PendingIntent时,第二个参数相同,那么就相当于在原来的PendingIntent上修改,我们看到的当然是最后一次修改的结果。所以解决方法就是把第二个参数设为一个动态的值,这里最好的办法就是设为appWidgetId,每个Widget都有一个唯一的ID,不会重复。

发现一个奇怪的问题,在我自己的程序中,是用一个for循环来循环绑定PendingIntent的,同时循环里还有一个线程来处理耗时操作。按上面的修改,我发现如果把绑定PendingIntent的代码放在循环体内,Thread外,上面的修改无效,但是如果放在Thread内,就有效了,暂时不知道原因,如有知道的同学希望留言说一声。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: