在数据量比较少的情况下使用SparseArray可以提高效率,最近一个项目利用它存储int型数据,利用indexOfValue去获取value的索引,本以为value大小范围可以是int的范围大小,结果不是,数据可以存储但是利用indexOfValue方法得到的索引就是不对返回-1检索不到,特别坑,当value范围是-128到127,indexOfValue才能得到正确的索引,查阅官方文档也没有找到原因,如果有大佬发现原因麻烦指出了,一起交流。解决这个问题可以用SparseIntArray代替,value的值是int的范围通过indexOfValue方法也能获得正确的索引。实验代码如下:
SparseArray abc = new SparseArray();
int gpuIndex = 0;
abc.put(gpuIndex++, 127);
abc.put(gpuIndex++, 128);
abc.put(gpuIndex++, -128);
int a, a1, a2;
a = a1 = a2 = Integer.MIN_VALUE;
a = abc.indexOfValue(127);
a1 = abc.indexOfValue(128);
a2 = abc.indexOfValue(-128);
Log.i("SparseArray", "SparseArrayIndex127: " + a);
Log.i("SparseArray", "SparseArrayIndex128: " + a1);
Log.i("SparseArray", "SparseArrayIndex-128: " + a2);
SparseIntArray def = new SparseIntArray();
int index = 0;
def.put(index++, 2147483647);
int b = def.indexOfValue(2147483647);
Log.i("SparseIntArray", "SparseIntArrayIndex: " + b);
输出的log日志为:
07-20 16:53:45.611: I/SparseArray(13173): SparseArrayIndex127: 0
07-20 16:53:45.611: I/SparseArray(13173): SparseArrayIndex128: -1
07-20 16:53:45.611: I/SparseArray(13173): SparseArrayIndex-128: 2
07-20 16:53:45.611: I/SparseIntArray(13173): SparseIntArrayIndex: 0
如果大佬知道原因还希望指出来一起讨论!
------------------------------------------------------------------2017.8.9更新----------------------------------------------------------------------------------------------
查看java的int的自动装箱机制发现了问题的原因,是由于自动装箱机制和“==”比较引起的
首先看一下SparseArray的indexOfValue方法源码
/**
* 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}.
*/
public int indexOfValue(E value) {
if (mGarbage) {
gc();
}
for (int i = 0; i < mSize; i++)
if (mValues[i] == value)
return i;
return -1;
}
注释已经提示了是利用“==”来进行比较,比较的是对象引用的地址,而传进来的类型E是是Integer的对象,我们知道在-128至127的数自动装箱时,获得的是同一个对象,而不在这个范围的自动装箱获得的是不同的对象,例子如下:
Integer num1 = 666; Integer num2 = 666; Integer num3 = 88; Integer num4 = 88;
System.out.println("num1==num2: "+(num1==num2));
System.out.println("num3==num4: "+(num3==num4));
输出结果:num1==num2: false num3==num4: true
所以indexOfValue(128)时,128自动装箱成Integer对象,利用“==”与原来put进去的128是不同的对象,所以检索不到,返回-1;
再看SparseIntArray的indexOfValue源码:
/**
* 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.
*/
public int indexOfValue(int value) {
for (int i = 0; i < mSize; i++)
if (mValues[i] == value)
return i;
return -1;
}
用的也是“==”,但是比较的类型是基本数据类型int,而不是Integer对象,所以能够检索到之前的数据。问题根源解决!
------------------------------------------------------------------------------------------------------------------------------------------------
后记:细节决定成败啊