当前位置:编程学习 > wap >>

android4.X 通话记录分组算法 求问

如题:android4.X 通话记录分组算法中 有一个CallLogGroupBuilder.java 类的addGroups(Cursor)方法 是遍历cursor , 然后后一个号码跟前一个号码相同的话(最后的效果是放在一起) 计数,然后执行addGroup(int cursorPosition, int size, boolean expanded)方法 ;不相同就单独出来不处理.但是小弟能力有限 没有看懂addGroup的原理,求大神帮忙解释下.
public abstract class GroupingListAdapter extends BaseAdapter {

    private static final int GROUP_METADATA_ARRAY_INITIAL_SIZE = 16;
    private static final int GROUP_METADATA_ARRAY_INCREMENT = 128;
    private static final long GROUP_OFFSET_MASK    = 0x00000000FFFFFFFFL;
    private static final long GROUP_SIZE_MASK     = 0x7FFFFFFF00000000L;
    private static final long EXPANDED_GROUP_MASK = 0x8000000000000000L;

    public static final int ITEM_TYPE_STANDALONE = 0;
    public static final int ITEM_TYPE_GROUP_HEADER = 1;
    public static final int ITEM_TYPE_IN_GROUP = 2;

    /**
     * Information about a specific list item: is it a group, if so is it expanded.
     * Otherwise, is it a stand-alone item or a group member.
     */
    protected static class PositionMetadata {
        int itemType;
        boolean isExpanded;
        int cursorPosition;
        int childCount;
        private int groupPosition;
        private int listPosition = -1;
    }

    private Context mContext;
    private Cursor mCursor;
    private int mCount;
    private int mGroupCount;

    /**
     * Information about where these groups are located in the list, how large they are
     * and whether they are expanded.
     */
    private long[] mGroupMetadata;

    private SparseIntArray mPositionCache = new SparseIntArray();
    private int mLastCachedListPosition;
    private int mLastCachedCursorPosition;
    private int mLastCachedGroup;

    /**
     * A reusable temporary instance of PositionMetadata
     */
    private PositionMetadata mPositionMetadata = new PositionMetadata();
    public GroupingListAdapter(Context context) {
        mContext = context;
    }

    /**
     * Scans over the entire cursor looking for duplicate phone numbers that need
     * to be collapsed.
     */
    private void findGroups() {
        mGroupCount = 0;
        mGroupMetadata = new long[GROUP_METADATA_ARRAY_INITIAL_SIZE];

        if (mCursor == null) {
            return;
        }
        //这里跳转到CallLogGroupBuilder中执行addGroups方法后返回执行下面addGroup方法
        addGroups(mCursor);
    }

    /**
     * Records information about grouping in the list.  Should be called by the overridden
     * {@link #addGroups} method.
     */
    protected void addGroup(int cursorPosition, int size, boolean expanded) {
        if (mGroupCount >= mGroupMetadata.length) {
int newSize = idealLongArraySize(mGroupMetadata.length + GROUP_METADATA_ARRAY_INCREMENT);
            long[] array = new long[newSize];
            System.arraycopy(mGroupMetadata, 0, array, 0, mGroupCount);
            mGroupMetadata = array;
        }

        long metadata = ((long)size << 32) | cursorPosition;
        if (expanded) {
            metadata |= EXPANDED_GROUP_MASK;
        }
        mGroupMetadata[mGroupCount++] = metadata;
    }

    private int idealLongArraySize(int need) {
        return idealByteArraySize(need * 8) / 8;
    }

    private int idealByteArraySize(int need) {
        for (int i = 4; i < 32; i++)
            if (need <= (1 << i) - 12)
                return (1 << i) - 12;

        return need;
    }

    public int getCount() {
        if (mCursor == null) {
            return 0;
        }

        if (mCount != -1) {
            return mCount;
        }

        int cursorPosition = 0;
        int count = 0;
        for (int i = 0; i < mGroupCount; i++) {
            long metadata = mGroupMetadata[i];
            int offset = (int)(metadata & GROUP_OFFSET_MASK);
            boolean expanded = (metadata & EXPANDED_GROUP_MASK) != 0;
            int size = (int)((metadata & GROUP_SIZE_MASK) >> 32);

            count += (offset - cursorPosition);

            if (expanded) {
                count += size + 1;
            } else {
                count++;
            }
            cursorPosition = offset + size;
        }

        mCount = count + mCursor.getCount() - cursorPosition;
        return mCount;
    }

    /**
     * Figures out whether the item at the specified position represents a
     * stand-alone element, a group or a group child. Also computes the
     * corresponding cursor position.
     */
    public void obtainPositionMetadata(PositionMetadata metadata, int position) {

        // If the description object already contains requested information, just return
        if (metadata.listPosition == position) {
            return;
        }

        int listPosition = 0;
        int cursorPosition = 0;
        int firstGroupToCheck = 0;

        // Check cache for the supplied position.  What we are looking for is
        // the group descriptor immediately preceding the supplied position.
        // Once we have that, we will be able to tell whether the position
        // is the header of the group, a member of the group or a standalone item.
        if (mLastCachedListPosition != -1) {
            if (position <= mLastCachedListPosition) {

                // Have SparceIntArray do a binary search for us.
                int index = mPositionCache.indexOfKey(position);

                // If we get back a positive number, the position corresponds to a group header.
                if (index < 0) {

                    // We had a cache miss, but we did obtain valuable information anyway.
                    // The negative number will allow us to compute the location of
                    // the group header immediately preceding the supplied position.
                    index = ~index - 1;

                    if (index >= mPositionCache.size()) {
                        index--;
                    }
                }

                // A non-negative index gives us the position of the group header
                // corresponding or preceding the position, so we can
                // search for the group information at the supplied position
                // starting with the cached group we just found
                if (index >= 0) {
                    listPosition = mPositionCache.keyAt(index);
                    firstGroupToCheck = mPositionCache.valueAt(index);
                    long descriptor = mGroupMetadata[firstGroupToCheck];
                    cursorPosition = (int)(descriptor & GROUP_OFFSET_MASK);
                }
            } else {

                // If we haven't examined groups beyond the supplied position,
                // we will start where we left off previously
                firstGroupToCheck = mLastCachedGroup;
                listPosition = mLastCachedListPosition;
                cursorPosition = mLastCachedCursorPosition;
            }
        }

        for (int i = firstGroupToCheck; i < mGroupCount; i++) {
            long group = mGroupMetadata[i];
            int offset = (int)(group & GROUP_OFFSET_MASK);

            // Move pointers to the beginning of the group
            listPosition += (offset - cursorPosition);
            cursorPosition = offset;

            if (i > mLastCachedGroup) {
                mPositionCache.append(listPosition, i);
                mLastCachedListPosition = listPosition;
                mLastCachedCursorPosition = cursorPosition;
                mLastCachedGroup = i;
            }

            // Now we have several possibilities:
            // A) The requested position precedes the group
            if (position < listPosition) {
                metadata.itemType = ITEM_TYPE_STANDALONE;
                metadata.cursorPosition = cursorPosition - (listPosition - position);
                return;
            }

            boolean expanded = (group & EXPANDED_GROUP_MASK) != 0;
            int size = (int) ((group & GROUP_SIZE_MASK) >> 32);

            // B) The requested position is a group header
            if (position == listPosition) {
                metadata.itemType = ITEM_TYPE_GROUP_HEADER;
                metadata.groupPosition = i;
                metadata.isExpanded = expanded;
                metadata.childCount = size;
                metadata.cursorPosition = offset;
                return;
            }

            if (expanded) {
                // C) The requested position is an element in the expanded group
                if (position < listPosition + size + 1) {
                    metadata.itemType = ITEM_TYPE_IN_GROUP;
                    metadata.cursorPosition = cursorPosition + (position - listPosition) - 1;
                    return;
                }

                // D) The element is past the expanded group
                listPosition += size + 1;
            } else {

                // E) The element is past the collapsed group
                listPosition++;
            }

            // Move cursor past the group
            cursorPosition += size;
        }

        // The required item is past the last group
        metadata.itemType = ITEM_TYPE_STANDALONE;
        metadata.cursorPosition = cursorPosition + (position - listPosition);
    }

    @Override
    public int getItemViewType(int position) {
        obtainPositionMetadata(mPositionMetadata, position);
        return mPositionMetadata.itemType;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        obtainPositionMetadata(mPositionMetadata, position);
        View view = convertView;
        if (view == null) {
            view = ... //文本太长了,发帖有文字长度限制 我就不贴完整了
        }

        mCursor.moveToPosition(mPositionMetadata.cursorPosition);
        switch (mPositionMetadata.itemType) {
            //bind各种View
        }
        return view;
    }
}
Android CallLog 分组
补充:移动开发 ,  Android
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,