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:

  • FrameLayout
  • LinearLayout
  • RelativeLayout

And the following widget classes:

  • AnalogClock
  • Button
  • Chronometer
  • ImageButton
  • ImageView
  • ProgressBar
  • TextView
  • ViewFlipper
  • ListView
  • GridView
  • StackView
  • AdapterViewFlipper

Descendants of these classes are not supported

其中有ListView和 GridView 等控件。

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

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

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

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

 

注意到:

String action = intent.getAction();

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

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

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

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

<?xml version= "1.0"  encoding= "utf-8" ?>    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"    >    

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

<?xml version= "1.0"  encoding= "utf-8" ?>    xmlns:android= "http://schemas.android.com/apk/res/android"    android:layout_width= "294dp"    android:layout_height= "400dp" >         android:layout_width= "fill_parent"      android:layout_height= "360dp"      android:minHeight= "100dp"      android:id= "@+id/listviewWrapper"      >                 android:layout_height = "360dp"          android:layout_width = "294dp"          android:background= "#000000"          android:id = "@+id/myListView"        />            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"      >   

下面是list_item 文件:

<?xml version= "1.0"  encoding= "utf-8" ?>    xmlns:android= "http://schemas.android.com/apk/res/android"    android:layout_width= "match_parent"    android:layout_height= "match_parent" >         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"    />         android:id= "@+id/imageItem"      android:layout_width= "wrap_content"      android:layout_height= "wrap_content"      android:layout_alignParentRight= "true"      android:layout_alignRight= "@id/item"      />

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

这是manifest 问件:

<?xml version= "1.0"  encoding= "utf-8" ?> "http://schemas.android.com/apk/res/android"      package = "com.zgc.AppWidget6"      android:versionCode= "1"      android:versionName= "1.0"  >        "15"  />                 android:icon= "@drawable/ic_launcher"          android:label= "@string/app_name"  >          ".MyWidgetProvider" >              "android.appwidget.provider"                  android:resource= "@xml/provider_info"  >                                            "android.appwidget.action.APPWIDGET_UPDATE" >                                             ".MyWidgetService"              android:permission= "android.permission.BIND_REMOTEVIEWS"              android:exported= "false"  >                             "android.permission.INTERNET" >

其中 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);      } }

class  ListRemoteViewsFactory implements  RemoteViewsService.RemoteViewsFactory {            private  static  int  mCount = 0 ;      private  List mWidgetItems = new  ArrayList();      private  List mWidgetItemsAttr= new  ArrayList();      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 checkPos = new  ArrayList();      //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 > mList= new  ArrayList>();                                               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 map = new  HashMap();                                                          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();        }   }

  



注意到几个方法:
public  void  onDataSetChanged(){.....}
public  RemoteViews getViewAt( int  position) {....}
public  int  getCount() {....}

onDateSetChanged(){...} 方法在你使用的 MyWidgetProvider 的 onReceive() 和 onUpdate() 方法中调用
AppWidgetManager 的实例的方法: mgr.notifyAppWidgetViewDataChanged(appIds, R.id.myListView); 来更新要求更新数据源:
首先就会调用 :
onDataSetChanged(){.....}
然后在调用 getViewAt( int  position){....}
其中getViewAt 的参数 position 就是你的ListView中每一项 item 的位置。从
0  计数。
其中你必须 override 的 getCount()方法是返回你的ListView item 的总数。这个自己必须返回自己的数据才能让getViewAt的postion能够计数。

你获取数据的方式比如http从服务器获取数据的话,就需要放在onDateSetChagged()方法里。
当然
public  RemoteViews getLoadingView(){...} 也可以。不过要注意放回的是RemoteViews 就说明这是要更新界面的,这个函数的作用就是在你更新界面的时候如果耗时就会显示 正在加载... 的默认字样,但是你可以更改这个界面。需要返回一个 RemoteViews 类型。其中你可以使用RemoteViews 去切换自己定义的 Layout 。

关于 remoteViews 的实例的方法:

更多相关文章

  1. Android(安卓)UI(TextView)详解
  2. Android[高级教程] 设计模式之七 单例模式
  3. android的surfaceview的用法
  4. Android(安卓)AIDL 双向调用的使用及相关原理
  5. Android面试知识点总结-Android篇
  6. Android(安卓)Service
  7. 通用(任何android机型)Root教程(完整版!附砖机自救方法)
  8. 关闭 / 隐藏 Android(安卓)软键盘
  9. Android中View的滑动

随机推荐

  1. android标题栏的选择与使用,AppCompatActi
  2. Android界面编程——Android布局组件(二)
  3. Android(安卓)自动编译、打包生成apk文件
  4. Android(安卓)显示原理简介
  5. Android(安卓)TV框架 TIF(Android(安卓)TV
  6. 选择Android还是IOS开发?
  7. 关于界面布局的一些小知识
  8. Android中shape使用
  9. Android内核开发 学习笔记
  10. Android中使用ormlite实现持久化(一)--He