導航:首頁 > 操作系統 > androidarraymap

androidarraymap

發布時間:2022-09-22 01:59:26

1. android arraymap與hashmap相比真的佔用內存小么

不一定,還是要看數據量。
相同情況下,一個定值,一個一次一次的取內存。

2. android simplearraymap 屬於哪個jar包

因為有的jar包已經封裝好了要寫的工具了,直接掉就可以。jar裡面確實不能包含res的資源文件,調用的時候會報錯「找不到資源」或「空指針」。現在一般的解決辦法在把項目打包成jar的時候不要勾選res資源文件打包。並且在自己的jar工程里寫一個類用來讀取res資源文件,然後將工程里的所有帶有R.id,R.layout之類的都用這個類去找資源。最後在要引用這個jar文件的工程中把屬於jar的資源文件復制到工程裡面。

3. 在Android開發中,有哪些好的內存優化方式

1. 使用更加輕量的數據結構

例如,我們可以考慮使用ArrayMap/SparseArray而不是HashMap等傳統數據結構。通常的HashMap的實現方式更加消耗內存,因為它需要一個額外的實例對象來記錄Mapping操作。另外,SparseArray更加高效,在於他們避免了對key與value的自動裝箱(autoboxing),並且避免了裝箱後的解箱。

2. 避免在Android裡面使用Enum

Android官方培訓課程提到過「Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.」,具體原理請參考《Android性能優化典範(三)》,所以請避免在Android裡面使用到枚舉。

3. 減小Bitmap對象的內存佔用

Bitmap是一個極容易消耗內存的大胖子,減小創建出來的Bitmap的內存佔用可謂是重中之重,,通常來說有以下2個措施:

inSampleSize:縮放比例,在把圖片載入內存之前,我們需要先計算出一個合適的縮放比例,避免不必要的大圖載入。

decode format:解碼格式,選擇ARGB_8888/RBG_565/ARGB_4444/ALPHA_8,存在很大差異

4.Bitmap對象的復用

縮小Bitmap的同時,也需要提高BitMap對象的復用率,避免頻繁創建BitMap對象,復用的方法有以下2個措施

LRUCache : 「最近最少使用演算法」在Android中有極其普遍的應用。ListView與GridView等顯示大量圖片的控制項里,就是使用LRU的機制來緩存處理好的Bitmap,把近期最少使用的數據從緩存中移除,保留使用最頻繁的數據,

inBitMap高級特性:利用inBitmap的高級特性提高Android系統在Bitmap分配與釋放執行效率。使用inBitmap屬性可以告知Bitmap解碼器去嘗試使用已經存在的內存區域,新解碼的Bitmap會嘗試去使用之前那張Bitmap在Heap中所佔據的pixel data內存區域,而不是去問內存重新申請一塊區域來存放Bitmap。利用這種特性,即使是上千張的圖片,也只會僅僅只需要佔用屏幕所能夠顯示的圖片數量的內存大小

4. 使用更小的圖片

在涉及給到資源圖片時,我們需要特別留意這張圖片是否存在可以壓縮的空間,是否可以使用更小的圖片。盡量使用更小的圖片不僅可以減少內存的使用,還能避免出現大量的InflationException。假設有一張很大的圖片被XML文件直接引用,很有可能在初始化視圖時會因為內存不足而發生InflationException,這個問題的根本原因其實是發生了OOM。

5.StringBuilder

在有些時候,代碼中會需要使用到大量的字元串拼接的操作,這種時候有必要考慮使用StringBuilder來替代頻繁的「+」。

6.避免在onDraw方法裡面執行對象的創建

類似onDraw等頻繁調用的方法,一定需要注意避免在這里做創建對象的操作,因為他會迅速增加內存的使用,而且很容易引起頻繁的gc,甚至是內存抖動。

7. 避免對象的內存泄露

類的靜態變數持有大數據對象

靜態變數長期維持到大數據對象的引用,阻止垃圾回收。

非靜態內部類存在靜態實例

非靜態內部類會維持一個到外部類實例的引用,如果非靜態內部類的實例是靜態的,就會間接長期維持著外部類的引用,阻止被回收掉。

資源對象未關閉

資源性對象比如(Cursor,File文件等)往往都用了一些緩沖,我們在不使用的時候,應該及時關閉它們, 以便它們的緩沖及時回收內存。它們的緩沖不僅存在於java虛擬機內,還存在於java虛擬機外。 如果我們僅僅是把它的引用設置為null,而不關閉它們,往往會造成內存泄露。

解決辦法: 比如SQLiteCursor(在析構函數finalize(),如果我們沒有關閉它,它自己會調close()關閉), 如果我們沒有關閉它,系統在回收它時也會關閉它,但是這樣的效率太低了。 因此對於資源性對象在不使用的時候,應該調用它的close()函數,將其關閉掉,然後才置為null. 在我們的程序退出時一定要確保我們的資源性對象已經關閉。 程序中經常會進行查詢資料庫的操作,但是經常會有使用完畢Cursor後沒有關閉的情況。如果我們的查詢結果集比較小, 對內存的消耗不容易被發現,只有在常時間大量操作的情況下才會復現內存問題,這樣就會給以後的測試和問題排查帶來困難和風險,記得try catch後,在finally方法中關閉連接

Handler內存泄漏

Handler作為內部類存在於Activity中,但是Handler生命周期與Activity生命周期往往並不是相同的,比如當Handler對象有Message在排隊,則無法釋放,進而導致本該釋放的Acitivity也沒有辦法進行回收。

4. android arraymap與hashmap相比真的佔用內存小么

HashMap簡介 綜述:HashMap 是一個散列表,它存儲的內容是鍵值對(key-value)映射。 1.HashMap 繼承於AbstractMap,實現了Map、Cloneable、java.io.Serializable介面。 2.HashMap 的實現不是同步的,這意味著它不是線程安全的。它的key、value都可以為null。此外,HashMap中的映射不是有序的。 3.HashMap 的實例有兩個參數影響其性能:「初始容量」 和 「載入因子」。容量 是哈希表中桶的數量,初始容量 只是哈希表在創建時的容量。載入因子 是哈希表在其容量自動增加之前可以達到多滿的一種尺度。當哈希表中的條目數超出了載入因子與當前容量的乘積時,則要對該哈希表進行 rehash 操作(即重建內部數據結構),從而哈希表將具有大約兩倍的桶數。 通常,默認載入因子是 0.75, 這是在時間和空間成本上尋求一種折衷。載入因子過高雖然減少了空間開銷,但同時也增加了查詢成本(在大多數 HashMap 類的操作中,包括 get 和 put 操作,都反映了這一點)。在設置初始容量時應該考慮到映射中所需的條目數及其載入因子,以便最大限度地減少 rehash 操作次數。如果初始容量大於最大條目數除以載入因子,則不會發生 rehash 操作。

5. Android開發中ArrayMap與HashMap有哪些不同

1、存儲方式不同

HashMap內部有一個HashMapEntry<K, V>[]對象,每一個鍵值對都存儲在這個對象里,當使用put方法添加鍵值對時,就會new一個HashMapEntry對象,具體實現如下:

[java] view plain
@Override public V put(K key, V value) {
if (key == null) {
return putValueForNullKey(value);
}

int hash = secondaryHash(key);
HashMapEntry<K, V>[] tab = table;
int index = hash & (tab.length - 1);
//先查找有沒有對應的key值,如果有,就改寫value,並返回改寫前的value值:oldValue
for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) {
if (e.hash == hash && key.equals(e.key)) {
preModify(e);
V oldValue = e.value;
e.value = value;
return oldValue;
}
}

// No entry for (non-null) key is present; create one
modCount++;
if (size++ > threshold) {
//擴容,雙倍
tab = doubleCapacity();
index = hash & (tab.length - 1);
}
addNewEntry(key, value, hash, index);
return null;
}
//創建對象存儲鍵值對
void addNewEntry(K key, V value, int hash, int index) {
table[index] = new HashMapEntry<K, V>(key, value, hash, table[index]);
}

ArrayMap的存儲中沒有Entry這個東西,他是由兩個數組來維護的
[java] view plain
int[] mHashes;
Object[] mArray;

mHashes數組中保存的是每一項的HashCode值,mArray中就是鍵值對,每兩個元素代表一個鍵值對,前面保存key,後面的保存value,我們看看下面代碼的結果:
[java] view plain
arraymap = new HashMap<String, String>();
a.put("a", "a_value");
a.put("b", "b_value");
執行上面代碼後,arraymap中的存儲是這樣的

是不是能清楚地看到ArrayMap的存儲了,這種存儲在put代碼中如下:

[java] view plain
mHashes[index] = hash;
mArray[index<<1] = key;
mArray[(index<<1)+1] = value;

2、添加數據時擴容時的處理不一樣

先來看看HashMap

[java] view plain
if (size++ > threshold) {
tab = doubleCapacity();
index = hash & (tab.length - 1);
}

doubleCapacity進行雙倍擴容,它的代碼中有這么一句話
[java] view plain
HashMapEntry<K, V>[] newTable = makeTable(newCapacity);

最終,這個newTable將作為擴容後的新對象返回,那麼makeTable做了什麼呢,如下:
[java] view plain
private HashMapEntry<K, V>[] makeTable(int newCapacity) {
@SuppressWarnings("unchecked") HashMapEntry<K, V>[] newTable
= (HashMapEntry<K, V>[]) new HashMapEntry[newCapacity];
table = newTable;
threshold = (newCapacity >> 1) + (newCapacity >> 2); // 3/4 capacity
return newTable;
}

我們清楚地看到,這里進行了new操作,重新創建對象,開銷很大。
那麼ArrayMap呢,看看:

[java] view plain
//如果容量不夠
ize >= 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: 0-" + mSize + " to 0");
//特別注意這,是,而不是new,效率提升
System.array(ohashes, 0, mHashes, 0, ohashes.length);
System.array(oarray, 0, mArray, 0, oarray.length);
}
//釋放無用空間,收縮數組
freeArrays(ohashes, oarray, mSize);
}

ArrayMap用的是數據,所以效率相對要高。

3、ArrayMap提供了數組收縮的功能,在clear或remove後,會重新收縮數組,是否空間

4、ArrayMap採用二分法查找;

以上就是android開發中,HashMap與ArrayMap的區別,大家在涉及到內存方面的實現,可根據實際情況選擇這兩種不同的方式。

6. 22 AndroidBroadcast廣播機制

廣播(Broadcast)機制用於進程/線程間通信,廣播分為廣播發送和廣播接收兩個過程,其中廣播接收者BroadcastReceiver便是Android四大組件之一。

BroadcastReceiver分為兩類:

從廣播發送方式可分為三類:

廣播在系統中以BroadcastRecord對象來記錄, 該對象有幾個時間相關的成員變數.

廣播注冊,對於應用開發來說,往往是在Activity/Service中調用 registerReceiver() 方法,而Activity或Service都間接繼承於Context抽象類,真正幹活是交給ContextImpl類。另外調用getOuterContext()可獲取最外層的調用者Activity或Service。

[ContextImpl.java]

其中broadcastPermission擁有廣播的許可權控制,scheler用於指定接收到廣播時onRecive執行線程,當scheler=null則默認代表在主線程中執行,這也是最常見的用法

[ContextImpl.java]

ActivityManagerNative.getDefault()返回的是ActivityManagerProxy對象,簡稱AMP.
該方法中參數有mMainThread.getApplicationThread()返回的是ApplicationThread,這是Binder的Bn端,用於system_server進程與該進程的通信。

[-> LoadedApk.java]

不妨令 以BroadcastReceiver(廣播接收者)為key,LoadedApk.ReceiverDispatcher(分發者)為value的ArrayMap 記為 A 。此處 mReceivers 是一個以 Context 為key,以 A 為value的ArrayMap。對於ReceiverDispatcher(廣播分發者),當不存在時則創建一個。

此處mActivityThread便是前面傳遞過來的當前主線程的Handler.

ReceiverDispatcher(廣播分發者)有一個內部類 InnerReceiver ,該類繼承於 IIntentReceiver.Stub 。顯然,這是一個Binder服務端,廣播分發者通過rd.getIIntentReceiver()可獲取該Binder服務端對象 InnerReceiver ,用於Binder IPC通信。

[-> ActivityManagerNative.java]

這里有兩個Binder服務端對象 caller 和 receiver ,都代表執行注冊廣播動作所在的進程. AMP通過Binder驅動將這些信息發送給system_server進程中的AMS對象,接下來進入AMS.registerReceiver。

[-> ActivityManagerService.java]

其中 mRegisteredReceivers 記錄著所有已注冊的廣播,以receiver IBinder為key, ReceiverList為value為HashMap。

在BroadcastQueue中有兩個廣播隊列mParallelBroadcasts,mOrderedBroadcasts,數據類型都為ArrayList<broadcastrecord style="box-sizing: border-box;">:</broadcastrecord>

mLruProcesses數據類型為 ArrayList<ProcessRecord> ,而ProcessRecord對象有一個IApplicationThread欄位,根據該欄位查找出滿足條件的ProcessRecord對象。

該方法用於匹配發起的Intent數據是否匹配成功,匹配項共有4項action, type, data, category,任何一項匹配不成功都會失敗。

broadcastQueueForIntent(Intent intent)通過判斷intent.getFlags()是否包含FLAG_RECEIVER_FOREGROUND 來決定是前台或後台廣播,進而返回相應的廣播隊列mFgBroadcastQueue或者mBgBroadcastQueue。

注冊廣播:

另外,當注冊的是Sticky廣播:

廣播注冊完, 另一個操作便是在廣播發送過程.

發送廣播是在Activity或Service中調用 sendBroadcast() 方法,而Activity或Service都間接繼承於Context抽象類,真正幹活是交給ContextImpl類。

[ContextImpl.java]

[-> ActivityManagerNative.java]

[-> ActivityManagerService.java]

broadcastIntent()方法有兩個布爾參數serialized和sticky來共同決定是普通廣播,有序廣播,還是Sticky廣播,參數如下:

broadcastIntentLocked方法比較長,這里劃分為8個部分來分別說明。

這個過程最重要的工作是:

BroadcastReceiver還有其他flag,位於Intent.java常量:

主要功能:

這個過主要處於系統相關的10類廣播,這里不就展開講解了.

這個過程主要是將sticky廣播增加到list,並放入mStickyBroadcasts裡面。

其他說明:

AMS.collectReceiverComponents

廣播隊列中有一個成員變數 mParallelBroadcasts ,類型為ArrayList<broadcastrecord style="box-sizing: border-box;">,記錄著所有的並行廣播。</broadcastrecord>

動態注冊的registeredReceivers,全部合並都receivers,再統一按串列方式處理。

廣播隊列中有一個成員變數 mOrderedBroadcasts ,類型為ArrayList<broadcastrecord style="box-sizing: border-box;">,記錄著所有的有序廣播。</broadcastrecord>

發送廣播過程:

處理方式:

可見不管哪種廣播方式,都是通過broadcastQueueForIntent()來根據intent的flag來判斷前台隊列或者後台隊列,然後再調用對應廣播隊列的scheleBroadcastsLocked方法來處理廣播;

在發送廣播過程中會執行 scheleBroadcastsLocked 方法來處理相關的廣播

[-> BroadcastQueue.java]

在BroadcastQueue對象創建時,mHandler=new BroadcastHandler(handler.getLooper());那麼此處交由mHandler的handleMessage來處理:

由此可見BroadcastHandler採用的是」ActivityManager」線程的Looper

[-> BroadcastQueue.java]

此處mService為AMS,整個流程還是比較長的,全程持有AMS鎖,所以廣播效率低的情況下,直接會嚴重影響這個手機的性能與流暢度,這里應該考慮細化同步鎖的粒度。

7. android arraymap與hashmap相比真的佔用內存小么

在認識hashmap中要先認識Map。在數組中我們是通過數組下標來對其內容索引的,而在Map中我們通過對象來對對象進行索引,用來索引的對象叫做key,其對應的對象叫做value。 HashMap的初始過程 :在並發環境下使用HashMap 而沒有做同步,可能會引起死循環,關於這一點,sun的官方網站上已有闡述,這並非是bug。 HashMap的數據結構 :HashMap主要是用數組來存儲數據的,我們都知道它會對key進行哈希運算,哈系運算會有重復的哈希值,對於哈希值的沖突,HashMap採用鏈表來解決的。在HashMap里有這樣的一句屬性聲明: transient Entry[] table; 因此hashmap可以在andriod中用來存儲數據。

8. 內存優化之ArrayMap、SparseArray、SparseIntArray

這幾個數據結構呢,都是Android這傢伙搞出來;為啥呢,打的旗號是節約內存,系統的很多地方都有他們的身影;為了追隨google的腳步,也為了擴展自己對於數據結構的理解,我們有必要學習它;

這里先大致說下,ArrayMap是一個map,是為了解決HashMap存儲數據浪費空間情況;SparseArray是數組,為稀疏數據准備的;SparseXXXArray,也是數組,也為稀疏數據准備,xxx是基本數據類型,這樣使用時不存在自動拆裝箱操作(就是基本類型和相對應類之間的自動轉換);SparseXXXArray的原理實現一致,這里只介紹SparseIntArray

ArrayMap結構

兩個數組來存儲;key的hash數據,key-value組成的數組;通過index來映射,2倍位置為key, 2倍位置+1 為value;mHashes數據,是從小到大有序存儲的

SparseArray結構

也是兩個數組,存儲數組索引的key,存儲數據value,通過相等索引來映射;mKeys是從小到大有序存儲的

從圖來看,我覺得是結構思想整體是一致的;但他們的實現思路還是存在不同的地方

這里key是可以為null,null是hash值為0,不為空時,其計算方式與下面變數有關,這個可以僅可以在構造器中設置,默認為false

計算區別如下:

由於是以hash來排序,如果使用默認,那麼我們的hashCode方法,要是每個對象固定,最好且是不同的

我們有必要先介紹以下,申請內存緩存機制,這涉及到下面兩個數組,其原理是一樣的,只是容量不同;

mBaseCache的容量大小為8, mTwiceBaseCache容量大小為16;兩個緩存每種最多緩存10個;緩存結構如下圖,入量按照8來繪制的:

這里的容量是申請的數組容量,數據存儲key-value,所以其能存儲的數據個數為其一半; 初始化、擴容都是根據存儲個數來計算的

初始化

擴容

調用下面兩個方法時,可能會擴容

數組的移動System.array方法處理,如果容器大小增加了,則廢棄的數組;廢棄的數組,進行回收,如果存儲容量大小為4或者8,會放入緩存中

查找可以插入或者替換數據的位置;查找思想:

查找位置為正整數,說明此處有數據,可替換,負整數,表示無數據且取非表示可插入位置

增加數據時,可能會擴容;如果數據未找到且容器存儲個數已滿,這時會進行擴容

刪除數據時,可能會進行容量縮減

如果你上面ArrayMap已經懂了,那麼SparseIntArray其實已經很簡單了;它存在下面的差異

SparseArray和SparseXXXArray那就更接近了;不過我們還是和ArrayMap做對比吧

和SparseXXXArray區別就是:無gc方法機制、存儲value值是類而不是基本數據

gc方法:如果有效數據前存在刪除數據標志值DELETED,則後面把有效數據往前移位

有沒有小夥伴在想,為何SparseXXXArray,沒有這種gc行為呢,因為基本類型,存什麼都無法標志其是無效數據啊;

技術變化都很快,但基礎技術、理論知識永遠都是那些;作者希望在余後的生活中,對常用技術點進行基礎知識分享;如果你覺得文章寫的不錯,請給與關注和點贊;如果文章存在錯誤,也請多多指教!

閱讀全文

與androidarraymap相關的資料

熱點內容
rf3148編程器 瀏覽:505
浙江標准網路伺服器機櫃雲主機 瀏覽:587
設置網路的伺服器地址 瀏覽:600
java圖形界面設計 瀏覽:751
純前端項目怎麼部署到伺服器 瀏覽:538
瓜子臉程序員 瀏覽:505
如何保證伺服器優質 瀏覽:94
小微信aPP怎麼一下找不到了 瀏覽:299
演算法纂要學術價值 瀏覽:975
程序員你好是什麼意思 瀏覽:801
倩女幽魂老伺服器如何玩 瀏覽:561
電子鍾單片機課程設計實驗報告 瀏覽:999
看加密頻道 瀏覽:381
程序員算不算流水線工人 瀏覽:632
三星電視我的app怎麼卸載 瀏覽:44
簡述vi編譯器的基本操作 瀏覽:507
讓程序員選小號 瀏覽:91
加強數字貨幣國際信息編譯能力 瀏覽:584
購買的app會員怎麼退安卓手機 瀏覽:891
程序員的種類及名稱 瀏覽:294