안드로이드 성능 최적화는 SparseArray를 사용하여 2013년 08월 01일android가 최근에 원 프로젝트를 재구성하였는데, 그 중에서HashMap으로ActivityGroup 불러오기를 캐시합니다

52005 단어
최근에 원 프로젝트를 재구성했는데 Activity Group이 불러온 뷰를 HashMap으로 캐시했습니다. Eclipse는 경고를 했습니다. 프로젝트 진행을 고려해 별로 신경 쓰지 않았는데 이번에는 힌트를 자세히 봤습니다. 아래와 같습니다.
Use new SparseArray<View> (...) instead for better performance

더 나은 성능을 얻기 위해 SparseArray로 대체한다는 뜻이다.SparseArray에 대해 전혀 익숙하지 않고 심지어 들어보지도 못했다. 첫 번째 느낌은 안드로이드가 제공하는 클래스일 것이다. 그래서 F3가 SparseArray의 원본에 들어갔는데 아니나 다를까 안드로이드가 제공하는 도구 클래스였다. 일부 원본은 다음과 같다.
* Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.util;

import com.android.internal.util.ArrayUtils;

/**
 * SparseArrays map integers to Objects. Unlike a normal array of Objects,
 * there can be gaps in the indices. It is intended to be more efficient
 * than using a HashMap to map Integers to Objects.
 */
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.
 */
    public SparseArray(int initialCapacity) {
        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 = binarySearch(mKeys, 0, 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 = binarySearch(mKeys, 0, 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;
        }
    }
    ...
mSize++;         ,SparseArray       (Sparse array),                       (    ),              。           ,        ,              ,                       。

계속해서 SparseArray의 원본 코드를 읽습니다. 구성 방법을 보면 일반적인 List와 마찬가지로 용기 크기를 미리 설정할 수 있습니다. 기본 크기는 10입니다.
public SparseArray() {
    this(10);
}

public SparseArray(int initialCapacity) {
    initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);

    mKeys = new int[initialCapacity];
    mValues = new Object[initialCapacity];
    mSize = 0;
}

데이터에 대한 추가 삭제와 수정을 다시 한 번 봅시다.
public void put(int key, E value) {}
public void append(int key, E value){}

수정 데이터는 처음에 setValueAt(int index, E value)만 수정할 수 있다고 생각했지만put(int key, E value)도 데이터를 수정할 수 있는 것으로 알았습니다.put(int key, E value)의 원본 코드를 보면 put 데이터가 존재하는지 확인하고put 데이터가 존재하지 않으면 추가하는 것을 알 수 있습니다.
public void put(int key, E value) {
    int i = binarySearch(mKeys, 0, 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 = ~binarySearch(mKeys, 0, 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;
    
    }
}

따라서 데이터를 수정하는 방법에는 실제로 두 가지가 있습니다.
public void put(int key, E value)
public void setValueAt(int index, E value)

마지막으로 데이터를 어떻게 찾는지 다시 봅시다.두 가지 방법으로 값을 질의할 수 있습니다.
public E get(int key)
public E get(int key, E valueIfKeyNotFound)

그 중에서 get (int key) 도 get (int key, E value If Key Not Found) 을 호출했을 뿐, 마지막으로 인용된 변수 이름에서 알 수 있듯이, 전송된 값은 찾을 수 없을 때 되돌아오는 값이다.get (int key) 을 찾을 수 없을 때 기본값으로null을 되돌려줍니다.
몇 번째 위치의 키를 보려면 다음과 같이 하십시오.
public int keyAt(int index)

한 가지 주의해야 할 것은 키가 있는 위치를 확인하는 것이다. 이분법으로 키의 위치를 찾기 때문에 0보다 작은 수치를 찾을 수 없고 -1을 되돌릴 수 없다.되돌아오는 마이너스는 그것이 찾을 수 없는 위치를 표시하는 것이다.
몇 번째 위치의 값을 보려면 다음과 같이 하십시오.
public E valueAt(int index)

값이 있는 위치를 보고 없으면 -1을 반환합니다.
public int indexOfValue(E value)

마지막으로 그 핵심은 반절 검색 함수(binary Search)라는 것을 발견했고 알고리즘은 잘 설계되었다.
private static int binarySearch(int[] a, int start, int len, int key) {
    int high = start + len, low = start - 1, guess;

    while (high - low &gt; 1) {
        guess = (high + low) / 2;

        if (a[guess] &lt; key)
            low = guess;
        else
            high = guess;
    }

    if (high == start + len)
        return ~(start + len);
    else if (a[high] == key)
        return high;
    else
        return ~high;
}

     SparseBooleanArrayHashMap<Integer, Boolean>SparseIntArray    HashMap<Integer, Integer>,          。

총결산
SparseArray android  <Interger,Object>   Hashmap      ,       ,          (binarySearch)。 Android
    HashMap<Integer, E> hashMap = new HashMap<Integer, E>();
.
    SparseArray<E> sparseArray = new SparseArray<E>();

마지막으로 재구성된 Activity GroupManager를 살펴보겠습니다.
public class ActivityGroupManager {
    static final String TAG = ActivityGroupManager.class.getName();

    private SparseArray<View> array;
    private ViewGroup container;

    public ActivityGroupManager() {
    	array = new SparseArray<View>();
    }

    public void setContainer(ViewGroup container) {
    	this.container = container;
    }

    public void showContainer(int num, View view) {
    	if (array.get(num) == null) {
    		array.put(num, view);
    		container.addView(view);
    	}
    	for (int i = 0; i < array.size(); i++) {
    		View v = array.valueAt(i);
    		v.setVisibility(View.GONE);
    	}
    	view.setVisibility(View.VISIBLE);
    }
}

좋은 웹페이지 즐겨찾기