国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

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

服務器之家 - 編程語言 - JAVA教程 - 深入分析Android系統中SparseArray的源碼

深入分析Android系統中SparseArray的源碼

2019-12-31 14:37低調小一 JAVA教程

這篇文章主要介紹了深入分析Android系統中SparseArray的源碼,SparseArray為Java實現,需要的朋友可以參考下

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

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

這個警告的意思是使用SparseArray來替代,以獲取更好的性能。

源碼
因為SparseArray整體代碼比較簡單,先把源碼展示出來,然后再分析為什么使用SparseArray會比使用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的構造函數:

   

?
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;
 }

從構造方法可以看出,這里也是預先設置了容器的大小,默認大小為10。

再來看一下添加數據操作:

?
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++;
  }
}


再看查數據的方法:

?
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數據和get數據的過程中,都統一調用了一個二分查找算法,其實這也就是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
 }

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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 亚洲午夜精品 | 久久伊人国产 | 91精品国产视频 | 欧美美女爱爱 | 国产中文字幕一区 | 日韩成人在线影院 | 日本网站在线免费观看 | 欧美精品一二三 | 亚洲 精品 综合 精品 自拍 | 久久国产一区二区 | 免费成人高清在线视频 | 久久精彩 | 中文字字幕一区二区三区四区五区 | 精品久久久久久久久久久下田 | 成人黄色在线观看 | 日韩久久精品一区二区 | 久久久久久久久久久久久av | 欧美激情一区二区三区 | 一区二区在线电影 | 国产精品伦一区二区三级视频 | 97超碰免费 | 伊人福利视频 | 日本一区二区精品 | 色影视| yellow视频在线 | 精品久久久久久亚洲综合网 | 日韩在线视频观看 | 午夜久久乐 | 久久久高清 | 欧美一级在线观看 | 黄色美女网站在线观看 | 激情五月婷婷在线 | 视频一区中文字幕 | 日韩欧美精品在线 | 久久久xxx | 精品一区二区三区免费 | 精品久久久久久久久久久久久久 | 91国内精品久久 | 91视频免费观看 | 国产福利电影 | 欧美一级在线观看 |