一个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();
}
}
}
效果如图。
网上的例子代码基本上是这样的,但是如果在启动的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方法的参数,不过这次改的是第二个参数,
如上面的代码,第二个参数是固定的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内,就有效了,暂时不知道原因,如有知道的同学希望留言说一声。
原来如此简单,只是我原来不会罢了。
首先在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); |
这里我们需要改一下第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); |
如果在生成PendingIntent时,第二个参数相同,那么就相当于在原来的PendingIntent上修改,我们看到的当然是最后一次修改的结果。所以解决方法就是把第二个参数设为一个动态的值,这里最好的办法就是设为appWidgetId,每个Widget都有一个唯一的ID,不会重复。
发现一个奇怪的问题,在我自己的程序中,是用一个for循环来循环绑定PendingIntent的,同时循环里还有一个线程来处理耗时操作。按上面的修改,我发现如果把绑定PendingIntent的代码放在循环体内,Thread外,上面的修改无效,但是如果放在Thread内,就有效了,暂时不知道原因,如有知道的同学希望留言说一声。
相关文章推荐
- 一个android应用向Home screen添加多个Widget
- Google Android开发者文档系列-创建有内容分享特性的应用之添加一个简单的共享action
- android 给应用添加一个快捷方式
- 用JAVA代码为android应用添加一个按钮
- 项目中添加 android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"应用崩溃
- 一个android应用效果开发引发的惨案(android Home按键) 推荐
- [绍棠] 通过主屏幕的应用Icon,用3D Touch呼出一个菜单 (Home Screen Quick Actions)
- 如何让appwidget开机后自动添加到Home Screen上
- 在HomeScreen上添加指定应用图标
- Android项目实战--手机卫士32--给清理进程添加一个Widget
- Android一个应用中展示多个多种样式的Widget
- Android为应用在桌面添加一个快捷方式
- 【Xamarin开发 Android 系列 12】 创建一个Json读取数据应用-添加定位服务
- 【Xamarin开发 Android 系列 11】 创建一个Json读取数据应用-添加摄像头集成
- Android:如何把一个应用添加到Settings列表中...
- [实践] Android5.1.1源码 - 为每个应用添加一个Content Provider
- 一个android应用效果开发引发的惨案(android Home按键)
- Android 创建一个Widget
- android基础笔记:ContentValues应用(查询、添加手机联系人)
- Android 如何判断一个应用在运行