android 中 AppWidget 的 ListView 的实现

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

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

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

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

And the following widget classes:

Descendants of these classes are not supported

其中有ListView和 GridView 等控件。

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

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

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

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

 

注意到:

String action = intent.getAction();

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

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

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

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

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

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

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

下面是list_item 文件:

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

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

这是manifest 问件:

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

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

RemoteViewsService的是个服务。其中:

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

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

具体逻辑如图:

    

 

下面是 service 的源代码:

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

  

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

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

申明intent 后使用:

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

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

 

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

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

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

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

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

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

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

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

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

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

 

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

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

 

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

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

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

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

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

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

 

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

posted on 2014-07-12 19:53  veins  阅读(2089)  评论(0编辑  收藏  举报

导航