分组ListView使用技巧

前言:

ListView通常显示比较大的数据量.例如,“通讯录”应用程序使用的 ListView 包含所有您的联系人。在此中Activity中每个联系人代表一个单一的item view。这种模式是很方便,因为在同一时间它显示在屏幕上的几次接触。换句话说,它为用户提供大型概述了他/她的联系人。但是,使用一个 ListView 部件是远远不够的......

如果让你开发了一个随机顺序显示所有联系人的通讯列表;解决的办法是理解和正常秩序中的所有联系人进行排序:按字母顺序排列。在另外的顺序,它通常是一个很好的做法,第几组数据。在“通讯录”应用程序实例,它归结为每个英文字母部分。


方法1:使用不同类型的视图ListView和更具体的adapter可以处理几种类型view。如果查询适配器接口,你会发现它包含两个具体方法:

  • getViewTypeCount()返回类型view AdapterView管理。大部分时间此方法返回1,因为所有项目的ListView类似。在这种情况下,返回2,ListView 的将处理两种类型的view:经常项目视图和属于分隔查看.
  • getItemViewType(INT)必须返回0(含)之间的一个整数getViewTypeCount() (inclusive )。给定的数字表示该类型的视图,在给定的位置。例如,我们可以确保返回的值是经常项目的小号0 和1的分隔符.


优势
  • 让你管理itmes的几种类型
  • 很容易理解
缺点
  • 几乎没有大量代码。
  • 在一个特定的位置获得该item可能有困难。比方说,我们有[S1,C1,C2,S2,C3,C4,C5] SN是N次的分离器和CN N次接触。第五次接触实际存储在我们的数据数组的第7次。这意味着你不能访问,不知道多少部分数据包含在N的前面接触到您的阵列中的N次接触。

方法2:利用GONE Visibility另一种方式的ListView sectioning  是使用的视图类的visibility属性。 Android是能够动态测量和布局item  view。在ListView的渲染系统,这两次传球被执行,只有当一个视图需要显示。换句话说,默认情况下, 一个 ListView item  view高度 可变的。巧妙设置分隔符的visiable。该算法是相当简单的,分隔符必须是View.VISIBLE时,该项目是第一个适配器或如果当前项目是在一个比前一个不同的组。如果没有这些条件进行了验证,我们将设置View.GONE的分隔。图形下面总结的伎俩: 缺点
  • 使用更多的内存。
优势
  • 很容易将Sectioning 进行的“即时”.
  • 简单分隔点击和执行的操作类似“下一步”。
  • GetItem(int) 始终返回在您的数据基础结构中的第n个位置的item。此方法过程中,是基于cursor的适配器。这是根据查询ContentProvider时发生的。



例子:
  • NotifyingAsyncQueryListener:这个类可以帮助我们以异步方式查询ContentProvider。这是一个很好的方式在运行时以异步方式与ContentProvider,它可以防止在查询中从而阻止UI或者ANR弹出...在下面的例子中,我创建了一个定制的监听器的基础上提供的API,AsyncQueryHandler。这个类是因为API级别1。如果你是Android更高的版本,你一定要仔细看看CursorLoader类。
  • ViewHolder:这种设计模式省去了经常性的调用findViewById(int)的使用,每次getView / BindView的执行。它由引用 child View 一次存储的标签(setTag(对象))查看和使用那些在重新引用的getView /BindView的方法代码。
  • itemview状态缓存:在以前的item,如果要显示需要检查分离器。一个简单的优化是缓存“分隔状态”每个item view。当然,我们需要彻底清除这个缓存(这里我们的基础数据的sursor)时被修改(changeCursor(光标))。
  • CharArrayBuffer:一般童鞋经常使用的 getString ()方法取出cursor里的数据。但是它意味着创建的String对象,一旦用户开始滚动列表这些对象可能被garbaged。为了防止重复创建对象,可以使用CharArrayBuffer包括从数据复制光标的原始字符数组,TextView 将直接使用。而不必每次创建一个 String 对象,因此,我们将重用一个CharArrayBuffer。
下面的例子显示你如何实施分段ListView的第二种方法。查询系统的所有设备上的音频文件,并显示切片和按字母顺序排序的ListView,如下面的截图所示的例子包括: 布局
首先,我们需要创建一个自定义的布局,将每个 cell 的布局。我们只是想显示歌名以及字幕。根据当前的分隔状态的状态我们还需要添加的查看,将gone/visiable;下面的布局很简单:

  1. <LinearLayout
  2.         xmlns:android="http://schemas.android.com/apk/res/android"
  3.         android:layout_width="fill_parent"
  4.         android:layout_height="wrap_content"
  5.         android:orientation="vertical"
  6.         android:paddingBottom="8dp">

  7.         <TextView
  8.                 style="?android:attr/listSeparatorTextViewStyle"
  9.                 android:id="@+id/separator"
  10.                 android:layout_width="fill_parent"
  11.                 android:layout_height="wrap_content"
  12.                 android:textColor="@android:color/white" />

  13.         <TextView
  14.                 android:id="@+id/title"
  15.                 android:layout_width="fill_parent"
  16.                 android:layout_height="wrap_content"
  17.                 android:singleLine="true"
  18.                 android:textColor="?android:attr/textColorPrimary"
  19.                 android:textSize="16sp"
  20.                 android:textStyle="bold"
  21.                 android:paddingTop="8dp"
  22.                 android:paddingRight="8dp"
  23.                 android:paddingLeft="8dp" />

  24.         <TextView
  25.                 android:id="@+id/subtitle"
  26.                 android:layout_width="fill_parent"
  27.                 android:layout_height="wrap_content"
  28.                 android:singleLine="true"
  29.                 android:textColor="?android:attr/textColorSecondary"
  30.                 android:textSize="14sp"
  31.                 android:textStyle="normal"
  32.                 android:paddingRight="8dp"
  33.                 android:paddingLeft="8dp" />

  34. </ LinearLayout中>
复制代码
实际的代码现在我们可以直接深入到Java代码。可能有人会问: 为什么我们不为屏幕上创建自定义布局。事实上我们并不需要创建一个自定义布局的ListView;而且ListActivity所提供的正是我们正在寻找一个完全类似的默认布局。我们会让ListActivity布局设置我们的屏幕上做工作。主要java代码:
  1. package com.miss.sos;

  2. import android.app.ListActivity;
  3. import android.content.Context;
  4. import android.database.CharArrayBuffer;
  5. import android.database.Cursor;
  6. import android.os.Bundle;
  7. import android.provider.MediaStore.Audio.Media;
  8. import android.text.TextUtils;
  9. import android.view.LayoutInflater;
  10. import android.view.View;
  11. import android.view.ViewGroup;
  12. import android.widget.CursorAdapter;
  13. import android.widget.ListView;
  14. import android.widget.TextView;

  15. import com.miss.sos.util.NotifyingAsyncQueryHandler;
  16. import com.miss.sos.util.NotifyingAsyncQueryHandler.NotifyingAsyncQueryListener;

  17. /**
  18. * Shows a smart way of handling separators in {@link ListView}s. It also shows
  19. * some ways to boost your {@link ListView}s using techniques like 'section
  20. * caching', ViewHolder, CharArrayBuffer, etc.

  21. * @author Cyril Mottier
  22. */
  23. public class SectionedListActivity extends ListActivity implements NotifyingAsyncQueryListener {

  24.     private AudioFilesAdapter mAdapter;
  25.     private NotifyingAsyncQueryHandler mQueryHandler;

  26.     @Override
  27.     public void onCreate(Bundle savedInstanceState) {
  28.         super.onCreate(savedInstanceState);

  29.         mAdapter = new AudioFilesAdapter(this, null);
  30.         setListAdapter(mAdapter);

  31.         // Starts querying the media provider. This is done asynchronously not
  32.         // to possibly block the UI or even worse fire an ANR...
  33.         mQueryHandler = new NotifyingAsyncQueryHandler(getContentResolver(), this);
  34.         mQueryHandler.startQuery(Media.EXTERNAL_CONTENT_URI, AudioFilesQuery.PROJECTION, AudioFilesQuery.SORT_ORDER);
  35.     }

  36.     @Override
  37.     protected void onDestroy() {
  38.         // Clear any strong reference to this Activity
  39.         mQueryHandler.clearQueryListener();
  40.         super.onDestroy();
  41.     }

  42.     @Override
  43.     public void onQueryComplete(int token, Object cookie, Cursor cursor) {
  44.         if (cursor != null) {
  45.             startManagingCursor(cursor);
  46.         }
  47.         mAdapter.changeCursor(cursor);
  48.     }

  49.     private static class AudioFilesViewHolder {
  50.         public TextView separator;
  51.         public TextView titleView;
  52.         public CharArrayBuffer titleBuffer = new CharArrayBuffer(128);
  53.         public TextView subtitleView;
  54.         public StringBuilder subtitleBuffer = new StringBuilder();
  55.     }

  56.     private static class AudioFilesAdapter extends CursorAdapter {

  57.         /**
  58.          * State of ListView item that has never been determined.
  59.          */
  60.         private static final int STATE_UNKNOWN = 0;

  61.         /**
  62.          * State of a ListView item that is sectioned. A sectioned item must
  63.          * display the separator.
  64.          */
  65.         private static final int STATE_SECTIONED_CELL = 1;

  66.         /**
  67.          * State of a ListView item that is not sectioned and therefore does not
  68.          * display the separator.
  69.          */
  70.         private static final int STATE_REGULAR_CELL = 2;

  71.         private final CharArrayBuffer mBuffer = new CharArrayBuffer(128);
  72.         private int[] mCellStates;

  73.         public AudioFilesAdapter(Context context, Cursor cursor) {
  74.             super(context, cursor);
  75.             mCellStates = cursor == null ? null : new int[cursor.getCount()];
  76.         }

  77.         @Override
  78.         public void changeCursor(Cursor cursor) {
  79.             super.changeCursor(cursor);
  80.             mCellStates = cursor == null ? null : new int[cursor.getCount()];
  81.         }

  82.         @Override
  83.         public void bindView(View view, Context context, Cursor cursor) {

  84.             final AudioFilesViewHolder holder = (AudioFilesViewHolder) view.getTag();

  85.             /*
  86.              * Separator
  87.              */
  88.             boolean needSeparator = false;

  89.             final int position = cursor.getPosition();
  90.             cursor.copyStringToBuffer(AudioFilesQuery.TITLE, holder.titleBuffer);

  91.             switch (mCellStates[position]) {
  92.                 case STATE_SECTIONED_CELL:
  93.                     needSeparator = true;
  94.                     break;

  95.                 case STATE_REGULAR_CELL:
  96.                     needSeparator = false;
  97.                     break;

  98.                 case STATE_UNKNOWN:
  99.                 default:
  100.                     // A separator is needed if it's the first itemview of the
  101.                     // ListView or if the group of the current cell is different
  102.                     // from the previous itemview.
  103.                     if (position == 0) {
  104.                         needSeparator = true;
  105.                     } else {
  106.                         cursor.moveToPosition(position - 1);

  107.                         cursor.copyStringToBuffer(AudioFilesQuery.TITLE, mBuffer);
  108.                         if (mBuffer.sizeCopied > 0 && holder.titleBuffer.sizeCopied > 0 && mBuffer.data[0] != holder.titleBuffer.data[0]) {
  109.                             needSeparator = true;
  110.                         }

  111.                         cursor.moveToPosition(position);
  112.                     }

  113.                     // Cache the result
  114.                     mCellStates[position] = needSeparator ? STATE_SECTIONED_CELL : STATE_REGULAR_CELL;
  115.                     break;
  116.             }

  117.             if (needSeparator) {
  118.                 holder.separator.setText(holder.titleBuffer.data, 0, 1);
  119.                 holder.separator.setVisibility(View.VISIBLE);
  120.             } else {
  121.                 holder.separator.setVisibility(View.GONE);
  122.             }

  123.             /*
  124.              * Title
  125.              */
  126.             holder.titleView.setText(holder.titleBuffer.data, 0, holder.titleBuffer.sizeCopied);

  127.             /*
  128.              * Subtitle
  129.              */
  130.             holder.subtitleBuffer.setLength(0);
  131.             final String album = cursor.getString(AudioFilesQuery.ALBUM);
  132.             if (!TextUtils.isEmpty(album)) {
  133.                 holder.subtitleBuffer.append(album);
  134.                 final String artist = cursor.getString(AudioFilesQuery.ARTIST);
  135.                 if (!TextUtils.isEmpty(artist)) {
  136.                     holder.subtitleBuffer.append(" - ");
  137.                     holder.subtitleBuffer.append(artist);
  138.                 }
  139.             }
  140.             
  141.             if (TextUtils.isEmpty(holder.subtitleBuffer)) {
  142.                 holder.subtitleView.setVisibility(View.GONE);
  143.             } else {
  144.                 holder.subtitleView.setVisibility(View.VISIBLE);
  145.                 holder.subtitleView.setText(holder.subtitleBuffer);
  146.             }
  147.             
  148.         }

  149.         @Override
  150.         public View newView(Context context, Cursor cursor, ViewGroup parent) {

  151.             View v = LayoutInflater.from(context).inflate(R.layout.audio_list_item, parent, false);

  152.             // The following code allows us to keep a reference on the child
  153.             // views of the item. It prevents us from calling findViewById at
  154.             // each getView/bindView and boosts the rendering code.
  155.             AudioFilesViewHolder holder = new AudioFilesViewHolder();
  156.             holder.separator = (TextView) v.findViewById(R.id.separator);
  157.             holder.titleView = (TextView) v.findViewById(R.id.title);
  158.             holder.subtitleView = (TextView) v.findViewById(R.id.subtitle);

  159.             v.setTag(holder);

  160.             return v;
  161.         }

  162.     }

  163.     /**
  164.      * Keep query data in one place
  165.      * 
  166.      * @author Cyril Mottier
  167.      */
  168.     private interface AudioFilesQuery {
  169.         String[] PROJECTION = {
  170.                 Media._ID, Media.TITLE, Media.ALBUM, Media.ARTIST
  171.         };

  172.         int TITLE = 1;
  173.         int ALBUM = 2;
  174.         int ARTIST = 3;

  175.         String SORT_ORDER = Media.TITLE + " ASC";
  176.     }

  177. }
复制代码
好了,希望大家happy Coding.!!!    效果图:
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值