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