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:
- 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 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; 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)。還可以實現回到第一個加載的頁面。其實可以做到回到上一個頁面。