Android Bundle--ArrayMap详解
Android 四大組件:Activity、Service、ContentProvider、Broadcast Receiver。
在Android App開發中,跟UI相關使用的最多的莫過于Activity了。
一個Activity 啟動另一個Activity時,可以使用Intent,其包含了一組方法方便攜帶一些參數:
1、MainActivity中包含一個按鈕,點擊打開DetailActivity:
public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);View detailBtn = findViewById(R.id.detail_btn);detailBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {onDetailBtnClick();}});}private void onDetailBtnClick() {Intent intent = new Intent(this, DetailActivity.class);//傳參intent.putExtra(ExtraKeyConstans.NAME, "CXC");intent.putExtra(ExtraKeyConstans.AGE, 22);/*//傳參Bundle extras = new Bundle();extras.putString(ExtraKeyConstans.NAME, "CXC");extras.putInt(ExtraKeyConstans.AGE, 22);intent.putExtras(extras);*/startActivity(intent);} }2、DetailActivity中僅包含一個DetailFragment,將從MainActivity中攜帶的參數傳入其中(直接透傳)。
public class DetailActivity extends AppCompatActivity {private static final String TAG = "DetailActivity";private static final String TAG_DETAIL_FRAGMENT = "detailFragmentTag";@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_detail);Intent intent = getIntent();//獲取參數/*//方式一:逐一獲取,并傳給FragmentString tUserName = intent == null ? "" : intent.getStringExtra(ExtraKeyConstans.NAME);int tUserAge = intent == null ? -1 : intent.getIntExtra(ExtraKeyConstans.AGE, -1);DetailFragment detailFragment = DetailFragment.newInstance(tUserName, tUserAge);Log.d(TAG, "-->onCreate()--tUserName:" + tUserName);Log.d(TAG, "-->tUserAge()--tUserAge:" + tUserName);*///方式二:不獲取,僅透傳給Fragment//如果所傳入的數據對當前Activity無用,直接透傳即可Bundle bundle = intent == null ? null : intent.getExtras();DetailFragment detailFragment = DetailFragment.newInstance(bundle);FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();fragmentTransaction.add(R.id.fragment_container,detailFragment,TAG_DETAIL_FRAGMENT);fragmentTransaction.commitAllowingStateLoss();} }在DetailFragment中獲取該參數并Log輸出:
public class DetailFragment extends Fragment {private static final String TAG = "DetailFragment";private String userName;private int userAge;public static DetailFragment newInstance(String userName, int userAge) {Bundle args = new Bundle();args.putString(ExtraKeyConstans.NAME, userName);args.putInt(ExtraKeyConstans.AGE, userAge);Log.d(TAG, "-->newInstance(String userName=" + userName + ", int userAge=" + userAge + ")--");return newInstance(args);}public static DetailFragment newInstance(Bundle args) {DetailFragment fragment = new DetailFragment();fragment.setArguments(args);Log.d(TAG, "-->newInstance(Bundle args=" + args + ")--");return fragment;}@Overridepublic void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);Bundle args = getArguments();if (args != null) {userName = args.getString(ExtraKeyConstans.NAME);userAge = args.getInt(ExtraKeyConstans.AGE);}Log.d(TAG, "-->onCreate()--userName=" + userName + ",userAge=" + userAge);}@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {return inflater.inflate(R.layout.fragment_detail, container, false);} }?
private Bundle mExtras;public @NonNull Intent putExtra(String name, String value) {if (mExtras == null) {mExtras = new Bundle();}mExtras.putString(name, value);return this;}public String getStringExtra(String name) {return mExtras == null ? null : mExtras.getString(name);}public @NonNull Intent putExtras(@NonNull Bundle extras) {if (mExtras == null) {mExtras = new Bundle();}mExtras.putAll(extras);return this;}public @Nullable Bundle getExtras() {return (mExtras != null)? new Bundle(mExtras): null;}存取數據均跟Bundle 類型的mExtras有關,聲明與方法如下:
/*** A mapping from String keys to various {@link Parcelable} values.** @see PersistableBundle*/ public final class Bundle extends BaseBundle implements Cloneable, Parcelable public void putString(@Nullable String key, @Nullable String value) {unparcel();mMap.put(key, value);}public String getString(@Nullable String key) {unparcel();final Object o = mMap.get(key);try {return (String) o;} catch (ClassCastException e) {typeWarning(key, o, "String", e);return null;}}而在Bundle中,數據存取跟ArrayMap<String,Object> mMap有關,所以,最終數據存取都跟這個mMap相關。
ArrayMap是Android平臺提供的一個與HashMap功能類似的容器類,聲明如下:
package android.util;public final class ArrayMap<K, V> implements Map<K, V>{int[] mHashes;//an integer array of hash codes for each itemObject[] mArray;//an Object array of the key/value pairs..... }其內部有兩個數組:int[] mHashes; Object[] mArray;
int[] mHashes:contains the hashes of the given keys in sorted order.?
Object[] mArray:stores key/value pairs according to the ordering of the "mHashes" array.
其中put和get方法如下:
/*** Retrieve a value from the array.* @param key The key of the value to retrieve.* @return Returns the value associated with the given key,* or null if there is no such key.*/@Overridepublic V get(Object key) {final int index = indexOfKey(key);return index >= 0 ? (V)mArray[(index<<1)+1] : null;}/*** Add a new value to the array map.* @param key The key under which to store the value. If* this key already exists in the array, its value will be replaced.* @param value The value to store for the given key.* @return Returns the old value that was stored for the given key, or null if there* was no such key.*/@Overridepublic V put(K key, V value) {final int hash;int index;if (key == null) {hash = 0;index = indexOfNull();} else {hash = mIdentityHashCode ? System.identityHashCode(key) : key.hashCode();index = indexOf(key, hash);}//key已經存在,則直接修改mArray中相應位置的值,并返回舊值。if (index >= 0) {index = (index<<1) + 1;final V old = (V)mArray[index];mArray[index] = value;return old;}//key不存在,根據indexOf返回的位置,將該key對應的hash存入mHashes并將key/values存入mArray中。index = ~index;if (mSize >= mHashes.length) {final int n = mSize >= (BASE_SIZE*2) ? (mSize+(mSize>>1)): (mSize >= BASE_SIZE ? (BASE_SIZE*2) : BASE_SIZE);if (DEBUG) Log.d(TAG, "put: grow from " + mHashes.length + " to " + n);final int[] ohashes = mHashes;final Object[] oarray = mArray;allocArrays(n);if (mHashes.length > 0) {if (DEBUG) Log.d(TAG, "put: copy 0-" + mSize + " to 0");System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length);System.arraycopy(oarray, 0, mArray, 0, oarray.length);}freeArrays(ohashes, oarray, mSize);}if (index < mSize) {if (DEBUG) Log.d(TAG, "put: move " + index + "-" + (mSize-index)+ " to " + (index+1));System.arraycopy(mHashes, index, mHashes, index + 1, mSize - index);System.arraycopy(mArray, index << 1, mArray, (index + 1) << 1, (mSize - index) << 1);}mHashes[index] = hash;mArray[index<<1] = key;mArray[(index<<1)+1] = value;mSize++;return null;}/*** Returns the index of a key in the set.** @param key The key to search for.* @return Returns the index of the key if it exists, else a negative integer.*/public int indexOfKey(Object key) {return key == null ? indexOfNull(): indexOf(key, mIdentityHashCode ? System.identityHashCode(key) : key.hashCode());}int indexOf(Object key, int hash) {final int N = mSize;// Important fast case: if nothing is in here, nothing to look for.if (N == 0) {return ~0;}//根據key的hash值在mHashes里進行二分查找int index = ContainerHelpers.binarySearch(mHashes, N, hash);// If the hash code wasn't found, then we have no entry for this key.if (index < 0) {return index;}//mArray[index*2]存儲的值與要查找的key相等,則返回該位置,//否則,則表示發生了沖突。// If the key at the returned index matches, that's what we want.if (key.equals(mArray[index<<1])) {return index;}//發生沖突后,則正序遍歷mHashes的(index,N)部分,//如果某個位置存儲的值與hash值相等并且mArray中相應位置與要查找的key相等,則返回該位置。// Search for a matching key after the index.int end;for (end = index + 1; end < N && mHashes[end] == hash; end++) {if (key.equals(mArray[end << 1])) return end;}//再逆序遍歷mHashes的[0,index)部分。// Search for a matching key before the index.for (int i = index - 1; i >= 0 && mHashes[i] == hash; i--) {if (key.equals(mArray[i << 1])) return i;}// Key not found -- return negative value indicating where a// new entry for this key should go. We use the end of the// hash chain to reduce the number of array entries that will// need to be copied when inserting.return ~end;}?
?
此外,在put操作時可能會進行相應的擴容操作,而在remove操作中可能會進行相應的縮容操作,這些操作可以減少內存的占用量以提高內存利用率。
由于其采用二分查找在數組上進行插入/刪除操作,并且在增/刪操作時可能會擴容/縮容操作(重新分配一個新的數組,并將原有數據復制進行),所以對于增/刪操作頻繁的場景不宜采用ArrayMap。
<1>ArrayMap is a generic key->value mapping data structure that is designed to be more memory efficient than a traditional java.util.HashMap.
<2>Note that this implementation is not intended to be appropriate for data structures that may contain large numbers of items.
<3>For better balance memory use,it will shrink its array as items are removed from it.
綜上:
在Activity間或者Activity與Fragment間傳遞數據,數據量一般很小,并且大部分操作是讀取操作(增/刪操作較少)所以采用ArrayMap更合適。
github地址:https://github.com/cxcbupt/FullscreenDemo
Refence:
Fun with ArrayMaps (Android Performance Patterns Season 3 ep1)
總結
以上是生活随笔為你收集整理的Android Bundle--ArrayMap详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android Platform Cod
- 下一篇: Android Studio: Debu