如Twitter客户端或者HTC的日历应用,可以添加大小不同的Widget。此疑问。
原来如此简单,只是我原来不会罢了。
首先在AndroidManifest.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文件内容如下:
- 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内容如下:
- 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 |
|
网上的例子代码基本上是这样的,但是如果在启动的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 |
|
如上面的代码,第二个参数是固定的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内,就有效了,暂时不知道原因,如有知道的同学希望留言说一声。