對Android中的堆棧的理解(Stack)

             堆棧空間分配
棧(操作系統):由操作系統自動分配釋放 ,存放函數的參數值局部變量的值等。其操作方式類似於數據結構中的棧。
堆(操作系統): 一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收,分配方式倒是類似於鏈表。

堆棧緩存方式

棧使用的是一級緩存, 他們通常都是被調用時處於存儲空間中,調用完畢立即釋放。
堆則是存放在二級緩存中,生命週期由虛擬機的垃圾回收算法來決定(並不是一旦成爲孤兒對象就能被回收)。所以調用這些對象的速度要相對來得低一些

Stack

         棧(stack)在計算機科學中是限定僅在表尾進行插入或刪除操作的線性表。棧是一種數據結構,它按照後進先出的原則存儲數據,先進入的數據被壓入棧底,最後的數據在棧頂,需要讀數據的時候從棧頂開始彈出數據。棧是只能在某一端插入和刪除的特殊線性表。用桶堆積物品,先堆進來的壓在底下,隨後一件一件往上堆。取走時,只能從上面一件一件取。讀和取都在頂部進行,底部一般是不動的。棧就是一種類似桶堆積物品的數據結構,進行刪除和插入的一端稱棧頂,另一端稱棧底。插入一般稱爲進棧,刪除則稱爲退棧。 棧也稱爲後進先出表。

      Heap

    堆(heap)又被爲優先隊列(priority queue)。儘管名爲優先隊列,但堆並不是隊列。回憶一下,在隊列中,我們可以進行的限定操作是dequeue和enqueue。dequeue是按照進入隊列的先後順序來取出元素。而在堆中,我們不是按照元素進入隊列的先後順序取出元素的,而是按照元素的優先級取出元素。

這就好像候機的時候,無論誰先到達候機廳,總是頭等艙的乘客先登機,然後是商務艙的乘客,最後是經濟艙的乘客。每個乘客都有頭等艙、商務艙、經濟艙三種個鍵值(key)中的一個。頭等艙->商務艙->經濟艙依次享有從高到低的優先級。

   Android 之活動任務堆棧




java.lang.Object
  java.util.AbstractCollection<E>
      java.util.AbstractList<E>
          java.util.Vector<E>
              java.util.Stack<E>
所有已實現的接口:
Serializable,Cloneable, Iterable<E>, Collection<E>, List<E>, RandomAccess

public class Stack<E>
extends Vector<E>

Stack 類表示後進先出(LIFO)的對象堆棧。它通過五個操作對類 Vector 進行了擴展 ,允許將向量視爲堆棧。它提供了通常的pushpop 操作,以及取堆棧頂點的 peek 方法、測試堆棧是否爲空的 empty 方法、在堆棧中查找項並確定到堆棧頂距離的search 方法。

首次創建堆棧時,它不包含項。

Deque 接口及其實現提供了 LIFO 堆棧操作的更完整和更一致的 set,應該優先使用此 set,而非此類。例如:

   Deque<Integer> stack = new ArrayDeque<Integer>();


       如果你的應用中涉及到的東西比較耗內存的話,比如:相機、第三方地圖、騰訊、新浪、錄音、視頻播放、大量圖片時,如果這些東西同時存在於應用中時,會有很多奇怪的問題出現,自動退出還不報錯等等一系列的問題,還有,如果我們的應用中使用startActivity()過多而且並沒有及時finish()掉的話,也會出現這樣那樣的問題,比如:退出應用時沒有退出乾淨,或者莫名其妙的報OOM,啓動的服務自動掛起什麼的!       其實,Google已經提供了一套完整的機制讓開發人員控制活動棧與任務棧
        
像這樣的跳轉我們在開發的過程中算是很長見到的了,在這裏我就不貼代碼了 ,假如就是有三個活動窗口(Activity1,Activity2Activity3)按先後順序 從Activity1--startActivity()Activity2再到Activity3這個過程大家應該可以想象的到,在這個過程生成的活動堆棧如圖所示:

http://img1.51cto.com/attachment/201206/160525368.jpg

    這個地方說明下,有時候大家可以想着從1到2時可以綁定數據完成回顯,但是如果要簡單的回顯用綁定或startActivityForResult()這兩種方式啓動,但是如果涉及到三個以上的活動惑更多活動之間的跳轉時,有時候不得不必須重新啓動新的活動,也就出現了前面的1>>2>>3>>4>>>>>>>甚至更多的活動跳轉,這樣一個個關閉有時候還是關不乾淨,應用退出的時候也還是不乾淨的,更搞笑的是有時候還有用戶在多個活動之間跳轉並不進行任何數據操作時還要求返回上一個Activity時你就不能直接finish掉上一個Activity,不然人家說你跳轉不對,針對這個問題我們來看下Google提供的堆棧任務控制機制吧,很簡單,用Flag來控制,這個時候就有個問題,提供的方法有setFlag()、addFlag(),這兩個肯定有什麼區別的,不然不會出現兩個控制Flag的方法的

如果是點擊回退鍵的過程中也會有不一樣同樣點擊了六次按鈕之後按的返回鍵,第一種效果必須點擊六次Back鍵後方可退出,而第二種效果只點擊一次即可退出,這就是Flag的魅力,激動….再來看Flag都有哪幾種吧,此處我列在這個地方,上面兩個效果中設置的是:i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);另外還有很多可以控制活動堆棧與任務棧的Flag,小馬在這個地方隨便列出兩個,剩餘的Flag值以截圖的形式顯示,節約時間:

  1. i.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
  2. i.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)其它:

    

Activity和Task(棧)的關係

  Task就像一個容器,而Activity就相當與填充這個容器的東西,第一個東西(Activity)則會處於最下面,最後添加的東西(Activity)則會在最低端。從Task中取出東西(Activity)則是從最頂端取出。

  二、界面跳轉和服務的啓動都會用到Intent,現在介紹Intent Flag是關於Activity的跳轉
  Intent intent = new Intent(this,xxx.class);
  //如果activity在task存在,拿到最頂端,不會啓動新的Activity
  intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
  //如果activity在task存在,將Activity之上的所有Activity結束掉
  intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  //默認的跳轉類型,將Activity放到一個新的Task中
  intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  //如果Activity已經運行到了Task,再次跳轉不會在運行這個Activity
  intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

  大家可以很清楚的看到以後所含的標誌中有針對於TASK的,對吧?指的就是任務堆棧,至於什麼是任務堆棧,大家不用太過糾結於與活動堆棧之間的概念什麼的,只記住一點:如果你在應用中啓動Activity的時候沒加任務堆棧的控制Flag時,開發環境肯定報錯,而且提示的很準確 ,就是:你缺少添加任務堆棧Flag標誌位,具體少了哪個標誌,開發環境也會很準確的指出,必須要你添加纔可正常編譯通過!下面列下小馬犯的錯誤,就是在一個Activity找到一個amr錄音文件,直接以下面的方式啓動去播放錄音,猛報錯:

  1. Intent i = new Intent(Intent.ACTION_VIEW); 
  2.       i.putExtra("filePath",path); 
  3.      startActivity(i); 

       如果加了 i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);操作下任務堆棧就可以了,具體的原因,也可以用一句話來總結:如果在一個Activity中同一時間,要操作不用的功能,比如:跳轉時還要操作視頻錄音文件的播放什麼的,都得設置新的任務棧來啓動打開,如果不啓動新任務棧的話,有時候會無原無故的顯示空白還不報錯!上面的錯只是一個小點,小到可以忽略不講,寫在這是提醒大家,該加的時候必須加Flag,至於什麼時候加,大家可以參照下官方的文檔及下面小馬貼出的官方文檔中解釋堆棧的圖解,加以理解學習,如下所示:Figure2:不多解釋,就是在A B 丙個任務堆棧,如果用戶正在於B任務堆棧進行交互時,A在等待喚醒,反之則反

          Figure3: 下面這個就好玩了,學習了下官方的文檔,講的是:無論啓動了一個新的任務堆棧或者在同一堆棧中來啓動一個活動,按返回鍵也還是會返回到用戶之前操作的Activity,如果以單例堆棧(類似單位模式)載入的話,就會在後臺生成一個針對於此活動的單獨的一個任務堆棧,當這個任務堆棧被喚醒到前臺時,此時的返回堆棧中就包含了從前幾個任務傳遞過來的棧頂的所有Activity,棧頂與棧底的顯示關係如果下圖:

            這個地方順帶着講下,在控制活動堆棧時方式只有一種,就是直接在.java文件中setFlag,如果是控制任務堆棧的話可以以addFlag或直接在全局配置文件中添加配置的方式來控制,大家可以直接在AndroidManifest.xml文件中activity節點中添加哪下屬性:taskAffinity、launchMode、allowTaskReparenting、clearTaskOnLaunch、alwaysRetainTaskState、finishOnTaskLaunch,兩種控制任務堆棧的方式換湯不換藥,大家看個人習慣選擇使用就可以了…切記,用的時候一定搞清楚你要加的標誌位是什麼意思,不要看到個task就addFlag,設置Flag是爲了讓應用更乾淨,控制更嚴密,如果加錯了標誌位,應用是不會報任何錯的,只是出現怪異的跳轉與關閉!!!

  

Stack是一個後進先出(last in first out,LIFO)的堆棧,在Vector類的基礎上擴展5個方法而來

Deque(雙端隊列)比起Stack具有更好的完整性和一致性,應該被優先使用

  1. E push(E item)   
  2.          把項壓入堆棧頂部。   
  3. E pop()   
  4.          移除堆棧頂部的對象,並作爲此函數的值返回該對象。   
  5. E peek()   
  6.          查看堆棧頂部的對象,但不從堆棧中移除它。   
  7. boolean empty()   
  8.          測試堆棧是否爲空。    
  9. int search(Object o)   
  10.          返回對象在堆棧中的位置,以 1 爲基數。  

Stack本身通過擴展Vector而來,而Vector本身是一個可增長的對象數組( a growable array of objects)那麼這個數組的哪裏作爲Stack的棧頂,哪裏作爲Stack的棧底?

答案只能從源代碼中尋找,jdk1.6:

  1. public class Stack<E> extends Vector<E> {  
  2.     /** 
  3.      * Creates an empty Stack. 
  4.      */  
  5.     public Stack() {  
  6.     }  
  7.   
  8.     /** 
  9.      * Pushes an item onto the top of this stack. This has exactly 
  10.      * the same effect as: 
  11.      * <blockquote><pre> 
  12.      * addElement(item)</pre></blockquote> 
  13.      * 
  14.      * @param   item   the item to be pushed onto this stack. 
  15.      * @return  the <code>item</code> argument. 
  16.      * @see     java.util.Vector#addElement 
  17.      */  
  18.     public E push(E item) {  
  19.     addElement(item);  
  20.   
  21.     return item;  
  22.     }  
  23.   
  24.     /** 
  25.      * Removes the object at the top of this stack and returns that 
  26.      * object as the value of this function. 
  27.      * 
  28.      * @return     The object at the top of this stack (the last item 
  29.      *             of the <tt>Vector</tt> object). 
  30.      * @exception  EmptyStackException  if this stack is empty. 
  31.      */  
  32.     public synchronized E pop() {  
  33.     E   obj;  
  34.     int len = size();  
  35.   
  36.     obj = peek();  
  37.     removeElementAt(len - 1);  
  38.   
  39.     return obj;  
  40.     }  
  41.   
  42.     /** 
  43.      * Looks at the object at the top of this stack without removing it 
  44.      * from the stack. 
  45.      * 
  46.      * @return     the object at the top of this stack (the last item 
  47.      *             of the <tt>Vector</tt> object). 
  48.      * @exception  EmptyStackException  if this stack is empty. 
  49.      */  
  50.     public synchronized E peek() {  
  51.     int len = size();  
  52.   
  53.     if (len == 0)  
  54.         throw new EmptyStackException();  
  55.     return elementAt(len - 1);  
  56.     }  
  57.   
  58.     /** 
  59.      * Tests if this stack is empty. 
  60.      * 
  61.      * @return  <code>true</code> if and only if this stack contains 
  62.      *          no items; <code>false</code> otherwise. 
  63.      */  
  64.     public boolean empty() {  
  65.     return size() == 0;  
  66.     }  
  67.   
  68.     /** 
  69.      * Returns the 1-based position where an object is on this stack. 
  70.      * If the object <tt>o</tt> occurs as an item in this stack, this 
  71.      * method returns the distance from the top of the stack of the 
  72.      * occurrence nearest the top of the stack; the topmost item on the 
  73.      * stack is considered to be at distance <tt>1</tt>. The <tt>equals</tt> 
  74.      * method is used to compare <tt>o</tt> to the 
  75.      * items in this stack. 
  76.      * 
  77.      * @param   o   the desired object. 
  78.      * @return  the 1-based position from the top of the stack where 
  79.      *          the object is located; the return value <code>-1</code> 
  80.      *          indicates that the object is not on the stack. 
  81.      */  
  82.     public synchronized int search(Object o) {  
  83.     int i = lastIndexOf(o);  
  84.   
  85.     if (i >= 0) {  
  86.         return size() - i;  
  87.     }  
  88.     return -1;  
  89.     }  
  90.   
  91.     /** use serialVersionUID from JDK 1.0.2 for interoperability */  
  92.     private static final long serialVersionUID = 1224463164541339165L;  
  93. }  

通過peek()方法註釋The object at the top of this stack (the last item of the Vector object,可以發現數組(Vector)的最後一位即爲Stack的棧頂

pop、peek以及search方法本身進行了同步

push方法調用了父類的addElement方法

empty方法調用了父類的size方法

Vector類爲線程安全類

綜上,Stack類爲線程安全類(多個方法調用而產生的數據不一致問題屬於原子性問題的範疇)

  1. public class Test {  
  2.     public static void main(String[] args) {  
  3.         Stack<String> s = new Stack<String>();  
  4.         System.out.println("------isEmpty");  
  5.         System.out.println(s.isEmpty());  
  6.         System.out.println("------push");  
  7.         s.push("1");  
  8.         s.push("2");  
  9.         s.push("3");  
  10.         Test.it(s);  
  11.         System.out.println("------pop");  
  12.         String str = s.pop();  
  13.         System.out.println(str);  
  14.         Test.it(s);  
  15.         System.out.println("------peek");  
  16.         str = s.peek();  
  17.         System.out.println(str);  
  18.         Test.it(s);  
  19.         System.out.println("------search");  
  20.         int i = s.search("2");  
  21.         System.out.println(i);  
  22.         i = s.search("1");  
  23.         System.out.println(i);  
  24.         i = s.search("none");  
  25.         System.out.println(i);  
  26.     }  
  27.       
  28.     public static void it(Stack<String> s){  
  29.         System.out.print("iterator:");  
  30.         Iterator<String> it = s.iterator();  
  31.         while(it.hasNext()){  
  32.             System.out.print(it.next()+";");  
  33.         }  
  34.         System.out.print("\n");  
  35.     }  
  36. }  

結果:

  1. ------isEmpty  
  2. true            
  3. ------push  
  4. iterator:1;2;3;    
  5. ------pop  
  6. 3       --棧頂是數組最後一個  
  7. iterator:1;2;  
  8. ------peek  
  9. 2       --pop取後刪掉,peek只取不刪  
  10. iterator:1;2;  
  11. ------search      
  12. 1       --以1爲基數,即棧頂爲1  
  13. 2       --和棧頂見的距離爲2-1=1  
  14. -1      --不存在於棧中  

Stack並不要求其中保存數據的唯一性,當Stack中有多個相同的item時,調用search方法,只返回與查找對象equal並且離棧頂最近的item與棧頂間距離(見源碼中search方法說明)



發佈了16 篇原創文章 · 獲贊 8 · 訪問量 38萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章