Android4.0中AppWidget的一些新玩意体验---RemoteViewsService

最近要把之前做的2.3上面的一些程序移植到4.0上面来,  几乎所有的AppWidget都是我一手操办, 所以这个玩意都是我弄.

我把Android2.3的代码直接拷到4.0的环境下面, 编译然后Push,  直接可以跑, 这是木有问题的.  但是我发现4.0上面有一些新东东是之前2.3上面没有的,

我也读了下官方的文档, 做了些demo, 这里总结给大家, 在以后需要做AppWidget的时候可以得心应手.

1: 应用列表中的预览图

如果你不想你的Widget在应用列表里面显示成那个丑机器人图片的话, 就需要在<appwidget-provider>中设置previewImage属性,例如:

[html] view plaincopy
 
  1. <appwidget-provider   
  2.     android:previewImage="@drawable/widget_preview"  
  3. />  


2. Widget可以resize

这个我先没注意到, 玩开发板的时候不小心把系统中带的日历的Widget拖出来,想删没有删掉, 发现边上出来一圈蓝边,于是乎想到是不是可以resize大小呢.?结果一试还真是可以,就翻日历源码的Widget和相应的xml文件,发现在<appwidget-provider>中设置了resizeMode属性, 可以设置让用户横向拉, 纵向拉.  设置minResizeWidth和minResizeHeight可以根据需要指定每次缩放的大小(一般设成一格宽, 当然对于集合来说这个要根据你Widget每个元素的大小,一般遵循的规则是拉伸大小为Widget里面每个元素的大小. 例如我看到BookMarket,他的每个元素是占一行两列,所以此时你设置拉伸大小就要注意了, 最好也设置成每次横向两列, 纵向一行就行了 ).   例如

[java] view plaincopy
 
  1. <!--需要两个方向都可以拉的话,就把他们或起来,android里面很多都是这么做的 -->  
  2. <appwidget-provider  
  3.   android:resizeMode="horizontal|vertical"  
  4.   android:minResizeWidth="146dip"  
  5.   android:minResizeHeight="72dip"  
  6. />  

以上72和146是怎么计算出来的这个不深说了, 文档上是这么说得.

3.支持很多集合控件

这个事非常让我兴奋的阿, 以前看到我Htc的机子上面Widget有集合控件,支持手势, 但是如果不定制RemoteViews是没办法实现的.

Gallery2中的Widget就是拿StackView去做的.  于是我参照了下Gallery2的源码和官方文档,了解了Widget中使用集合控件的方法.

集合是通过一个RemoteViewService去做的, 然后要创建一个RemoteViewsFactory, 这个接口里面的一些方法下面我会一一解释.

不多说.直接上我写的demo的代码,拿ListView做的,其他集合控件都差不多的使用.

widget_provider.xml

[html] view plaincopy
 
  1. <?xml version="1.0" encoding="utf-8" ?>   
  2.   <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"   
  3.         android:minHeight="220dip"   
  4.         android:minWidth="220dip"   
  5.         android:updatePeriodMillis="0"   
  6.         android:initialLayout="@layout/main" />   


main.xml

[html] view plaincopy
 
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:orientation="vertical" >  
  6.     <ListView  
  7.        android:layout_width="fill_parent"  
  8.        android:layout_height="fill_parent"   
  9.        android:id="@+id/list_data"  
  10.          />  
  11.       
  12.       
  13. </LinearLayout>  

list_item.xml

[java] view plaincopy
 
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:orientation="horizontal"  
  6.     android:id="@+id/item_layout" >  
  7.     <TextView   
  8.         android:layout_width="wrap_content"  
  9.         android:layout_height="match_parent"  
  10.         android:id="@+id/tv_key"  
  11.         android:textSize="24dip"/>  
  12.     <TextView   
  13.         android:layout_width="match_parent"  
  14.         android:layout_height="match_parent"  
  15.         android:id="@+id/tv_value"  
  16.         android:textSize="24dip"  
  17.         android:gravity="right"/>  
  18. </LinearLayout>  



ListViewService.java

[java] view plaincopy
 
  1. package cn.xuhui.pro;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import android.content.Context;  
  7. import android.content.Intent;  
  8. import android.widget.RemoteViews;  
  9. import android.widget.RemoteViewsService;  
  10.   
  11. public class ListViewService extends RemoteViewsService {  
  12.   
  13.     @Override  
  14.     public RemoteViewsFactory onGetViewFactory(Intent intent) {  
  15.         //这里很简单的给ListView一个List就好了  
  16.         List<String> list = new ArrayList<String>();  
  17.         for(int i = 1; i <= 30; i++) {  
  18.             list.add(i + "," + i);  
  19.         }         
  20.           
  21.         return new ListRemoteViewsFactory(this, list);  
  22.     }  
  23.       
  24.     private static class ListRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {  
  25.         private List<String> mList;  
  26.         private Context mContext;  
  27.           
  28.         //构造ListRemoteViewsFactory  
  29.         public ListRemoteViewsFactory(Context context, List<String> list) {  
  30.             mList = list;  
  31.             mContext = context;  
  32.         }  
  33.           
  34.           
  35.         @Override  
  36.         public int getCount() {  
  37.             //返回count  
  38.             return mList.size();  
  39.         }  
  40.   
  41.         @Override  
  42.         public long getItemId(int position) {  
  43.             //类似Adapter里面的getItemId,不用处理,一般直接返回就够了  
  44.             return position;  
  45.         }  
  46.   
  47.         @Override  
  48.         public RemoteViews getLoadingView() {  
  49.             //when ListView is scrolled, the loading view is not necessary  
  50.             //如果是StackView之类需要显示图片什么的,滑动的时候免得用户看到白板,就设置个Loading的View  
  51.             return null;  
  52.         }  
  53.   
  54.         @Override  
  55.         public RemoteViews getViewAt(int position) {  
  56.                         //这个方法相当于返回ListView的一个Item(类似Adapter里面的getView/getItem吧)  
  57.                         RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.list_item);  
  58.             String[] entry = mList.get(position).split(",");  
  59.             rv.setTextViewText(R.id.tv_key, entry[0]);  
  60.             rv.setTextViewText(R.id.tv_value, entry[1]);  
  61.                         Intent fillInIntent = new Intent(mContext, WidgetClickHandlerService.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  
  62.             fillInIntent.putExtra("clicked_item", mList.get(position));  
  63.             //记住,这里是不可以用setOnClickPendingIntent的,官方API上有说, PendingIntent对于CollectionViews是无效的.  
  64.                         rv.setOnClickFillInIntent(R.id.item_layout, fillInIntent);  
  65.             return rv;  
  66.         }  
  67.   
  68.         @Override  
  69.         public int getViewTypeCount() {  
  70.             //视图种类, 如果我们的集合里面就只有一种视图,那么返回1.附上官方的api doc  
  71.             /* 
  72.             Returns the number of types of Views that will be created by getView(int, View, ViewGroup).  
  73.             Each type represents a set of views that can be converted in getView(int, View, ViewGroup).  
  74.             If the adapter always returns the same type of View for all items, this method should return 1 
  75.             */  
  76.             return 1;  
  77.         }  
  78.   
  79.         @Override  
  80.         public boolean hasStableIds() {  
  81.             //return True if the same id always refers to the same object.  
  82.             //如果返回true, 同一个id总是指向同一个对象  
  83.             return true;  
  84.         }  
  85.   
  86.         @Override  
  87.         public void onCreate() {  
  88.             // TODO ready for data source  
  89.             //这个方法一般是准备或者处理数据源的,这里不做处理. 可以参看Gallery2的  
  90.         }  
  91.   
  92.         @Override  
  93.         public void onDataSetChanged() {  
  94.             // TODO demo only , no dataSet change, 可以参看Gallery2的  
  95.         }  
  96.   
  97.         @Override  
  98.         public void onDestroy() {  
  99.             mList.clear();  
  100.             mList = null;  
  101.         }  
  102.     }  
  103.   
  104. }  


我们点击ListView的Item时就用一个服务简单弹一个Toast就可以了

WidgetClickHandlerService .java

[java] view plaincopy
 
  1. package cn.xuhui.pro;  
  2.   
  3. import android.app.Service;  
  4. import android.content.Intent;  
  5. import android.os.IBinder;  
  6. import android.widget.Toast;  
  7.   
  8. public class WidgetClickHandlerService extends Service {  
  9.   
  10.     @Override  
  11.     public IBinder onBind(Intent intent) {  
  12.         return null;  
  13.     }  
  14.       
  15.     @Override  
  16.     public void onStart(Intent intent, int startId) {  
  17.         super.onStart(intent, startId);  
  18.         String data = intent.getStringExtra("clicked_item");  
  19.         Toast.makeText(this, data, Toast.LENGTH_LONG).show();  
  20.     }  
  21.   
  22. }  


MyAppWidgetProvider.java

[java] view plaincopy
 
  1. package cn.xuhui.pro;  
  2.   
  3.   
  4. import android.app.PendingIntent;  
  5. import android.appwidget.AppWidgetManager;  
  6. import android.appwidget.AppWidgetProvider;  
  7. import android.content.ComponentName;  
  8. import android.content.Context;  
  9. import android.content.Intent;  
  10. import android.widget.RemoteViews;  
  11.   
  12. public class MyAppWidgetProvider extends AppWidgetProvider {  
  13.     @Override  
  14.     public void onUpdate(Context context, AppWidgetManager appWidgetManager,  
  15.             int[] appWidgetIds) {  
  16.         RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.main);  
  17.         Intent intent = new Intent(context, ListViewService.class);  
  18.         rv.setRemoteAdapter(R.id.list_data, intent);  
  19.         //注意,下面这段代码不能少,否则点击没有效果  
  20.                 Intent clickIntent = new Intent(context, WidgetClickHandlerService.class);  
  21.                 PendingIntent pendingIntent = PendingIntent.getService(  
  22.                 context, 0, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT);  
  23.         rv.setPendingIntentTemplate(R.id.list_data, pendingIntent);  
  24.         appWidgetManager.updateAppWidget(new ComponentName(context, MyAppWidgetProvider.class), rv);  
  25.     }  
  26. }  


最后AndroidManifest.xml

[html] view plaincopy
 
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="cn.xuhui.pro"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >  
  6.   
  7.     <uses-sdk android:minSdkVersion="15" />  
  8.   
  9.     <application  
  10.         android:icon="@drawable/ic_launcher"  
  11.         android:label="@string/app_name" >  
  12.         <!--这里必须加上这个权限, 否则报错 -->  
  13.         <service   
  14.             android:name=".ListViewService"  
  15.             android:permission="android.permission.BIND_REMOTEVIEWS"  
  16.             />  
  17.           
  18.         <service   
  19.             android:name=".WidgetClickHandlerService"  
  20.             />  
  21.           
  22.         <receiver android:name=".MyAppWidgetProvider"  
  23.             android:label="xh_demo">  
  24.             <intent-filter>  
  25.                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>  
  26.             </intent-filter>  
  27.             <meta-data android:name="android.appwidget.provider"  
  28.                     android:resource="@xml/widget_provider" />  
  29.         </receiver>  
  30.     </application>  
  31.   
  32. </manifest>  


好了, 今天就总结到这里, 以后有时间再来研究一些Widget的东西吧

原文:http://blog.csdn.net/izard999/article/details/7444457

原文地址:https://www.cnblogs.com/veins/p/3834455.html