android 中 AppWidget 的 ListView 的实现

http://www.cnblogs.com/debugman/archive/2012/06/18/android.html

3.0 以后系统直接支持了ListView. 关于ListView 的国内资料匮乏,大多数例子都是转来转去。由于初学android, 鄙人在搜索资料的时候遇到了不少麻烦~很是郁闷和苦恼~深感国内学习氛围确实怪异,学习方式需要改变。应该多去查看官方文档。。。。

话不多说,现在开始listView 实现:

这是文档列出的支持的布局和widget控件:

A RemoteViews object (and, consequently, an App Widget) can support the following layout classes:

And the following widget classes:

Descendants of these classes are not supported

其中有ListView和 GridView 等控件。

android 中实现 appWidget 有自己的一套机制:

1.  widget 的支持,AppWidgetProvider 类的实现。

覆盖在 AppWidgetProvider 的 OnReceive() 函数,从android的源码中可以知道,AppWidgetProvider 的 OnUpdate() , OnEnable(), OnDelete() 等方法都是从 OnReceive() 方法中分配进去的。即所有的广播先通过OnReceive()函数,再分配到OnUpdate()等函数去。

public  void  onReceive(Context context, Intent intent) {
     // Protect against rogue update broadcasts (not really a security issue,
     // just filter bad broacasts out so subclasses are less likely to crash).
     String action = intent.getAction();
     if  (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
         Bundle extras = intent.getExtras();
         if  (extras != null ) {
             int [] appWidgetIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);
             if  (appWidgetIds != null  && appWidgetIds.length > 0 ) {
                 this .onUpdate(context, AppWidgetManager.getInstance(context), appWidgetIds);
             }
         }
     }
     else  if  (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {
         Bundle extras = intent.getExtras();
         if  (extras != null  && extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_ID)) {
             final  int  appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);
             this .onDeleted(context, new  int [] { appWidgetId });
         }
     }
     else  if  (AppWidgetManager.ACTION_APPWIDGET_ENABLED.equals(action)) {
         this .onEnabled(context);
     }
     else  if  (AppWidgetManager.ACTION_APPWIDGET_DISABLED.equals(action)) {
         this .onDisabled(context);
     }
}
// END_INCLUDE(onReceive)

 

注意到:

String action = intent.getAction();

这里 intent 先获取 action, 通过action 来获取到广播并区分类型,所以自己定义 action 通过 PendingIntent 来实现各种跳转~

到这里先摆下基础的文件吧:

这里需要注意到的是:android中的xml 文件不能有大写字母。区分单词用最好用  _  符号。否则找不到文件名。

provider_info 文件,提供 appWidget 的一些基本控制信息。

<?xml version= "1.0"  encoding= "utf-8" ?>
<appwidget-provider
   android:minWidth = "294dp"
   android:minHeight = "367dp"
   android:updatePeriodMillis = "1000"
   android:initialLayout = "@layout/listview"
   android:background= "#0000ff"
   >
   
</appwidget-provider>

listview 文件: ListView 控件就在内部:

<?xml version= "1.0"  encoding= "utf-8" ?>
<RelativeLayout
   android:layout_width= "294dp"
   android:layout_height= "400dp" >
   <LinearLayout
     android:layout_width= "fill_parent"
     android:layout_height= "360dp"
     android:minHeight= "100dp"
     android:id= "@+id/listviewWrapper"
     >
       <ListView
         android:layout_height = "360dp"
         android:layout_width = "294dp"
         android:background= "#000000"
         android:id = "@+id/myListView"
       />
   </LinearLayout>
   <Button
     android:layout_width= "fill_parent"
     android:layout_height= "wrap_content"
     android:layout_below= "@id/listviewWrapper"
     
     android:layout_alignParentLeft= "true"
     android:id= "@+id/refresh"
     android:text= "refresh"
     >
   </Button>
</RelativeLayout>

下面是list_item 文件:

<?xml version= "1.0"  encoding= "utf-8" ?>
<RelativeLayout
   android:layout_width= "match_parent"
   android:layout_height= "match_parent" >
   <TextView
     android:layout_width= "fill_parent"
     android:layout_height= "wrap_content"
     android:gravity= "center"
     android:textColor= "#ff0000"
     android:layout_marginTop= "5px"
     android:layout_marginBottom= "5px"
     android:paddingBottom= "25px"
     android:paddingTop= "5px"
     android:textSize= "60px"
     android:id= "@+id/item"
   />
   <ImageView
     android:id= "@+id/imageItem"
     android:layout_width= "wrap_content"
     android:layout_height= "wrap_content"
     android:layout_alignParentRight= "true"
     android:layout_alignRight= "@id/item"
     />
</RelativeLayout>

 list 的 item 中也可以添加 ImageView 等appWidget 支持的控件。

这是manifest 问件:

<?xml version= "1.0"  encoding= "utf-8" ?>
<manifest xmlns:android= "http://schemas.android.com/apk/res/android"
     package = "com.zgc.AppWidget6"
     android:versionCode= "1"
     android:versionName= "1.0"  >
 
     <uses-sdk android:minSdkVersion= "15"  />
 
     <application
         android:icon= "@drawable/ic_launcher"
         android:label= "@string/app_name"  >
         <receiver android:name= ".MyWidgetProvider" >
             <meta-data android:name= "android.appwidget.provider"
                 android:resource= "@xml/provider_info"  >
             </meta-data>
             <intent-filter >
                 <action android:name= "android.appwidget.action.APPWIDGET_UPDATE" ></action>   
             </intent-filter>
         </receiver>
         
         <service android:name= ".MyWidgetService"
             android:permission= "android.permission.BIND_REMOTEVIEWS"
             android:exported= "false"  ></service>
         
      </application>
      
     <uses-permission android:name= "android.permission.INTERNET" ></uses-permission>
</manifest>

其中 service 提供 name 是 MyWidgetService ,他是继承RemoteViewsService 类。是我们需要为 远程 ListView 提供 数据源的服务。

RemoteViewsService的是个服务。其中:

public  RemoteViewsFactory onGetViewFactory(Intent intent) {
       return  new  ListRemoteViewsFactory( this .getApplicationContext(), intent);
   }
ListRemoteViewsFactory 这里就充当 ListView 的数据源。

就好比在activity 中使用ListView 一样。也需要通过AdapterView 来为ListView 提供数据源。不过AdatperView中提供了每一Item的方法。

具体逻辑如图:

    

 

下面是 service 的源代码:

public  class  MyWidgetService  extends  RemoteViewsService {
     @Override
     public  RemoteViewsFactory onGetViewFactory(Intent intent) {
         return  new  ListRemoteViewsFactory( this .getApplicationContext(), intent);
     }
 
     @Override
     public  void  onCreate() {
         // TODO Auto-generated method stub
         System.out.println( "service in onCreate" );
         super .onCreate();
     }
     
     @Override
     public  void  onDestroy() {
         // TODO Auto-generated method stub
         System.out.println( "service in onDestory" );
         super .onDestroy();
     }
 
     @Override
     public  boolean  onUnbind(Intent intent) {
         // TODO Auto-generated method stub
         System.out.println( "service in onUnbind" );
         return  super .onUnbind(intent);
     }
 
     @Override
     public  void  onRebind(Intent intent) {
         // TODO Auto-generated method stub
         System.out.println( "service in onRebind" );
         super .onRebind(intent);
     }
 
     @Override
     public  void  onStart(Intent intent, int  startId) {
         // TODO Auto-generated method stub
         System.out.println( "service in onStart" );
         super .onStart(intent, startId);
     }
 
     @Override
     public  int  onStartCommand(Intent intent, int  flags, int  startId) {
         // TODO Auto-generated method stub
         return  super .onStartCommand(intent, flags, startId);
     }
}<br><br>
class  ListRemoteViewsFactory implements  RemoteViewsService.RemoteViewsFactory {
     
     private  static  int  mCount = 0 ;
     private  List<WidgetItem> mWidgetItems = new  ArrayList<WidgetItem>();
     private  List<String> mWidgetItemsAttr= new  ArrayList<String>();
     private  Context mContext;
     private  int  mAppWidgetId;
     private  String url = "http://10.40.73.77/php/getData.php" ;
     
     public  static  int  whichPage = 0 ;
     public  static  int  mainPageId = - 1 ;
     public  static  int  secPageId = - 1 ;
     public  static  final  int  mainPage = 0 ;
     public  static  final  int  secPage = 1 ;
     public  static  List<Integer> checkPos = new  ArrayList<Integer>();
     //public static int[] checkPosArr = new int[100];
     
     
     public  ListRemoteViewsFactory(Context context, Intent intent){
         mContext = context;
         mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                 AppWidgetManager.INVALID_APPWIDGET_ID);
     }
     
     @Override
     public  void  onCreate() {
         System.out.println( "onCreate in factory" );
         // TODO Auto-generated method stub
         try  {
             Thread.sleep( 3000 );
         } catch  (InterruptedException e) {
             e.printStackTrace();
         }
     }
 
     @Override
     public  int  getCount() {
         // TODO Auto-generated method stub
         if (whichPage == mainPage){
             mCount = mWidgetItems.size();
         }
         else  if (whichPage == secPage){
             mCount = mWidgetItemsAttr.size();
         }
         
         return  mCount;
     }
 
     @Override
     public  long  getItemId( int  position) {
         // TODO Auto-generated method stub
         return  position;
     }
 
     @Override
     public  RemoteViews getLoadingView() {
         // TODO Auto-generated method stub
         System.out.println( "getLoadingView" );
         return  null ;
     }
 
     @Override
     public  RemoteViews getViewAt( int  position) {
         System.out.println( "getViewAt" );
         // TODO Auto-generated method stub
         RemoteViews rv = new  RemoteViews(mContext.getPackageName(), R.layout.list_item);
         switch (whichPage){
         case  mainPage :
             if (- 1  == mainPageId){ //refresh main page
                 System.out.println( "getViewAt mainPage refresh" );
                 
                 rv.setTextViewText(R.id.item, mWidgetItems.get(position).text);
                 Bundle extras = new  Bundle();
                 extras.putInt( "page" , 0 );
                 extras.putInt(MyWidgetProvider.EXTRA_ITEM, position);
                 extras.putString( "name" , mWidgetItems.get(position).text);
                 Intent fillInIntent = new  Intent();
             fillInIntent.putExtras(extras);
             rv.setOnClickFillInIntent(R.id.item, fillInIntent);
             }
             else { //refresh to secPage list content
                 System.out.println( "getViewAt mainPage item click" );
                 
                 mainPageId = - 1 ;
             }
             break ;
             
         case  secPage:
             if (- 1  == secPageId){ //refresh when click back button, but I only have one home button
                 //refresh second list page
                 System.out.println( "getViewAt secPage refresh" );
                 
                 rv.setTextViewText(R.id.item, mWidgetItemsAttr.get(position));
                 rv.setImageViewResource(R.id.imageItem, R.drawable.checkbox);
                 
                 Bundle extras = new  Bundle();
                 extras.putInt( "page" , 1 );
                 extras.putInt(MyWidgetProvider.EXTRA_ITEM, position);
                 Intent fillInIntent = new  Intent();
                 fillInIntent.putExtras(extras);
                 rv.setOnClickFillInIntent(R.id.item, fillInIntent);
                 rv.setOnClickFillInIntent(R.id.imageItem, fillInIntent);
             }
             else { //change positon
                 rv.setTextViewText(R.id.item, mWidgetItemsAttr.get(position));
                 
                 if (- 1  != checkPos.indexOf(position)){
                     //change list item picture to be checked
                     rv.setImageViewResource(R.id.imageItem, R.drawable.checkedbox);
                 }
                 else {
                     rv.setImageViewResource(R.id.imageItem, R.drawable.checkbox);
                 }
                 
                 //每一个 item 都需要从新赋值。否则会出错!!具体原因没有查明
                 Bundle extras = new  Bundle();
                 extras.putInt( "page" , 1 );
                 extras.putInt(MyWidgetProvider.EXTRA_ITEM, position);
                 Intent fillInIntent = new  Intent();
                 fillInIntent.putExtras(extras);
                 rv.setOnClickFillInIntent(R.id.item, fillInIntent);
                 rv.setOnClickFillInIntent(R.id.imageItem, fillInIntent);
             }
             break ;
             default : ;
         }
         
         return  rv;
     }
 
     @Override
     public  int  getViewTypeCount() {
         // TODO Auto-generated method stub
         return  1 ;
     }
 
     @Override
     public  boolean  hasStableIds() {
         // TODO Auto-generated method stub
         return  true ;
     }
 
 
     @Override
     public  void  onDataSetChanged() {
         // TODO Auto-generated method stub
         System.out.println( "onDataSetChanged" );
 
             //this func is get data
         mWidgetItems.clear();
         
         
         switch (whichPage){
         case  mainPage :
             System.out.println( "onDataSetChanged_mainPage" );
             if (- 1  == mainPageId){ //refresh main page
                 
                 try {
                     URL reqURL = new  URL(url);
                     BufferedReader br = new  BufferedReader( new  InputStreamReader(reqURL.openStream(), "gbk" ));
                     StringBuffer sb = new  StringBuffer();
                     String line;
                     while ( null  != (line = br.readLine())){
                         sb.append(line);
                     }  
                     br.close();
             
                     ArrayList <Map<String, Object>> mList= new  ArrayList<Map<String, Object>>();
                        
                     JSONArray arr_json = new  JSONArray(sb.toString());
                     for ( int  i = 0 , len = arr_json.length(); i < len; i++){
                            String strName = arr_json.getJSONObject(i).getString( "name" );
                            String strUrl = arr_json.getJSONObject(i).getString( "url" );
                            int  id = arr_json.getJSONObject(i).getInt( "id" );
                            
                            Map<String, Object> map = new  HashMap<String, Object>();
                            
                            mWidgetItems.add( new  WidgetItem(strName, id));
                            
                            map.put( "name" , strName);
                            map.put( "url" , strUrl);
                            mList.add(map);            
                     }
                         
                             mCount = mWidgetItems.size();
                     } catch (Exception e){
                         Toast.makeText(mContext, "can't connect server" , Toast.LENGTH_LONG).show();
                     }
             }
             else { //
                 System.out.println( "onDataSetChanged_mainPage else" );
                 
                 WidgetItem item = mWidgetItems.get(mainPageId);
                 
             }
             
             System.out.println( "onDataSetChanged_-1" );
             break ;
             
         case  secPage: //here can get more info from server, but no need to get more infomation, 
             if (- 1  == secPageId){
                 mWidgetItemsAttr.clear();
                 
                 System.out.println( "onDataSetChanged_secPage -1" );
                 mWidgetItemsAttr.add( "zhang" );
                 mWidgetItemsAttr.add( "gui" );
                 mWidgetItemsAttr.add( "chuang" );
                 mWidgetItemsAttr.add( "hui" );
                 mWidgetItemsAttr.add( "cong" );
                 mWidgetItemsAttr.add( "gui" );
                 mWidgetItemsAttr.add( "chuang" );
                 mWidgetItemsAttr.add( "hui" );
                 mWidgetItemsAttr.add( "cong" );
                 mWidgetItemsAttr.add( "gui" );
                 mWidgetItemsAttr.add( "chuang" );
                 mWidgetItemsAttr.add( "hui" );
                 mWidgetItemsAttr.add( "cong" );
                 mWidgetItemsAttr.add( "cong" );
             }
             else {
                 System.out.println( "onDataSetChanged_secPage else" );
             }
             break ;
             
             default : return  ;
         }
         
 
         
     }
 
     @Override
     public  void  onDestroy() {
         System.out.println( "onDestory in factory" );
         // TODO Auto-generated method stub
         mWidgetItems.clear();  
     }
 
}

  

<br>
<br>注意到几个方法:<br> public  void  onDataSetChanged(){.....}<br> public  RemoteViews getViewAt( int  position) {....}<br> public  int  getCount() {....}<br><br>onDateSetChanged(){...} 方法在你使用的 MyWidgetProvider 的 onReceive() 和 onUpdate() 方法中调用
AppWidgetManager 的实例的方法: mgr.notifyAppWidgetViewDataChanged(appIds, R.id.myListView); 来更新要求更新数据源:<br>首先就会调用 :
onDataSetChanged(){.....}
然后在调用 getViewAt( int  position){....}<br>其中getViewAt 的参数 position 就是你的ListView中每一项 item 的位置。从 0  计数。<br>其中你必须 override 的 getCount()方法是返回你的ListView item 的总数。这个自己必须返回自己的数据才能让getViewAt的postion能够计数。<br><br>你获取数据的方式比如http从服务器获取数据的话,就需要放在onDateSetChagged()方法里。<br>当然 public  RemoteViews getLoadingView(){...} 也可以。不过要注意放回的是RemoteViews 就说明这是要更新界面的,这个函数的作用就是在你更新界面的时候如果耗时就会显示 正在加载... 的默认字样,但是你可以更改这个界面。需要返回一个 RemoteViews 类型。其中你可以使用RemoteViews 去切换自己定义的 Layout 。<br><br>关于 remoteViews 的实例的方法:
rv.setOnClickFillInIntent(R.id.item, fillInIntent);
在下面会解释。<br><br><br>下面是provider:
public  class  MyWidgetProvider extends  AppWidgetProvider{
     public  static  final  String TOAST_ACTION = "com.zgc.listwidget.TOAST_ACTION" ;
     public  static  final  String EXTRA_ITEM = "com.zgc.listwidget.EXTRA_ITEM" ;
     public  static  final  String TO_SITE = "com.zgc.listwidget.TO_SITE" ;
     public  static  final  String SITE = "com.zgc.listwidget.SITE" ;
     public  static  final  String BACK_HOME = "com.zgc.listwidget.BACK_HOME" ;
     public  static  String PicName = "" ;
     public  static  final  String REFRESH = "com.zgc.listwidget.REFRESH" ;
     
     public  static  final  String ITEM = "com.zgc.AppWidget6.ITEM" ;
     
     
 
     @Override
     public  IBinder peekService(Context myContext, Intent service) {
         // TODO Auto-generated method stub
         System.out.println( "peekService in provider" );
         return  super .peekService(myContext, service);
     }
 
     @Override
     public  void  onDeleted(Context context, int [] appWidgetIds) {
         // TODO Auto-generated method stub
         System.out.println( "onDeleted in Provider" );
         super .onDeleted(context, appWidgetIds);
     }
 
     @Override
     public  void  onDisabled(Context context) {
         // TODO Auto-generated method stub
         System.out.println( "onDisabled in Provider" );
         super .onDisabled(context);
     }
 
     @Override
     public  void  onEnabled(Context context) {
         // TODO Auto-generated method stub
         System.out.println( "onEnabled in Provider" );
         super .onEnabled(context);
     }
 
     @Override
     public  void  onReceive(Context context, Intent intent) {
         // TODO Auto-generated method stub
         AppWidgetManager mgr = AppWidgetManager.getInstance(context);
         ComponentName cmpName = new  ComponentName(context, MyWidgetProvider. class );
         
         if  (intent.getAction().equals(ITEM)) {
             System.out.println( "item action" );
             int  pageNum = intent.getIntExtra( "page" , 1 );
             int  itemPos = intent.getIntExtra(EXTRA_ITEM, 0 );
             if ( 0  == pageNum){
                 System.out.println( "item action 0 page" );
                 ListRemoteViewsFactory.secPageId = - 1 ;
                 ListRemoteViewsFactory.whichPage = ListRemoteViewsFactory.secPage;
                 
                 int [] appIds = mgr.getAppWidgetIds(cmpName);
                 mgr.notifyAppWidgetViewDataChanged(appIds, R.id.myListView);
                 
                 //change refresh to commit button ,here no need to reload listview
                 RemoteViews rv2 = new  RemoteViews(context.getPackageName(), R.layout.listview);
                 rv2.setTextViewText(R.id.refresh, "commit" );
                 Intent commitIntent = new  Intent(context, MyWidgetProvider. class );
                 commitIntent.setData(Uri.parse(commitIntent.toUri(Intent.URI_INTENT_SCHEME)));
                 commitIntent.setAction(SITE);
                 PendingIntent commitPendingIntent = PendingIntent.getBroadcast(context, 0 ,
                         commitIntent, PendingIntent.FLAG_UPDATE_CURRENT);
                 rv2.setOnClickPendingIntent(R.id.refresh, commitPendingIntent);
                 
                 mgr.updateAppWidget(appIds, rv2);
                 
             }
             else  if ( 1  == pageNum){
                 System.out.println( "item action 1 page" );
                 ListRemoteViewsFactory.secPageId = itemPos;
                 
                 if (- 1  == ListRemoteViewsFactory.checkPos.indexOf(itemPos)){
                     ListRemoteViewsFactory.checkPos.add(itemPos);
                 }
                 else {
                     ListRemoteViewsFactory.checkPos.remove(ListRemoteViewsFactory.checkPos.indexOf(itemPos));
                 }
 
                 int [] appIds = mgr.getAppWidgetIds(cmpName);
                 mgr.notifyAppWidgetViewDataChanged(appIds, R.id.myListView);
             }
 
         }
         else  if (intent.getAction().equals(SITE)){
             System.out.println( "in receive commit SITE action" );
             RemoteViews rv = new  RemoteViews(context.getPackageName(), R.layout.img);
             int  id = R.drawable.uliuli;
             if (PicName.equals( "google" )){
                 id = R.drawable.uliuli;
             }
             else  if (PicName.equals( "douban" )){
                 id = R.drawable.uliuli;
             }
             rv.setImageViewResource(R.id.displayImage, id);
             
             Intent homeIntent = new  Intent(context, MyWidgetProvider. class );
             homeIntent.setAction(BACK_HOME);
             //homeIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
             homeIntent.setData(Uri.parse(homeIntent.toUri(Intent.URI_INTENT_SCHEME)));
             PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0 , homeIntent,
                     PendingIntent.FLAG_UPDATE_CURRENT);
             rv.setOnClickPendingIntent(R.id.backHome, pendingIntent);
             
             mgr.updateAppWidget(cmpName, rv);
             //Toast.makeText(context, "Touched view zhang", Toast.LENGTH_SHORT).show();
         }
         else  if (intent.getAction().equals(BACK_HOME)){
             System.out.println( "back_home " );
        
             int [] appWidgetIds = mgr.getAppWidgetIds(cmpName);
             
             //mgr.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.myListView);
                 
             Intent serviceIntent = new  Intent(context, MyWidgetService. class );  //
             //intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
             serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME)));
             RemoteViews rv = new  RemoteViews(context.getPackageName(), R.layout.listview);
             rv.setRemoteAdapter(R.id.myListView, serviceIntent);
                 
             Intent toastIntent = new  Intent(context, MyWidgetProvider. class );
             toastIntent.setAction(MyWidgetProvider.ITEM);
 
             intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
             PendingIntent toastPendingIntent = PendingIntent.getBroadcast(context, 0 , toastIntent,
             PendingIntent.FLAG_UPDATE_CURRENT);
             rv.setPendingIntentTemplate(R.id.myListView, toastPendingIntent);
                 
             mgr.updateAppWidget(appWidgetIds, rv);
             
             Intent refreshIntent = new  Intent(context, MyWidgetProvider. class );
             refreshIntent.setAction(REFRESH);
             PendingIntent refreshPendingIntent = PendingIntent.getBroadcast(context, 0 ,
                     refreshIntent, 0 );
             rv.setOnClickPendingIntent(R.id.refresh, refreshPendingIntent);
             
             ListRemoteViewsFactory.whichPage = ListRemoteViewsFactory.mainPage;
             ListRemoteViewsFactory.mainPageId = - 1 ;
             mgr.updateAppWidget(cmpName, rv);
             mgr.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.myListView);
             System.out.println( "zhanggui" );
             //Toast.makeText(context, "Touched view back home", Toast.LENGTH_SHORT).show();
         }
         else  if (intent.getAction().equals(REFRESH)){
             System.out.println( "refresh button begin" );
             int [] appWidgetIds = mgr.getAppWidgetIds(cmpName);
             mgr.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.myListView);
             System.out.println( "refresh button end" );
         }
         super .onReceive(context, intent);
     }
 
     @Override
     public  void  onUpdate(Context context, AppWidgetManager appWidgetManager,
             int [] appWidgetIds) {
         System.out.println( "onUpdate" );
         // TODO Auto-generated method stub
         
         for ( int  i = 0 ; i < appWidgetIds.length; i++){
             Intent intent = new  Intent(context, MyWidgetService. class );
             intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
             // When intents are compared, the extras are ignored, so we need to embed the extras
             // into the data so that the extras will not be ignored.
             intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
             RemoteViews rv = new  RemoteViews(context.getPackageName(), R.layout.listview);
             rv.setRemoteAdapter(R.id.myListView, intent);
             //rv.setEmptyView(R.id.myListView, R.id.empty);
             
             Intent refreshIntent = new  Intent(context, MyWidgetProvider. class );
             refreshIntent.setAction(REFRESH);
             PendingIntent refreshPendingIntent = PendingIntent.getBroadcast(context, 0 ,
                     refreshIntent, 0 );
             rv.setOnClickPendingIntent(R.id.refresh, refreshPendingIntent);
 
             Intent toastIntent = new  Intent(context, MyWidgetProvider. class );
             toastIntent.setAction(MyWidgetProvider.ITEM);
             //toastIntent.putExtra("page", 0); // main page
             intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
             PendingIntent toastPendingIntent = PendingIntent.getBroadcast(context, 0 , toastIntent,
                     PendingIntent.FLAG_UPDATE_CURRENT);
             rv.setPendingIntentTemplate(R.id.myListView, toastPendingIntent);
 
             appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
         }
         super .onUpdate(context, appWidgetManager, appWidgetIds);
     }
 
 
}

首先看onUpdate() 函数,默认是从这里先进去的:

申明intent 后使用:

intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));

用:这是为了让 intent 能够带上 extras 数据一起传递,否则在intent的比较的过程中会被忽略掉。这里的比较应该是在同一个代码块中有多个intent的时候会发生比较吧(猜测:因为当一条逻辑执行路径上代码块中只有一个Intent发送的时候能够带数据(不适用intent.setData函数),但是有多个Intent的话不行)

 

PendingIntent 的使用不再解释。不过这里的 remoteView 实例使用:

rv.setPendingIntentTemplate(R.id.myListView, toastPendingIntent);

listView 使用 setPendingIntentTemplate 方法,当你点击 ListView 中的任何一个item 时都会发送 toastPendingIntent ,在我们的 service 中的getViewAt() 方法中,为每一个item 都设置了一个 intent :

rv.setOnClickFillInIntent(R.id.item, fillInIntent);

其中 remoteViews 的setOnClickFillInIntent() 是将 fillIntent 合并到 toastPendingIntent 中去。就是两个 intent 合并了。

具体的合并方法是Intent中的fillIn(..) 方法:

Intent A : {data="foo", categories="bar"}

Intent B : {action="gotit", data-type="some/thing", categories="one","two"}.

调用 fillIn(): A.fillIn(B, Intent.FILL_IN_DATA)

结果:  A : {action="gotit", data-type="some/thing", categories="bar"}.

 

注意到 action 还是你在 onUpdate()中设置的 action,当然你也可以在 item 中的 fillInIntent 设置action.但是不好。

这里可以在每个 item 的 fillInIntent 中 使用 putExtras() 方法让Intent 带每个item 的 位置号码 来区分每个 item.

 

机制基本上已经说完,还有一点就是:

RemoteViewsService 中每次获取数据都会重新创建 service 和 销毁 service ,但是 RemoteViewsService.RemoteViewsFactory

的销毁则是在 机器上把 appWidget 删除后发生。就好像 RemoteViewsService.RemoteViewsFactory 是个数据库。你每次去访问这个数据源都会创建 一个 RemoteViewsService 然后销毁。这个源于我android学习1月,也不清楚内部机制。没仔细研究。等研究了再发文表上。

还有 AppWidgetProvider 类的实例是每发送一次 intent (即每一次 boardcast) 就新建一次,所以如果需要做 flag 来表示按钮是否check的话,最好就先声明为 static 类型或者放到其他类中。

其余的就是自己逻辑的实现:

我这里实现了 两个 ListView 的数据加载(通过http从服务器获取数据)和点入每条item进入另外的页面(这里也是在listView上从新加载数据,但是可以区分每个Item。也可以自己加载其他的layout)。还可以实现回到第一个加载的页面。其实可以做到回到上一个页面。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值