当我们声明并实例化一个HashMap的时候,会出现如下提示:

系统建议我们用SparseArray来代替HashMap,都说SparseArray性能优于HashMap,那我们就来做个示例,用直观的数据来对比一下二者的性能。
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private HashMap<Integer,byte[]> mMap = new HashMap<>(16);
private SparseArray<byte[]> mSparseArray = new SparseArray<>(16);
private int mCount = 100*1000;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn_map_memory).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0;i < mCount;i++){
mMap.put(i,new byte[10]);
}
Log.i(TAG,"HashMap memory click...");
}
}).start();
}
});
findViewById(R.id.btn_sparsearray_memory).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0;i < mCount;i++){
mSparseArray.put(i,new byte[10]);
}
Log.i(TAG,"SparseArray memory click...");
}
}).start();
}
});
findViewById(R.id.btn_map_time).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
long start = System.currentTimeMillis();
for (int i = 0;i < mCount;i++){
mMap.get(i);
}
long current = System.currentTimeMillis();
Log.i(TAG,"HashMap time test:" + (current - start));
}
}).start();
}
});
findViewById(R.id.btn_sparsearray_time).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
long start = System.currentTimeMillis();
for (int i = 0;i < mCount;i++){
mSparseArray.get(i);
}
long current = System.currentTimeMillis();
Log.i(TAG,"SparseArray time test:" + (current - start));
}
}).start();
}
});
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<Button
android:id="@+id/btn_map_memory"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginBottom="10dp"
android:text="HashMap 测试内存"
/>
<Button
android:id="@+id/btn_sparsearray_memory"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginBottom="10dp"
android:text="SparseArray 测试内存"
/>
<Button
android:id="@+id/btn_map_time"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginBottom="10dp"
android:text="HashMap 测试时间"
/>
<Button
android:id="@+id/btn_sparsearray_time"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginBottom="10dp"
android:text="SparseArray 测试时间"
/>
</LinearLayout>
简单新建一个Activity,写4个button,分别用来测试HashMap和SparseArray消耗内存大小,以及遍历HashMap和SparseArray的全部值所需要的时间。这里总数量设置为10万个,HashMap和SparseArray的值都为byte类型的数组,测试两者内存时分别用for循环向里面添加对应的值,测试两者时间的时候分别遍历两者全部的值。
AndroidStudio给我们提供了一个非常好用的性能监测的工具——Profiler,我们可以用这个工具来监测二者占用内存。
运行demo:

可以看到,初始内存为5.5M,接下来,点击第一个按钮,测试HashMap里put10万个数据所占用内存:

可以看到,最终当内存稳定时,上升到13.2M,那么13.2-5.5 = 7.7M,说明HashMap占用7.7M内存。
紧接着点击第二个按钮,测试SparseArray里put10万个数据所占用内存:

可以看到,最终当内存稳定时,上升到17.3M,那么17.3 - 13.2 = 4.1M,说明SparseArray占用4.1M内存。一个7.7M,一个4.1M,将近一倍的差距。
好,从空间上,当数据量相同时,可以知道SparseArray比HashMap更节省内存,那么从时间上呢?
点击第三个和第四个按钮,看到Logcat输出如下日志:

同样是遍历10万个值,HashMap用掉了1373毫秒,而SparseArray只用掉了72毫秒,20倍的差距,可见速度上也是大大优于HashMap。
通过这样一个小demo,我们直观的感受到了从空间和时间上,SparseArray的性能都要优于HashMap。之后的文章,我们会从源码的角度,进一步分析,为什么SparseArray的性能要优于HashMap。