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
  xmlns:android="http://schemas.android.com/apk/res/android"
  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
  xmlns:android="http://schemas.android.com/apk/res/android"
  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
  xmlns:android="http://schemas.android.com/apk/res/android"
  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);
	}
}

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();	
	}

}

  



注意到几个方法:
public void onDataSetChanged(){.....}
public RemoteViews getViewAt(int position) {....}
public int getCount() {....}

onDateSetChanged(){...} 方法在你使用的 MyWidgetProvider 的 onReceive() 和 onUpdate() 方法中调用
AppWidgetManager 的实例的方法: mgr.notifyAppWidgetViewDataChanged(appIds, R.id.myListView); 来更新要求更新数据源:
首先就会调用 :
onDataSetChanged(){.....}
然后在调用 getViewAt(int position){....}
其中getViewAt 的参数 position 就是你的ListView中每一项 item 的位置。从 0 计数。
其中你必须 override 的 getCount()方法是返回你的ListView item 的总数。这个自己必须返回自己的数据才能让getViewAt的postion能够计数。

你获取数据的方式比如http从服务器获取数据的话,就需要放在onDateSetChagged()方法里。
当然 public RemoteViews getLoadingView(){...} 也可以。不过要注意放回的是RemoteViews 就说明这是要更新界面的,这个函数的作用就是在你更新界面的时候如果耗时就会显示 正在加载... 的默认字样,但是你可以更改这个界面。需要返回一个 RemoteViews 类型。其中你可以使用RemoteViews 去切换自己定义的 Layout 。

关于 remoteViews 的实例的方法:
rv.setOnClickFillInIntent(R.id.item, fillInIntent);
在下面会解释。


下面是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)。还可以实现回到第一个加载的页面。其实可以做到回到上一个页面。

 

博客园不能奉上源代码,可惜。。。有需要的留言~

 

posted on 2012-06-18 20:00  debugman  阅读(5882)  评论(29编辑  收藏  举报