SparseArray根据源码简单分析

/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * 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 android.util;

import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;

import libcore.util.EmptyArray;

/**
 * SparseArrays map integers to Objects.  Unlike a normal array of Objects,
 * there can be gaps in the indices.  It is intended to be more memory efficient
 * than using a HashMap to map Integers to Objects, both because it avoids
 * auto-boxing keys and its data structure doesn't rely on an extra entry object
 * for each mapping.
 *
 * 

Note that this container keeps its mappings in an array data structure, * using a binary search to find keys. The implementation is not intended to be appropriate for * data structures * that may contain large numbers of items. It is generally slower than a traditional * HashMap, since lookups require a binary search and adds and removes require inserting * and deleting entries in the array. For containers holding up to hundreds of items, * the performance difference is not significant, less than 50%.

* *

To help with performance, the container includes an optimization when removing * keys: instead of compacting its array immediately, it leaves the removed entry marked * as deleted. The entry can then be re-used for the same key, or compacted later in * a single garbage collection step of all removed entries. This garbage collection will * need to be performed at any time the array needs to be grown or the the map size or * entry values are retrieved.

* *

It is possible to iterate over the items in this container using * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using * keyAt(int) with ascending values of the index will return the * keys in ascending order, or the values corresponding to the keys in ascending * order in the case of valueAt(int).

*/ public class SparseArray implements Cloneable { private static final Object DELETED = new Object(); //数据结构中是否包含为空的垃圾 private boolean mGarbage = false; //一个存key的数组 private int[] mKeys; //一个存value的数组 private Object[] mValues; private int mSize; /** * Creates a new SparseArray containing no mappings. * 默认创建大小为10 */ public SparseArray() { this(10); } /** * Creates a new SparseArray containing no mappings that will not * require any additional memory allocation to store the specified * number of mappings. If you supply an initial capacity of 0, the * sparse array will be initialized with a light-weight representation * not requiring any additional array allocations. */ public SparseArray(int initialCapacity) { if (initialCapacity == 0) { mKeys = EmptyArray.INT; mValues = EmptyArray.OBJECT; } else { mValues = ArrayUtils.newUnpaddedObjectArray(initialCapacity); mKeys = new int[mValues.length]; } mSize = 0; } @Override @SuppressWarnings("unchecked") public SparseArray clone() { SparseArray clone = null; try { clone = (SparseArray) super.clone(); clone.mKeys = mKeys.clone(); clone.mValues = mValues.clone(); } catch (CloneNotSupportedException cnse) { /* ignore */ } return clone; } /** * Gets the Object mapped from the specified key, or null * if no such mapping has been made. * 根据key查找数据,查找不到则返回null */ public E get(int key) { return get(key, null); } /** * Gets the Object mapped from the specified key, or the specified Object * if no such mapping has been made. * 根据key查找数据,查找不到则返回为默认值valueIfKeyNotFound */ @SuppressWarnings("unchecked") public E get(int key, E valueIfKeyNotFound) { //二分查找法 int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i < 0 || mValues[i] == DELETED) { //没找到,或者找到空对象 return valueIfKeyNotFound; } else { //找到了 return (E) mValues[i]; } } /** * Removes the mapping from the specified key, if there was any. * 根据key删除 */ public void delete(int key) { //二分法 int i = ContainerHelpers.binarySearch(mKeys, mSize, key); //找到目标 if (i >= 0) { if (mValues[i] != DELETED) {//不为空对象。则置为空对象 mValues[i] = DELETED; mGarbage = true;//存在垃圾 } } } /** * @hide * Removes the mapping from the specified key, if there was any, returning the old value. * 根据key删除并且返回删除的内容 */ public E removeReturnOld(int key) { int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i >= 0) { if (mValues[i] != DELETED) { final E old = (E) mValues[i]; mValues[i] = DELETED; mGarbage = true; return old; } } return null; } /** * Alias for {@link #delete(int)}. */ public void remove(int key) { delete(key); } /** * Removes the mapping at the specified index. * *

For indices outside of the range 0...size()-1, * the behavior is undefined.

* 根据位置移除 */ public void removeAt(int index) { if (mValues[index] != DELETED) { mValues[index] = DELETED; mGarbage = true; } } /** * Remove a range of mappings as a batch. * * @param index Index to begin at * @param size Number of mappings to remove * *

For indices outside of the range 0...size()-1, * the behavior is undefined.

* 批量处理一系列的删除操作 */ public void removeAtRange(int index, int size) { final int end = Math.min(mSize, index + size); for (int i = index; i < end; i++) { removeAt(i); } } /** * 处理垃圾回收 */ private void gc() { // Log.e("SparseArray", "gc start with " + mSize); int n = mSize; int o = 0; int[] keys = mKeys; Object[] values = mValues; for (int i = 0; i < n; i++) { Object val = values[i]; if (val != DELETED) { if (i != o) { keys[o] = keys[i]; values[o] = val; values[i] = null; } o++; } } mGarbage = false; mSize = o; // Log.e("SparseArray", "gc end with " + mSize); } /** * Adds a mapping from the specified key to the specified value, * replacing the previous mapping from the specified key if there * was one. * 添加键值对 */ public void put(int key, E value) { int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i >= 0) {//如果数组中已经有这个key.则替换这个key对应的值。 mValues[i] = value; } else { //如果没有则i为反 i = ~i;//i为负数。所以取反 //键在规定范围内。对应的值也正好为空对象。那么正好替换。 if (i < mSize && mValues[i] == DELETED) { mKeys[i] = key; mValues[i] = value; return; } //如果存在垃圾。需要空间大于实际空间。那么先回收。再重新计算i. if (mGarbage && mSize >= mKeys.length) { gc(); // Search again because indices may have changed. i = ~ContainerHelpers.binarySearch(mKeys, mSize, key); } //向数组中插入数据 源码在末尾 mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key); mValues = GrowingArrayUtils.insert(mValues, mSize, i, value); mSize++; } } /** * Returns the number of key-value mappings that this SparseArray * currently stores. * 返回大小。 */ public int size() { if (mGarbage) { gc(); } return mSize; } /** * Given an index in the range 0...size()-1, returns * the key from the indexth key-value mapping that this * SparseArray stores. * *

The keys corresponding to indices in ascending order are guaranteed to * be in ascending order, e.g., keyAt(0) will return the * smallest key and keyAt(size()-1) will return the largest * key.

* *

For indices outside of the range 0...size()-1, * the behavior is undefined.

* 根据位置返回当前位置的key */ public int keyAt(int index) { if (mGarbage) { gc(); } return mKeys[index]; } /** * Given an index in the range 0...size()-1, returns * the value from the indexth key-value mapping that this * SparseArray stores. * *

The values corresponding to indices in ascending order are guaranteed * to be associated with keys in ascending order, e.g., * valueAt(0) will return the value associated with the * smallest key and valueAt(size()-1) will return the value * associated with the largest key.

* *

For indices outside of the range 0...size()-1, * the behavior is undefined.

* 根据位置返回当前的value */ @SuppressWarnings("unchecked") public E valueAt(int index) { if (mGarbage) { gc(); } return (E) mValues[index]; } /** * Given an index in the range 0...size()-1, sets a new * value for the indexth key-value mapping that this * SparseArray stores. * *

For indices outside of the range 0...size()-1, the behavior is undefined.

* 根据位置设置value */ public void setValueAt(int index, E value) { if (mGarbage) { gc(); } mValues[index] = value; } /** * Returns the index for which {@link #keyAt} would return the * specified key, or a negative number if the specified * key is not mapped. * 根据key返回key的位置 */ public int indexOfKey(int key) { if (mGarbage) { gc(); } return ContainerHelpers.binarySearch(mKeys, mSize, key); } /** * Returns an index for which {@link #valueAt} would return the * specified key, or a negative number if no keys map to the * specified value. *

Beware that this is a linear search, unlike lookups by key, * and that multiple keys can map to the same value and this will * find only one of them. *

Note also that unlike most collections' {@code indexOf} methods, * this method compares values using {@code ==} rather than {@code equals}. * 根据value返回value的位置 */ public int indexOfValue(E value) { if (mGarbage) { gc(); } for (int i = 0; i < mSize; i++) if (mValues[i] == value) return i; return -1; } /** * Removes all key-value mappings from this SparseArray. * 清空 */ public void clear() { int n = mSize; Object[] values = mValues; for (int i = 0; i < n; i++) { values[i] = null; } mSize = 0; mGarbage = false; } /** * Puts a key/value pair into the array, optimizing for the case where * the key is greater than all existing keys in the array. * 添加新的key.value 到最高效的位置 */ public void append(int key, E value) { if (mSize != 0 && key <= mKeys[mSize - 1]) { put(key, value); return; } if (mGarbage && mSize >= mKeys.length) { gc(); } mKeys = GrowingArrayUtils.append(mKeys, mSize, key); mValues = GrowingArrayUtils.append(mValues, mSize, value); mSize++; } /** * {@inheritDoc} * *

This implementation composes a string by iterating over its mappings. If * this map contains itself as a value, the string "(this Map)" * will appear in its place. * */ @Override public String toString() { if (size() <= 0) { return "{}"; } StringBuilder buffer = new StringBuilder(mSize * 28); buffer.append('{'); for (int i=0; i 0) { buffer.append(", "); } int key = keyAt(i); buffer.append(key); buffer.append('='); Object value = valueAt(i); if (value != this) { buffer.append(value); } else { buffer.append("(this Map)"); } } buffer.append('}'); return buffer.toString(); } } /** * Inserts an element into the array at the specified index, growing the array if there is no * more room. * * @param array The array to which to append the element. Must NOT be null. * @param currentSize The number of elements in the array. Must be less than or equal to * array.length. * @param element The element to insert. * @return the array to which the element was appended. This may be different than the given * array. * 向数组中插入数据 */ public static T[] insert(T[] array, int currentSize, int index, T element) { assert currentSize <= array.length; if (currentSize + 1 <= array.length) { System.arraycopy(array, index, array, index + 1, currentSize - index); array[index] = element; return array; } @SuppressWarnings("unchecked") T[] newArray = ArrayUtils.newUnpaddedArray((Class)array.getClass().getComponentType(), growSize(currentSize)); System.arraycopy(array, 0, newArray, 0, index); newArray[index] = element; System.arraycopy(array, index, newArray, index + 1, array.length - index); return newArray; }

你可能感兴趣的:(SparseArray根据源码简单分析)