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

来源:互联网 发布:盗墓笔记重启豆瓣知乎 编辑:程序博客网 时间:2024/05/17 12:51

如Twitter客户端或者HTC的日历应用,可以添加大小不同的Widget。此疑问。

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

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

Xml代码  收藏代码
  1. <receiver android:name="com.jftt.widget.MyWidgetProvider1" android:label="天气 4 x 1">  
  2.     <meta-data android:name="android.appwidget.provider"  
  3.             android:resource="@xml/my_widget1" />  
  4.     <intent-filter>  
  5.         <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />    
  6.     </intent-filter>  
  7. </receiver>  
  8. <receiver android:name="com.jftt.widget.MyWidgetProvider" android:label="全部 4 x 2">  
  9.     <meta-data android:name="android.appwidget.provider"  
  10.             android:resource="@xml/my_widget" />  
  11.     <intent-filter>  
  12.         <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />    
  13.     </intent-filter>  
  14. </receiver>  
  15. <receiver android:name="com.jftt.widget.MyWidgetProvider2" android:label="步数 4 x 1">  
  16.     <meta-data android:name="android.appwidget.provider"  
  17.             android:resource="@xml/my_widget2" />  
  18.     <intent-filter>  
  19.         <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />    
  20.     </intent-filter>  
  21. </receiver>  

CreateWidget.java文件内容如下:

Java代码  收藏代码
  1. package com.jftt.activity;  
  2.   
  3. import android.app.Activity;  
  4. import android.appwidget.AppWidgetManager;  
  5. import android.content.Intent;  
  6. import android.os.Bundle;  
  7. import android.util.Log;  
  8.   
  9. import com.jftt.widget.R;  
  10.   
  11. public class CreateWidget extends Activity {  
  12.     private static final String TAG = "CreateWidget";  
  13.     int mAppWidgetId;  
  14.   
  15.     @Override  
  16.     protected void onCreate(Bundle savedInstanceState) {  
  17.         super.onCreate(savedInstanceState);  
  18.         Log.i(TAG, " on WidgetConf ... ");  
  19.           
  20.         setResult(RESULT_CANCELED);  
  21.         // Find the widget id from the intent.  
  22.         Intent intent = getIntent();  
  23.         Bundle extras = intent.getExtras();  
  24.         if (extras != null) {  
  25.             mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);  
  26.         }  
  27.   
  28.         // If they gave us an intent without the widget id, just bail.  
  29.         if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {  
  30.             finish();  
  31.         }  
  32.           
  33.         // return OK  
  34.         Intent resultValue = new Intent();  
  35.         resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);  
  36.           
  37.         setResult(RESULT_OK, resultValue);  
  38.         finish();  
  39.     }  
  40. }  

MyWidgetProvider.java内容如下:

Java代码  收藏代码
  1. package com.jftt.widget;  
  2.   
  3. import android.app.PendingIntent;  
  4. import android.appwidget.AppWidgetManager;  
  5. import android.appwidget.AppWidgetProvider;  
  6. import android.content.ComponentName;  
  7. import android.content.Context;  
  8. import android.content.Intent;  
  9. import android.content.pm.PackageManager;  
  10. import android.util.Log;  
  11. import android.view.View;  
  12. import android.widget.RemoteViews;  
  13.   
  14. import com.jftt.activity.WidgetSetting;  
  15.   
  16. public class MyWidgetProvider extends AppWidgetProvider {  
  17.     private static final String TAG = "MyWidgetProvider";  
  18.   
  19.     @Override  
  20.     public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {  
  21.         super.onUpdate(context, appWidgetManager, appWidgetIds);  
  22.         Log.i(TAG, "onUpdate");  
  23.         final int N = appWidgetIds.length;  
  24.         for (int i = 0; i < N; i++) {  
  25.             int appWidgetId = appWidgetIds[i];  
  26.             Log.i(TAG, "this is [" + appWidgetId + "] onUpdate!");  
  27.               
  28.             Intent intent = new Intent(context, WidgetSetting.class);  
  29.             PendingIntent pending = PendingIntent.getActivity(context, 0, intent, 0);  
  30.   
  31.             Intent intent2 = new Intent(context, MyWidgetProvider.class);  
  32.             intent2.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);  
  33.               
  34.             Log.i(TAG, "appWidgetId "+appWidgetId);  
  35.             PendingIntent doubleClick = PendingIntent.getBroadcast(context, appWidgetId, intent2, PendingIntent.FLAG_UPDATE_CURRENT);  
  36.               
  37.             RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);  
  38.             remoteViews.setOnClickPendingIntent(R.id.pic5, pending);  
  39.             remoteViews.setOnClickPendingIntent(R.id.widget, doubleClick);  
  40.             appWidgetManager.updateAppWidget(appWidgetId, remoteViews);  
  41.         }  
  42.     }  
  43.   
  44.     @Override  
  45.     public void onDeleted(Context context, int[] appWidgetIds) {  
  46.         super.onDeleted(context, appWidgetIds);  
  47.         Log.i(TAG, "onDeleted");  
  48.         final int N = appWidgetIds.length;  
  49.         for (int i = 0; i < N; i++) {  
  50.             int appWidgetId = appWidgetIds[i];  
  51.             Log.i(TAG, "this is [" + appWidgetId + "] onDelete!");  
  52.         }  
  53.     }  
  54.   
  55.     @Override  
  56.     public void onDisabled(Context context) {  
  57.         super.onDisabled(context);  
  58.         Log.i(TAG, "onDisabled");  
  59.         PackageManager pm = context.getPackageManager();  
  60.         pm.setComponentEnabledSetting(new ComponentName("com.jftt.widget""com.jftt.widget.MyWidgetProvider"), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);  
  61.     }  
  62.   
  63.     @Override  
  64.     public void onEnabled(Context context) {  
  65.         super.onEnabled(context);  
  66.         Log.i(TAG, "onEnabled");  
  67.         PackageManager pm = context.getPackageManager();  
  68.         pm.setComponentEnabledSetting(new ComponentName("com.jftt.widget""com.jftt.widget.MyWidgetProvider"), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);  
  69.     }  
  70.   
  71.     static long start = 0;  
  72.   
  73.     @Override  
  74.     public void onReceive(Context context, Intent intent) {  
  75.         super.onReceive(context, intent);  
  76.         if ((System.currentTimeMillis() - start) < 500) {  
  77.             AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);  
  78.             RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);  
  79.             remoteViews.setViewVisibility(R.id.setting, View.VISIBLE);  
  80.             int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 0);  
  81.             appWidgetManager.updateAppWidget(appWidgetId, remoteViews);  
  82.         } else {  
  83.             start = System.currentTimeMillis();  
  84.         }  
  85.     }  
  86. }  


 效果如图。



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

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

12345678910
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
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内,就有效了,暂时不知道原因,如有知道的同学希望留言说一声。



原创粉丝点击