Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> [Android] 你真的了解Activity嗎?

[Android] 你真的了解Activity嗎?

編輯:關於Android編程

Activity是什麼?

我們都知道android中有四大組件(Activity 活動,Service 服務,Content Provider 內容提供者,BroadcastReceiver 廣播接收器),Activity是我們用的最多也是最基本的組件,因為應用的所有操作都與用戶相關,Activity 提供窗口來和用戶進行交互。
官方文檔這麼說:
  

An activity is a single, focused thing that the user can do. Almost all activities interact with the user, so the Activity class takes care of creating a window for you in which you can place your UI with setContentView(View).

大概的意思(原諒我):

activity是獨立平等的,用來處理用戶操作。幾乎所有的activity都是用來和用戶交互的,所以activity類會創建了一個窗口,開發者可以通過setContentView(View)的接口把UI放到給窗口上。

Android中的activity全都歸屬於task管理 。task 是多個 activity 的集合,這些 activity 按照啟動順序排隊存入一個棧(即“back stack”)。android默認會為每個App維持一個task來存放該app的所有activity,task的默認name為該app的packagename。

當然我們也可以在AndroidMainfest.xml中申明activity的taskAffinity屬性來自定義task,但不建議使用,如果其他app也申明相同的task,它就有可能啟動到你的activity,帶來各種安全問題(比如拿到你的Intent)。

Activity的內部調用過程

 

上面已經說了,系統通過堆棧來管理activity,當一個新的activity開始時,它被放置在堆棧的頂部和成為運行活動,以前的activity始終保持低於它在堆棧,而不會再次到達前台,直到新的活動退出。

還是上這張官網的activity_lifecycle圖:

 

這裡寫圖片描述

 

首先打開一個新的activity實例的時候,系統會依次調用

onCreate() -> onStart() -> onResume() 然後開始running

running的時候被覆蓋了(從它打開了新的activity或是被鎖屏,但是它依然在前台運行, lost focus but is still visible),系統調用onPause();

該方法執行activity暫停,通常用於提交未保存的更改到持久化數據,停止動畫和其他的東西。但這個activity還是完全活著(它保持所有的狀態和成員信息,並保持連接到窗口管理器

接下來它有三條出路
①用戶返回到該activity就調用onResume()方法重新running

②用戶回到桌面或是打開其他activity,就會調用onStop()進入停止狀態(保留所有的狀態和成員信息,對用戶不可見

③系統內存不足,擁有更高限權的應用需要內存,那麼該activity的進程就可能會被系統回收。(回收onRause()和onStop()狀態的activity進程)要想重新打開就必須重新創建一遍。

如果用戶返回到onStop()狀態的activity(又顯示在前台了),系統會調用

onRestart() -> onStart() -> onResume() 然後重新running

在activity結束(調用finish ())或是被系統殺死之前會調用onDestroy()方法釋放所有占用的資源。

activity生命周期中三個嵌套的循環

activity的完整生存期會在 onCreate() 調用和 onDestroy() 調用之間發生。 

activity的可見生存期會在 onStart() 調用和 onStop() 調用之間發生。系統會在activity的整個生存期內多次調用 onStart() 和onStop(), 因為activity可能會在顯示和隱藏之間不斷地來回切換。 

activity的前後台切換會在 onResume() 調用和 onPause() 之間發生。
因為這個狀態可能會經常發生轉換,為了避免切換遲緩引起的用戶等待,這兩個方法中的代碼應該相當地輕量化。

activity被回收的狀態和信息保存和恢復過程

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        if(savedInstanceState!=null){ //判斷是否有以前的保存狀態信息
             savedInstanceState.get("Key"); 
             }
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
   @Override
protected void onSaveInstanceState(Bundle outState) {
    // TODO Auto-generated method stub
     //可能被回收內存前保存狀態和信息,
       Bundle data = new Bundle(); 
       data.putString("key", "last words before be kill");
       outState.putAll(data);
    super.onSaveInstanceState(outState);
}
   @Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
       if(savedInstanceState!=null){ //判斷是否有以前的保存狀態信息
             savedInstanceState.get("Key"); 
             }
    super.onRestoreInstanceState(savedInstanceState);
}
}

onSaveInstanceState方法

在activity 可能被回收之前 調用,用來保存自己的狀態和信息,以便回收後重建時恢復數據(在onCreate()或onRestoreInstanceState()中恢復)。旋轉屏幕重建activity會調用該方法,但其他情況在onRause()和onStop()狀態的activity不一定會調用 ,下面是該方法的文檔說明。

   One example of when onPause and onStop is called and not this method is when a user navigates back from activity B to activity A: there is no need to call onSaveInstanceState on B because that particular instance will never be restored, so the system avoids calling it. An example when onPause is called and not onSaveInstanceState is when activity B is launched in front of activity A: the system may avoid calling onSaveInstanceState on activity A if it isn't killed during the lifetime of B since the state of the user interface of A will stay intact. 

也就是說,系統靈活的來決定調不調用該方法,但是如果要調用就一定發生在onStop方法之前,但並不保證發生在onPause的前面還是後面。

onRestoreInstanceState方法

這個方法在onStart 和 onPostCreate之間調用,在onCreate中也可以狀態恢復,但有時候需要所有布局初始化完成後再恢復狀態。

  onPostCreate:一般不實現這個方法,當程序的代碼開始運行時,它調用系統做最後的初始化工作。

啟動模式

啟動模式什麼?

  
簡單的說就是定義activity 實例與task 的關聯方式。
  

為什麼要定義啟動模式?

為了實現一些默認啟動(standard)模式之外的需求:
  

讓某個 activity 啟動一個新的 task (而不是被放入當前 task )

讓 activity 啟動時只是調出已有的某個實例(而不是在 back stack 頂創建一個新的實例) 

或者,你想在用戶離開 task 時只保留根 activity,而 back stack 中的其它 activity 都要清空

怎樣定義啟動模式?

定義啟動模式的方法有兩種:

使用 manifest 文件

在 manifest 文件中activity聲明時,利用 activity 元素的 launchMode 屬性來設定 activity 與 task 的關系。

 
           .......
        

注意: 你用 launchMode 屬性為 activity 設置的模式可以被啟動 activity 的 intent 標志所覆蓋。

有哪些啟動模式?

“standard” (默認模式) 

當通過這種模式來啟動Activity時, Android總會為目標 Activity創建一個新的實例,並將該Activity添加到當前Task棧中。這種方式不會啟動新的Task,只是將新的 Activity添加到原有的Task中。 
  

“singleTop” 

該模式和standard模式基本一致,但有一點不同:當將要被啟動的Activity已經位於Task棧頂時,系統不會重新創建目標Activity實例,而是直接復用Task棧頂的Activity。

“singleTask”

Activity在同一個Task內只有一個實例。
  
如果將要啟動的Activity不存在,那麼系統將會創建該實例,並將其加入Task棧頂; 

如果將要啟動的Activity已存在,且存在棧頂,直接復用Task棧頂的Activity。 

如果Activity存在但是沒有位於棧頂,那麼此時系統會把位於該Activity上面的所有其他Activity全部移出Task,從而使得該目標Activity位於棧頂。

“singleInstance” 

無論從哪個Task中啟動目標Activity,只會創建一個目標Activity實例且會用一個全新的Task棧來裝載該Activity實例(全局單例).

如果將要啟動的Activity不存在,那麼系統將會先創建一個全新的Task,再創建目標Activity實例並將該Activity實例放入此全新的Task中。

如果將要啟動的Activity已存在,那麼無論它位於哪個應用程序,哪個Task中;系統都會把該Activity所在的Task轉到前台,從而使該Activity顯示出來。

使用 Intent 標志

在要啟動 activity 時,你可以在傳給 startActivity() 的 intent 中包含相應標志,以修改 activity 與 task 的默認關系。

     Intent i = new Intent(this,NewActivity.class);
        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(i);

可以通過標志修改的默認模式有哪些?

FLAG_ACTIVITY_NEW_TASK

與”singleTask”模式相同,在新的 task 中啟動 activity。如果要啟動的 activity 已經運行於某 task 中,則那個 task 將調入前台。

FLAG_ACTIVITY_SINGLE_TOP

與 “singleTop”模式相同,如果要啟動的 activity位於back stack 頂,系統不會重新創建目標Activity實例,而是直接復用Task棧頂的Activity。

FLAG_ACTIVITY_CLEAR_TOP

此種模式在launchMode中沒有對應的屬性值。如果要啟動的 activity 已經在當前 task 中運行,則不再啟動一個新的實例,且所有在其上面的 activity 將被銷毀。

關於啟動模式的一些建議

一般不要改變 activity 和 task 默認的工作方式。 如果你確定有必要修改默認方式,請保持謹慎,並確保 activity 在啟動和從其它 activity 返回時的可用性,多做測試和安全方面的工作。

Intent Filter

android的3個核心組件——Activity、services、廣播接收器——是通過intent傳遞消息的。intent消息用於在運行時綁定不同的組件。
在 Android 的 AndroidManifest.xml 配置文件中可以通過 intent-filter 節點為一個 Activity 指定其 Intent Filter,以便告訴系統該 Activity 可以響應什麼類型的 Intent。

intent-filter 的三大屬性

Action

一個 Intent Filter 可以包含多個 Action,Action 列表用於標示 Activity 所能接受的“動作”,它是一個用戶自定義的字符串。

 
  
  
……
 

在代碼中使用以下語句便可以啟動該Intent 對象:

Intent i=new Intent(); 
i.setAction("com.scu.amazing7Action");

Action 列表中包含了“com.scu.amazing7Action”的 Activity 都將會匹配成功

URL

在 intent-filter 節點中,通過 data節點匹配外部數據,也就是通過 URI 攜帶外部數據給目標組件。

注意:只有data的所有的屬性都匹配成功時 URI 數據匹配才會成功

Category

為組件定義一個 類別列表,當 Intent 中包含這個類別列表的所有項目時才會匹配成功。


   
   

Activity 種 Intent Filter 的匹配過程

①加載所有的Intent Filter列表
②去掉action匹配失敗的Intent Filter
③去掉url匹配失敗的Intent Filter
④去掉Category匹配失敗的Intent Filter
⑤判斷剩下的Intent Filter數目是否為0。如果為0查找失敗返回異常;如果大於0,就按優先級排序,返回最高優先級的Intent Filter

開發中Activity的一些問題

一般設置Activity為非公開的

 

注意:非公開的Activity不能設置intent-filter,以免被其他activity喚醒(如果擁有相同的intent-filter)。

不要指定activity的taskAffinity屬性

不要設置activity的LaunchMode(保持默認)

注意Activity的intent最好也不要設定為FLAG_ACTIVITY_NEW_TASK

在匿名內部類中使用this時加上activity類名(類名.this,不一定是當前activity)

設置activity全屏

在其 onCreate()方法中加入:

// 設置全屏模式
 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 
 // 去除標題欄
 requestWindowFeature(Window.FEATURE_NO_TITLE);

覺得有幫助的,頂一下,謝謝!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved