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

  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="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

android 中 AppWidget 的 ListView 的实现

时间: 2024-10-03 21:42:01

android 中 AppWidget 的 ListView 的实现的相关文章

android中scrollview包含listView对高度设置

当scrollview中包含listView时,滑动的时候会出现问题..最常见的问题是listview滑动不了...问题原因是在加载listview时它的高度应该按照adapter所绑定的数据来确定,而不是fill_parent或者是wrap_content... 项目中用到了就把它抽取出来做个记录 import android.view.View; import android.view.ViewGroup; import android.widget.ListAdapter; import

Android中ScrollView嵌套ListView只显示一行的解决方案

Android中ScrollView嵌套ListView只显示一行的解决方案 解决方案1: 直接把包含ListView控件的ScrollView控件从布局文件中去除,留下ListView控件,这是最简单快捷的解决办法. 如果一定要在ScrollView中包含ListView,则参考 解决方案2: public void showlist() { List<HashMap<String, String>> dataHashMaps = new ArrayList<HashMap

Android中监听ListView滑动到底部

Android中的应用就是ListView中向下滑动加载更多的功能,不要再onScroll方法中进行判断,那样当滑动到底部的时候,可能我们需要触发点什么事件,比如加载更多.隐藏某个控件等等. 第一种方法是直接滑动到底部就触发 listview.setOnScrollListener(new OnScrollListener(){       @Override       public void onScrollStateChanged(AbsListView view, int scrollS

Android中一个关于ListView的奇怪问题

今天在做项目的时候发现了一个比较奇怪的问题,是关于ListView的,即ListView的android:height属性会影响程序中ListView的getView()方法的调用次数,如果设置ListView的android:height属性为0dp,同时设置android:weight=1,或者直接设置android:height属性为"wrap_content",那么ListView在展示数据的时候,getView()被执行的次数并不会是传入数据集合的size,而会比size的值

android中ScrollView嵌套ListView或GridView显示位置问题

Android中ScrollView中嵌套ListView或GridView时在开始进入界面时总是显示中间位置,开头的位置显示不出来.这种情况下只需要在ScrollView的父控件中添加以下两行代码即可. 1 android:focusableInTouchMode="true" 2 android:focusable="true" 还有一个问题:在ScrollView嵌套ListView或GridView时仅仅显示一行或两行,ListView或GridView无法

android 中如何实现listview向左边滑动跟微信删除好友一样的效果?

============问题描述============ 今天在开发android的时候需要实现liview中的每个子item向左边滑动一半,露出删除按钮,跟现在微信删除好友一样.怎么实现啊....求大神.. ============解决方案1============ 每个item的layout布局中是包含删除按钮的,并且默认删除按钮是隐藏的,当向左滑动后把按钮显示出来. 如果要滑动效果,还可以加个动画,采用ObjectAnimator就可以实现. ============解决方案2======

Android中取消GridView &amp; ListView默认的点击背景色

方法一: gridView.setSelector(new ColorDrawable(Color.TRANSPARENT)); listView.setSelector(new ColorDrawable(Color.TRANSPARENT)); 在代码中初始化的时候设置其属性. 方法二: <GridView android:listSelector="@android:color/transparent" android:numColumns="auto_fit&q

android中ProgressBar和ListView

ProgressBar进度条的使用情况: 进度条的.xml声明:如果不声明格式,则默认格式为转圆圈的形式,声明进度条的visibility为不可见. <ProgressBar android:id="@+id/firstBar" android:layout_width="fill_parent" android:layout_height="wrap_content" style="?android:attr/progressB

Android 中ScrollView嵌套ListView 最简单有效的处理方法

第一次写博客,有错的地方大家可以指出: 大家都知道在ScrollView嵌套ListView,ListView会显示不完全,无法计算ListView的高度,要解决在一个滑动界面中显示ListView和其他布局,有两种方法: 第一种:就是让listView的高度全部展示出来,那么这个就要对ListView进行封装,重新设置高度:代码如下: public class ListViewForScrollView extends ListView { public ListViewForScrollVi