首页 > 代码库 > android 中 AppWidget 的 ListView 的实现
android 中 AppWidget 的 ListView 的实现
3.0 以后系统直接支持了ListView. 关于ListView 的国内资料匮乏,大多数例子都是转来转去。由于初学android, 鄙人在搜索资料的时候遇到了不少麻烦~很是郁闷和苦恼~深感国内学习氛围确实怪异,学习方式需要改变。应该多去查看官方文档。。。。
话不多说,现在开始listView 实现:
这是文档列出的支持的布局和widget控件:
A RemoteViews object (and, consequently, an App Widget) can support the following layout classes:
- FrameLayout
- LinearLayout
- RelativeLayout
And the following widget classes:
- AnalogClock
- Button
- Chronometer
- ImageButton
- ImageView
- ProgressBar
- TextView
- ViewFlipper
- ListView
- GridView
- StackView
- AdapterViewFlipper
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); } }<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="http://www.mamicode.com/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)。还可以实现回到第一个加载的页面。其实可以做到回到上一个页面。
原文:http://www.cnblogs.com/debugman/archive/2012/06/18/android.html