In Android development, we use most of the Java API, such as HashMap this API, the usage is very high, but for Android this memory-sensitive mobile platform, many times the use of some Java API does not achieve better performance, Instead, it consumes more memory, so for Android, this mobile platform also introduces more of its own API, such as Sparsearray, Arraymap to replace the HashMap in some cases can bring better performance improvement.
Before introducing them, let's introduce the internal storage structure of HashMap and see why Sparsearray and Arraymap are recommended.
HashMap
HashMap internally uses an array with a default capacity of 16 to store data, and each element in the array is the head node of a linked list, so, more precisely, the HASHMAP internal storage structure is a ZIP structure using a hash table (array + linked list),
This method of storing data is called the Zipper method.
And each node is entry type, then what is entry? Let's take a look at the properties of entry in HashMap:
final K key;V value;final int hash;HashMapEntry<K, V> next;
From which we learned that entry stored content has key, value, hash value, and next next entry, then, these entry data are stored according to what rules? is by calculating the hash value of the element key, and then hashmap the array length to get the position of the element stored, the calculation formula is hash (key)%len, such as: suppose Hash (46) =14,hash () = 46, we take the remainder of Len separately, get
Hash (%16=14,hash)%16=14,hash (46)%16=14, so the three elements of key 14, 30, and 46 are stored in the position labeled 14 below the array, such as:
It can be seen that if there are more than one element of the hash value of key is the same, the latter element will not overwrite the previous element, but instead take a list of the way, the added elements added to the end of the list, thus resolving the hash conflict problem, Thus we know that the method of dealing with hash conflicts in HashMap is the chain address method, in which a knowledge point is added, and the methods of dealing with hash conflicts are as follows:
- Open Address Law
- Re-hash method
- Chain Address method
- Create a public overflow zone
Here, the point is, we know that the default storage size in HashMap is an array with a capacity of 16, so when we create a HashMap object, even if there are no elements inside it, we will give it a memory space, and When we put the data in the HashMap again, when a certain capacity limit is reached, this capacity will be expanded to meet such a relationship: The amount of data in HashMap > capacity * load factor, and hashmap The default load factor is 0.75), HashMap space will be expanded, and the expansion of the new space must be twice times the original, we can see the put () method has such a line of code:
int newCapacity = oldCapacity * 2;
So, the focus is this, as long as the capacity to meet the expansion conditions, HashMap space will be twice times the law to increase. If we have hundreds of thousands of, millions of data, then hashmap to store these data will continue to expand, and in this process also need to do hash operations, which will cause great consumption and waste of our memory space, and HashMap get the data by traversing entry[] Array to get the corresponding elements, when the data volume is very slow, so in Android, HashMap is the comparison of memory, we can use Sparsearray and arraymap in some cases instead of hashmap.
Sparsearray
Sparsearray is more memory-saving than HashMap, and performs better under certain conditions, mainly because it avoids the automatic boxing of keys (int to integer type), which is internally stored by two arrays of data, one store key, and the other stores value, In order to optimize performance, it also takes the data in a compressed way to represent the sparse array of data, thereby saving memory space, we can see from the source key and value are represented by an array:
private int[] mKeys; private Object[] mValues;
As we can see, Sparsearray can only store data of type int, and while Sparsearray is storing and reading data, it uses binary lookup method, we can look at:
public void put(int key, E value) { int i = ContainerHelpers.binarySearch(mKeys, mSize, key); ... } public E get(int key, E valueIfKeyNotFound) { int i = ContainerHelpers.binarySearch(mKeys, mSize, key); ... }
That is, when the put adds data, it uses the binary lookup method and the previous key to compare the size of the key of the currently added element, and then arrange it in order from small to large, so the sparsearray stored elements are arranged from small to large by the key value of the element.
And in the acquisition of data, but also using the binary search method to determine the location of the element, so, in the acquisition of data is very fast, faster than HashMap, because HashMap get the data through the entry[] array to get the corresponding elements.
Add data
public void put(int key, E value)
Delete data
public void remove(int key)
Or
public void delete(int key)
In fact, remove internally or by calling Delete to delete the data
Get Data
public E get(int key)
Or
public E get(int key, E valueIfKeyNotFound)
The method can set the value returned by default if key does not exist
Unique methods
In addition to this, Sparsearray provides two unique methods for more convenient data query:
Get the corresponding key:
public int keyAt(int index)
Get the corresponding value:
public E valueAt(int index)
Sparsearray Application Scenario:
Although Sparsearray performance is better, but because of its add, find, delete data need to do a binary search first, so in the case of large data volume, the performance is not obvious, will be reduced by at least 50%.
We can use Sparsearray instead of HashMap to meet the following two conditions:
- Small amount of data, preferably within thousand
- The key must be of type int, in which case the HashMap can be replaced with Sparsearray:
HashMap<Integer, Object> map = new HashMap<>();用SparseArray代替:SparseArray<Object> array = new SparseArray<>();
Arraymap
This API information can be said on the internet almost no, but the egg, can only read the document
Arraymap is a <key,value> Map data structure, it is designed to consider the memory optimization, internal is the use of two arrays for data storage, an array record key hash value, another array record value value, It is the same as Sparsearray, the key using the binary method to order from small to large, in addition, delete, find data is the first use of binary search method to get the corresponding index, and then through the index to add, find, delete and so on, so, Scenario and Sparsearray, if the data volume is relatively large, then its performance will degrade at least 50%.
Add data
public V put(K key, V value)
Get Data
public V get(Object key)
Delete data
public V remove(Object key)
Unique methods
Like Sparsearray, it has two more convenient ways to get data:
public K keyAt(int index)public V valueAt(int index)
Arraymap Application Scenarios
- Small amount of data, preferably within thousand
- Data structure type is map type
ArrayMap<Key, Value> arrayMap = new ArrayMap<>();
"Note": if we are to be compatible with the following versions of AIP19, then the imported package needs to be V4 package
import android.support.v4.util.ArrayMap;
Summary
Sparsearray and Arraymap are similar, which one to use?
Assuming that the amount of data is within thousand:
1, if the type of key has been determined to be of type int, then use Sparsearray, because it avoids the process of automatic boxing, if the key is a long type, it also provides a longsparsearray to ensure that the key is a long type of use
2. If the key type is a different type, use the Arraymap
Android Memory optimization (use Sparsearray and arraymap instead of HashMap)