zoukankan      html  css  js  c++  java
  • 分组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;下面的布局很简单:

    View Code
    <LinearLayout
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:paddingBottom="8dp">
     
            <TextView
                    style="?android:attr/listSeparatorTextViewStyle"
                    android:id="@+id/separator"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:textColor="@android:color/white" />
     
            <TextView
                    android:id="@+id/title"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:singleLine="true"
                    android:textColor="?android:attr/textColorPrimary"
                    android:textSize="16sp"
                    android:textStyle="bold"
                    android:paddingTop="8dp"
                    android:paddingRight="8dp"
                    android:paddingLeft="8dp" />
     
            <TextView
                    android:id="@+id/subtitle"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:singleLine="true"
                    android:textColor="?android:attr/textColorSecondary"
                    android:textSize="14sp"
                    android:textStyle="normal"
                    android:paddingRight="8dp"
                    android:paddingLeft="8dp" />
     
    </ LinearLayout中>

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

    View Code
    package com.miss.sos;
    
    import android.app.ListActivity;
    import android.content.Context;
    import android.database.CharArrayBuffer;
    import android.database.Cursor;
    import android.os.Bundle;
    import android.provider.MediaStore.Audio.Media;
    import android.text.TextUtils;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.CursorAdapter;
    import android.widget.ListView;
    import android.widget.TextView;
    
    import com.miss.sos.util.NotifyingAsyncQueryHandler;
    import com.miss.sos.util.NotifyingAsyncQueryHandler.NotifyingAsyncQueryListener;
    
    /**
     * Shows a smart way of handling separators in {@link ListView}s. It also shows
     * some ways to boost your {@link ListView}s using techniques like 'section
     * caching', ViewHolder, CharArrayBuffer, etc.
     * 
     * @author Cyril Mottier
     */
    public class SectionedListActivity extends ListActivity implements NotifyingAsyncQueryListener {
    
        private AudioFilesAdapter mAdapter;
        private NotifyingAsyncQueryHandler mQueryHandler;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            mAdapter = new AudioFilesAdapter(this, null);
            setListAdapter(mAdapter);
    
            // Starts querying the media provider. This is done asynchronously not
            // to possibly block the UI or even worse fire an ANR...
            mQueryHandler = new NotifyingAsyncQueryHandler(getContentResolver(), this);
            mQueryHandler.startQuery(Media.EXTERNAL_CONTENT_URI, AudioFilesQuery.PROJECTION, AudioFilesQuery.SORT_ORDER);
        }
    
        @Override
        protected void onDestroy() {
            // Clear any strong reference to this Activity
            mQueryHandler.clearQueryListener();
            super.onDestroy();
        }
    
        @Override
        public void onQueryComplete(int token, Object cookie, Cursor cursor) {
            if (cursor != null) {
                startManagingCursor(cursor);
            }
            mAdapter.changeCursor(cursor);
        }
    
        private static class AudioFilesViewHolder {
            public TextView separator;
            public TextView titleView;
            public CharArrayBuffer titleBuffer = new CharArrayBuffer(128);
            public TextView subtitleView;
            public StringBuilder subtitleBuffer = new StringBuilder();
        }
    
        private static class AudioFilesAdapter extends CursorAdapter {
    
            /**
             * State of ListView item that has never been determined.
             */
            private static final int STATE_UNKNOWN = 0;
    
            /**
             * State of a ListView item that is sectioned. A sectioned item must
             * display the separator.
             */
            private static final int STATE_SECTIONED_CELL = 1;
    
            /**
             * State of a ListView item that is not sectioned and therefore does not
             * display the separator.
             */
            private static final int STATE_REGULAR_CELL = 2;
    
            private final CharArrayBuffer mBuffer = new CharArrayBuffer(128);
            private int[] mCellStates;
    
            public AudioFilesAdapter(Context context, Cursor cursor) {
                super(context, cursor);
                mCellStates = cursor == null ? null : new int[cursor.getCount()];
            }
    
            @Override
            public void changeCursor(Cursor cursor) {
                super.changeCursor(cursor);
                mCellStates = cursor == null ? null : new int[cursor.getCount()];
            }
    
            @Override
            public void bindView(View view, Context context, Cursor cursor) {
    
                final AudioFilesViewHolder holder = (AudioFilesViewHolder) view.getTag();
    
                /*
                 * Separator
                 */
                boolean needSeparator = false;
    
                final int position = cursor.getPosition();
                cursor.copyStringToBuffer(AudioFilesQuery.TITLE, holder.titleBuffer);
    
                switch (mCellStates[position]) {
                    case STATE_SECTIONED_CELL:
                        needSeparator = true;
                        break;
    
                    case STATE_REGULAR_CELL:
                        needSeparator = false;
                        break;
    
                    case STATE_UNKNOWN:
                    default:
                        // A separator is needed if it's the first itemview of the
                        // ListView or if the group of the current cell is different
                        // from the previous itemview.
                        if (position == 0) {
                            needSeparator = true;
                        } else {
                            cursor.moveToPosition(position - 1);
    
                            cursor.copyStringToBuffer(AudioFilesQuery.TITLE, mBuffer);
                            if (mBuffer.sizeCopied > 0 && holder.titleBuffer.sizeCopied > 0 && mBuffer.data[0] != holder.titleBuffer.data[0]) {
                                needSeparator = true;
                            }
    
                            cursor.moveToPosition(position);
                        }
    
                        // Cache the result
                        mCellStates[position] = needSeparator ? STATE_SECTIONED_CELL : STATE_REGULAR_CELL;
                        break;
                }
    
                if (needSeparator) {
                    holder.separator.setText(holder.titleBuffer.data, 0, 1);
                    holder.separator.setVisibility(View.VISIBLE);
                } else {
                    holder.separator.setVisibility(View.GONE);
                }
    
                /*
                 * Title
                 */
                holder.titleView.setText(holder.titleBuffer.data, 0, holder.titleBuffer.sizeCopied);
    
                /*
                 * Subtitle
                 */
                holder.subtitleBuffer.setLength(0);
                final String album = cursor.getString(AudioFilesQuery.ALBUM);
                if (!TextUtils.isEmpty(album)) {
                    holder.subtitleBuffer.append(album);
                    final String artist = cursor.getString(AudioFilesQuery.ARTIST);
                    if (!TextUtils.isEmpty(artist)) {
                        holder.subtitleBuffer.append(" - ");
                        holder.subtitleBuffer.append(artist);
                    }
                }
                
                if (TextUtils.isEmpty(holder.subtitleBuffer)) {
                    holder.subtitleView.setVisibility(View.GONE);
                } else {
                    holder.subtitleView.setVisibility(View.VISIBLE);
                    holder.subtitleView.setText(holder.subtitleBuffer);
                }
                
            }
    
            @Override
            public View newView(Context context, Cursor cursor, ViewGroup parent) {
    
                View v = LayoutInflater.from(context).inflate(R.layout.audio_list_item, parent, false);
    
                // The following code allows us to keep a reference on the child
                // views of the item. It prevents us from calling findViewById at
                // each getView/bindView and boosts the rendering code.
                AudioFilesViewHolder holder = new AudioFilesViewHolder();
                holder.separator = (TextView) v.findViewById(R.id.separator);
                holder.titleView = (TextView) v.findViewById(R.id.title);
                holder.subtitleView = (TextView) v.findViewById(R.id.subtitle);
    
                v.setTag(holder);
    
                return v;
            }
    
        }
    
        /**
         * Keep query data in one place
         * 
         * @author Cyril Mottier
         */
        private interface AudioFilesQuery {
            String[] PROJECTION = {
                    Media._ID, Media.TITLE, Media.ALBUM, Media.ARTIST
            };
    
            int TITLE = 1;
            int ALBUM = 2;
            int ARTIST = 3;
    
            String SORT_ORDER = Media.TITLE + " ASC";
        }
    
    }

    好了,希望大家happy Coding.!!!   效果图:

    NotifyingAsyncQueryHandler代码:

    View Code
    /*
     * Copyright (C) 2011 Cyril Mottier (http://www.cyrilmottier.com)
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package com.miss.sos.util;
    
    import java.lang.ref.WeakReference;
    
    import android.content.AsyncQueryHandler;
    import android.content.ContentResolver;
    import android.database.Cursor;
    import android.net.Uri;
    
    /**
     * A particular {@link AsyncQueryHandler} allowing clients to be notified via a
     * listener. The {@link NotifyingAsyncQueryHandler} also make sure no strong
     * reference is kept on the given listener (as it is often a Context).
     * 
     * @author Cyril Mottier
     */
    public class NotifyingAsyncQueryHandler extends AsyncQueryHandler {
    
        private WeakReference<NotifyingAsyncQueryListener> mListener;
    
        /**
         * Client may use this to listen to completed query operations.
         * 
         * @author Cyril Mottier
         */
        public interface NotifyingAsyncQueryListener {
            void onQueryComplete(int token, Object cookie, Cursor cursor);
        }
    
        public NotifyingAsyncQueryHandler(ContentResolver resolver, NotifyingAsyncQueryListener listener) {
            super(resolver);
            setQueryListener(listener);
        }
    
        /**
         * Assign the given {@link NotifyingAsyncQueryListener}.
         */
        public void setQueryListener(NotifyingAsyncQueryListener listener) {
            mListener = (listener != null) ? new WeakReference<NotifyingAsyncQueryListener>(listener) : null;
        }
        
        public void clearQueryListener() {
            mListener = null;
        }
    
        public void startQuery(Uri uri, String[] projection) {
            startQuery(-1, null, uri, projection, null, null, null);
        }
    
        public void startQuery(Uri uri, String[] projection, String sortOrder) {
            startQuery(-1, null, uri, projection, null, null, sortOrder);
        }
    
        @Override
        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
            final NotifyingAsyncQueryListener listener = (mListener == null) ? null : mListener.get();
            if (listener != null) {
                listener.onQueryComplete(token, cookie, cursor);
            } else if (cursor != null) {
                cursor.close();
            }
        }
    }
  • 相关阅读:
    前端上传组件Plupload使用指南
    移动前端开发之viewport的深入理解
    性能更好的js动画实现方式——requestAnimationFrame
    如何判断一个js对象是否一个DOM对象
    用Phaser来制作一个html5游戏——flappy bird (二)
    用Phaser来制作一个html5游戏——flappy bird (一)
    css选择器中:first-child与:first-of-type的区别
    用node-webkit把web应用打包成桌面应用
    为Titanium创建自己的安卓推送模块
    Titanium中调用ios组件时语言不是本地化的解决方法
  • 原文地址:https://www.cnblogs.com/androidsj/p/2953575.html
Copyright © 2011-2022 走看看