一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務(wù)器之家 - 編程語(yǔ)言 - JAVA教程 - 深入分析Android系統(tǒng)中SparseArray的源碼

深入分析Android系統(tǒng)中SparseArray的源碼

2019-12-31 14:37低調(diào)小一 JAVA教程

這篇文章主要介紹了深入分析Android系統(tǒng)中SparseArray的源碼,SparseArray為Java實(shí)現(xiàn),需要的朋友可以參考下

前言
昨晚想在Android應(yīng)用中增加一個(gè)int映射到String的字典表,使用HashMap實(shí)現(xiàn)的時(shí)候,Eclipse給出了一個(gè)警告,昨晚項(xiàng)目上線緊張,我直接給忽略了,今天看了一下具體的Eclipse提示如下:

?
1
Use new SparseArray<String> (...) instead for better performance

這個(gè)警告的意思是使用SparseArray來(lái)替代,以獲取更好的性能。

源碼
因?yàn)镾parseArray整體代碼比較簡(jiǎn)單,先把源碼展示出來(lái),然后再分析為什么使用SparseArray會(huì)比使用HashMap有更好的性能。

   

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
public class SparseArray<E> implements Cloneable {
    private static final Object DELETED = new Object();
    private boolean mGarbage = false;
   
    private int[] mKeys;
    private Object[] mValues;
    private int mSize;
   
    /**
     * Creates a new SparseArray containing no mappings.
     */
    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 = ContainerHelpers.EMPTY_INTS;
        mValues = ContainerHelpers.EMPTY_OBJECTS;
      } else {
        initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
        mKeys = new int[initialCapacity];
        mValues = new Object[initialCapacity];
      }
      mSize = 0;
    }
   
    @Override
    @SuppressWarnings("unchecked")
    public SparseArray<E> clone() {
      SparseArray<E> clone = null;
      try {
        clone = (SparseArray<E>) 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 <code>null</code>
     * if no such mapping has been made.
     */
    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.
     */
    @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.
     */
    public void delete(int key) {
      int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
   
      if (i >= 0) {
        if (mValues[i] != DELETED) {
          mValues[i] = DELETED;
          mGarbage = true;
        }
      }
    }
   
    /**
     * Alias for {@link #delete(int)}.
     */
    public void remove(int key) {
      delete(key);
    }
   
    /**
     * Removes the mapping at the specified index.
     */
    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
     */
    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) {
        mValues[i] = value;
      } else {
        i = ~i;
   
        if (i < mSize && mValues[i] == DELETED) {
          mKeys[i] = key;
          mValues[i] = value;
          return;
        }
   
        if (mGarbage && mSize >= mKeys.length) {
          gc();
   
          // Search again because indices may have changed.
          i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
        }
   
        if (mSize >= mKeys.length) {
          int n = ArrayUtils.idealIntArraySize(mSize + 1);
   
          int[] nkeys = new int[n];
          Object[] nvalues = new Object[n];
   
          // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
          System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
          System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
   
          mKeys = nkeys;
          mValues = nvalues;
        }
   
        if (mSize - i != 0) {
          // Log.e("SparseArray", "move " + (mSize - i));
          System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
          System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
        }
   
        mKeys[i] = key;
        mValues[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 <code>0...size()-1</code>, returns
     * the key from the <code>index</code>th key-value mapping that this
     * SparseArray stores.
     *
     * <p>The keys corresponding to indices in ascending order are guaranteed to
     * be in ascending order, e.g., <code>keyAt(0)</code> will return the
     * smallest key and <code>keyAt(size()-1)</code> will return the largest
     * key.</p>
     */
    public int keyAt(int index) {
      if (mGarbage) {
        gc();
      }
   
      return mKeys[index];
    }
   
    /**
     * Given an index in the range <code>0...size()-1</code>, returns
     * the value from the <code>index</code>th key-value mapping that this
     * SparseArray stores.
     *
     * <p>The values corresponding to indices in ascending order are guaranteed
     * to be associated with keys in ascending order, e.g.,
     * <code>valueAt(0)</code> will return the value associated with the
     * smallest key and <code>valueAt(size()-1)</code> will return the value
     * associated with the largest key.</p>
     */
    @SuppressWarnings("unchecked")
    public E valueAt(int index) {
      if (mGarbage) {
        gc();
      }
   
      return (E) mValues[index];
    }
   
    /**
     * Given an index in the range <code>0...size()-1</code>, sets a new
     * value for the <code>index</code>th key-value mapping that this
     * SparseArray stores.
     */
    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.
     */
    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.
     * <p>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.
     * <p>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;
    }
   
    /**
     * 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.
     */
    public void append(int key, E value) {
      if (mSize != 0 && key <= mKeys[mSize - 1]) {
        put(key, value);
        return;
      }
   
      if (mGarbage && mSize >= mKeys.length) {
        gc();
      }
   
      int pos = mSize;
      if (pos >= mKeys.length) {
        int n = ArrayUtils.idealIntArraySize(pos + 1);
   
        int[] nkeys = new int[n];
        Object[] nvalues = new Object[n];
   
        // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
        System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
        System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
   
        mKeys = nkeys;
        mValues = nvalues;
      }
   
      mKeys[pos] = key;
      mValues[pos] = value;
      mSize = pos + 1;
    }
   
    /**
     * {@inheritDoc}
     *
     * <p>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<mSize; i++) {
        if (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();
    }
  }


首先,看一下SparseArray的構(gòu)造函數(shù):

   

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
  * Creates a new SparseArray containing no mappings.
  */
 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 = ContainerHelpers.EMPTY_INTS;
     mValues = ContainerHelpers.EMPTY_OBJECTS;
   } else {
     initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
     mKeys = new int[initialCapacity];
     mValues = new Object[initialCapacity];
   }
   mSize = 0;
 }

從構(gòu)造方法可以看出,這里也是預(yù)先設(shè)置了容器的大小,默認(rèn)大小為10。

再來(lái)看一下添加數(shù)據(jù)操作:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/**
 * 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) {
    mValues[i] = value;
  } else {
    i = ~i;
 
    if (i < mSize && mValues[i] == DELETED) {
      mKeys[i] = key;
      mValues[i] = value;
      return;
    }
 
    if (mGarbage && mSize >= mKeys.length) {
      gc();
 
      // Search again because indices may have changed.
      i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
    }
 
    if (mSize >= mKeys.length) {
      int n = ArrayUtils.idealIntArraySize(mSize + 1);
 
      int[] nkeys = new int[n];
      Object[] nvalues = new Object[n];
 
      // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
      System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
      System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
 
      mKeys = nkeys;
      mValues = nvalues;
    }
 
    if (mSize - i != 0) {
      // Log.e("SparseArray", "move " + (mSize - i));
      System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
      System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
    }
 
    mKeys[i] = key;
    mValues[i] = value;
    mSize++;
  }
}


再看查數(shù)據(jù)的方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
 * Gets the Object mapped from the specified key, or <code>null</code>
 * if no such mapping has been made.
 */
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.
 */
@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];
  }
}


可以看到,在put數(shù)據(jù)和get數(shù)據(jù)的過(guò)程中,都統(tǒng)一調(diào)用了一個(gè)二分查找算法,其實(shí)這也就是SparseArray能夠提升效率的核心。

   

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static int binarySearch(int[] array, int size, int value) {
   int lo = 0;
   int hi = size - 1;
  
   while (lo <= hi) {
     final int mid = (lo + hi) >>> 1;
     final int midVal = array[mid];
  
     if (midVal < value) {
       lo = mid + 1;
     } else if (midVal > value) {
       hi = mid - 1;
     } else {
       return mid; // value found
     }
   }
   return ~lo; // value not present
 }

個(gè)人認(rèn)為(lo + hi) >>> 1的方法有些怪異,直接用 lo + (hi - lo) / 2更好一些。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: ts人妖另类国产 | 四虎影库紧急大通知 | 69日本xxxxxxxxx98| 久久青草免费91线频观看站街 | 国产欧美精品专区一区二区 | 久久精品视频免费 | 日本一片免费观看高清完整 | 草草在线免费视频 | 国产欧美日韩精品高清二区综合区 | 国产伦精品一区二区三区女 | 日韩一区二区三区四区不卡 | 亚洲精品二三区伊人久久 | 污软件在线观看 | 香蕉在线精品亚洲第一区 | 欧美日韩精品一区二区三区视频在线 | 午夜福利试看120秒体验区 | 国产在线一区二区杨幂 | 爽爽影院免费观看 | 亚洲欧美国产另类视频 | 久久AV喷吹AV高潮欧美 | 天天爽天天干天天操 | 成人高清网站 | 国产精品51麻豆cm传媒 | 大学第一次基本都没了 | 小小水蜜桃视频高清在线观看免费 | 国产农村乱子伦精品视频 | 欧美另类videos另类粗暴 | 日本一区二区视频在线 | 狠狠搞视频 | 精品久久久久久久久久香蕉 | 桥本有菜在线四虎福利网 | 色伦网| 交换年轻夫妇HD中文字幕 | 成人青青草 | 亚洲男人的天堂网站 | 91精品国产综合久久福利 | 狠狠色狠狠色综合日日小蛇 | 亚洲国产精品综合一区在线 | 毛片免费视频观看 | 亚洲国产欧美在线人成aaa | 情缘1完整版在线观看 |