程序活動單元Activity

 
    
        Android四大組件分別爲activity、service、content provider、broadcast receiver。
 
        Activity 類是 Android 應用的關鍵組件,而 Activity 的啓動和組合方式則是該平臺應用模型的基本組成部分。在編程範式中,應用是通過 main() 方法啓動的,而 Android 系統與此不同,它會調用與其生命週期特定階段相對應的特定回調方法來啓動 Activity 實例中的代碼。
 
4.0Activity 的概念
        移動應用體驗與桌面體驗的不同之處在於,用戶與應用的互動並不總是在同一位置開始,而是經常以不確定的方式開始。例如,如果您從主屏幕打開電子郵件應用,可能會看到電子郵件列表,如果您通過社交媒體應用啓動電子郵件應用,則可能會直接進入電子郵件應用的郵件撰寫界面。
 
        Activity 類的目的就是促進這種範式的實現。當一個應用調用另一個應用時,調用方應用會調用另一個應用中的 Activity,而不是整個應用。通過這種方式,Activity 充當了應用與用戶互動的入口點。您可以將 Activity 實現爲 Activity 類的子類。
 
        Activity 提供窗口供應用在其中繪製界面。此窗口通常會填滿屏幕,但也可能比屏幕小,並浮動在其他窗口上面。通常,一個 Activity 實現應用中的一個屏幕。例如,應用中的一個 Activity 實現“偏好設置”屏幕,而另一個 Activity 實現“選擇照片”屏幕。
 
        大多數應用包含多個屏幕,這意味着它們包含多個 Activity。通常,應用中的一個 Activity 會被指定爲主 Activity,這是用戶啓動應用時出現的第一個屏幕。然後,每個 Activity 可以啓動另一個 Activity,以執行不同的操作。例如,一個簡單的電子郵件應用中的主 Activity 可能會提供顯示電子郵件收件箱的屏幕。主 Activity 可能會從該屏幕啓動其他 Activity,以提供執行寫郵件和打開郵件這類任務的屏幕。
 
        雖然應用中的各個 Activity 協同工作形成統一的用戶體驗,但每個 Activity 與其他 Activity 之間只存在鬆散的關聯,應用內不同 Activity 之間的依賴關係通常很小。事實上,Activity 經常會啓動屬於其他應用的 Activity。例如,瀏覽器應用可能會啓動社交媒體應用的“分享”Activity。
 
        
 
 
4.1Activity的生命週期
 
1.生命週期狀態
啓動狀態:當Activity啓動之後便會進入下一狀態。
運行狀態:Activity處於屏幕最前端,可與用戶進行交互。
暫停狀態:Activity仍然可見,但無法獲取焦點,用戶對他操作沒有響應。
停止狀態:Activity完全不可見,系統內存不足時會銷燬該Activity。
銷燬狀態:Activity將被清理出內存。
注意:其中的啓動狀態和銷燬狀態爲過渡期,不會在該時期停留
 
2.生命週期方法

第一次運行程序時調用的生命週期方法爲: onCreate()→onStart()→onResume()。
退出程序時調用的生命週期方法爲: onPause()→onStop0→onDestory()。
 
  • onCreate():
           您必須實現此回調,其在系統首次創建 Activity 時觸發。Activity 會在創建後進入已創建狀態。在 onCreate() 方法中,您需執行基本應用啓動邏輯,該邏輯在 Activity 的整個生命週期中只應發生一次。例如,onCreate() 的實現可能會將數據綁定到列表,將 Activity 與 ViewModel 相關聯,並實例化某些類範圍變量。此方法接收 savedInstanceState 參數,後者是包含 Activity 先前保存狀態的 Bundle 對象。如果 Activity 此前未曾存在,則 Bundle 對象的值爲 null。
           如果您有一個具有生命週期感知能力的組件與您的 Activity 生命週期相關聯,則該組件將收到 ON_CREATE 事件。系統將調用經過 @OnLifecycleEvent 註釋的方法,以使您具有生命週期感知能力的組件可以執行已創建狀態所需的任何設置代碼。
 
  • onStart():
           當 Activity 進入“已開始”狀態時,系統會調用此回調。onStart() 調用使 Activity 對用戶可見,因爲應用會爲 Activity 進入前臺並支持交互做準備。例如,應用通過此方法來初始化維護界面的代碼。
           當 Activity 進入已開始狀態時,與 Activity 生命週期相關聯的所有具有生命週期感知能力的組件都將收到 ON_START 事件。
           onStart() 方法會非常快速地完成,並且與“已創建”狀態一樣,Activity 不會一直處於“已開始”狀態。一旦此回調結束,Activity 便會進入已恢復狀態,系統將調用 onResume() 方法。
     
  • onResume():
           Activity 會在進入“已恢復”狀態時來到前臺,然後系統調用 onResume() 回調。這是應用與用戶交互的狀態。應用會一直保持這種狀態,直到某些事件發生,讓焦點遠離應用。此類事件包括接到來電、用戶導航到另一個 Activity,或設備屏幕關閉。
            當 Activity 進入已恢復狀態時,與 Activity 生命週期相關聯的所有具有生命週期感知能力的組件都將收到 ON_RESUME 事件。這時,生命週期組件可以啓動任何需要在組件可見,且位於前臺時運行的功能,例如啓動攝像頭預覽.
           當發生中斷事件時,Activity 進入已暫停狀態,系統調用 onPause() 回調。
           如果 Activity 從“已暫停”狀態返回“已恢復”狀態,系統將再次調用 onResume() 方法。因此,您應實現 onResume(),以初始化在 onPause() 期間釋放的組件,並執行每次 Activity 進入“已恢復”狀態時必須完成的任何其他初始化操作。
 
  • onPause():
           系統將此方法視爲用戶正在離開您的 Activity 的第一個標誌(儘管這並不總是意味着活動正在遭到銷燬);此方法表示 Activity 不再位於前臺(儘管如果用戶處於多窗口模式,Activity 仍然可見)。使用 onPause() 方法暫停或調整當 Activity 處於“已暫停”狀態時不應繼續(或應有節制地繼續)的操作,以及您希望很快恢復的操作。Activity 進入此狀態有多個原因,例如:
                  * 如 onResume() 部分所述,某個事件會中斷應用執行。這是最常見的情況。
                  * 在 Android 7.0(API 級別 24)或更高版本中,有多個應用在多窗口模式下運行。無論何時,都只有一個應用(窗口)可以擁有焦點,因此係統會暫停所有其他應用。
                  * 有新的半透明 Activity(例如對話框)處於開啓狀態。只要 Activity 仍然部分可見但並未處於焦點之中,它便會一直暫停。
           當 Activity 進入已暫停狀態時,與 Activity 生命週期相關聯的所有具有生命週期感知能力的組件都將收到 ON_PAUSE 事件。這時,生命週期組件可以停止任何無需在組件未在前臺時運行的功能,例如停止攝像頭預覽。
           您還可以使用 onPause() 方法釋放系統資源、傳感器(例如 GPS)手柄,或當您的 Activity 暫停且用戶不需要它們時仍然可能影響電池續航時間的任何資源。然而,正如上文的 onResume() 部分所述,如果處於多窗口模式,則“已暫停”的 Activity 仍完全可見。因此,您應該考慮使用 onStop() 而非 onPause() 來完全釋放或調整與界面相關的資源和操作,以便更好地支持多窗口模式。
     
  • onStop():
           如果您的 Activity 不再對用戶可見,則說明其已進入已停止狀態,因此係統將調用 onStop() 回調。舉例而言,如果新啓動的 Activity 覆蓋整個屏幕,就可能會發生這種情況。如果系統已結束運行並即將終止,系統還可以調用 onStop()。
           當 Activity 進入已停止狀態時,與 Activity 生命週期相關聯的所有具有生命週期感知能力的組件都將收到 ON_STOP 事件。這時,生命週期組件可以停止任何無需在組件未在屏幕上可見時運行的功能。
           在 onStop() 方法中,應用應釋放或調整應用對用戶不可見時的無用資源。例如,應用可以暫停動畫效果,或從細粒度位置更新切換到粗粒度位置更新。使用 onStop() 而非 onPause() 可確保與界面相關的工作繼續進行,即使用戶在多窗口模式下查看您的 Activity 也能如此。
           您還應該使用 onStop() 執行 CPU 相對密集的關閉操作。例如,如果您無法找到更合適的時機來將信息保存到數據庫,則可在 onStop() 期間執行此操作。
 
  • onRestart():當處於“已停止”狀態的 Activity 即將重啓時,系統就會調用此回調。onRestart() 會從 Activity 停止時的狀態恢復 Activity。
 
  • onDestroy():
           銷燬 Ativity 之前,系統會先調用 onDestroy()。系統調用此回調的原因如下:
                  1. Activity 正在結束(由於用戶徹底關閉 Activity 或由於系統爲 Activity 調用 finish()),或者
                  2. 由於配置變更(例如設備旋轉或多窗口模式),系統暫時銷燬 Activity
           當 Activity 進入已銷燬狀態時,與 Activity 生命週期相關聯的所有具有生命週期感知能力的組件都將收到 ON_DESTROY 事件。此時,生命週期組件可以在 Activity 遭到銷燬之前清理所需的任何數據。
           您應使用 ViewModel 對象來容納 Activity 的相關視圖數據,而不是在您的 Activity 中加入邏輯來確定 Activity 遭到銷燬的原因。如要由於配置變更而重新創建 Activity,則 ViewModel 不必執行任何操作,因爲系統將保留 ViewModel 並將其提供給下一個 Activity 實例。如果不重新創建 Activity,ViewModel 將調用 onCleared() 方法,以便在 Activity 遭到銷燬前清除所需的任何數據。
           您可以使用 isFinishing() 方法區分這兩種情況。
           如果 Activity 正在結束,則 onDestroy() 是 Activity 收到的最後一個生命週期回調。如果由於配置變更而調用 onDestroy(),則系統會立即新建 Activity 實例,然後在新配置中爲新實例調用 onCreate()。
           onDestroy() 回調應釋放先前的回調(例如 onStop())尚未釋放的所有資源。
 
 
 
3.腳下留心
手機橫豎屏切換時,系統會根據AndroidManifest.xml文件中Activity的configChanges屬性值的不同而調用相應的生命週期方法。
沒有設置configChanges屬性的值時:
  • 當由豎屏切換橫屏時,調用的方法依次是onPause()、onStop() 、onDestory( 、onCreate() 、 onStart() 和onResume()的方法。
<activity android:name=".MainActivity" android:configChanges="orientationkeyboardHidden">
  • 打開程序時同樣會調用onCreate()→onStart()→onResume( 方法,但是當進行橫豎屏切換時不會再執行其他的生命週期方法。
如果希望某一個界面一直處於豎屏或者橫屏狀態,不隨手機的晃動而改變,可以在清單文件中通過設置Activity的screenOrientation屬性完成
  • 豎屏:android:screenOrientation="portrait"
  • 橫屏: android:screenOrientation="landscape"
 
 
4.2Activity的創建配置和關閉
 
1.Activity的創建
右擊包名→New→Activity→Empty Activity
 
2.配置Activity
包名處點擊右鍵選擇[New]→[JavaClass]選項,填寫Java類名,完成創建。在該類中繼承Activity
當啓動該Activity時,會拋出RuntimeException異常信息:
 
要聲明 Activity,請打開清單文件,並添加 <activity> 元素作爲 <application> 元素的子元素。此元素唯一的必要屬性是 android:name,該屬性用於指定 Activity 的類名稱
 
  • 在AndroidManifest.xml文件的<application> </application>標籤中配置
    Activity :<activity android:name="cn.itcast.activitybasic.SecondActivity" />
 
  • 如果Activity所在的包與AndroidManifest.xml文件的<manifest></manifest>標籤中通過package屬性指定的包名一致則android:name屬性的值可以直接設置爲“.Activity名稱”。
    <activity android:name=".SecondActivity"></activity>
 
注意:發佈應用後,就不應再更改 Activity 名稱,否則可能會破壞某些功能,例如應用快捷方式。
 
 
 
3.開啓和關閉Activity
開啓Activity :startActivity)
  • 在MainActivity的onCreate()方法中啓動SecondActivity 
    Intent intent = new Intent(MainActivity.this,SecondActivity.class);
        startActivity(intent);
 
關閉Activity :finish()
 
 
4.3Intent與IntentFilter
 
1.聲明 intent 過濾器
 
Intent被稱爲意圖,是程序中各組件進行交互的一-種重要方式,他不僅可以指定當前組件要執行的動作,還可以在不同組件之間進行數據傳遞。
 
一般用於啓動Activity、Service 以及發送廣播等。根據開啓目標組件的方式不同,Intent被分爲兩種類型顯示意圖隱式意圖
  • 顯式意圖可以直接通過名稱開啓指定的目標組件
  • 隱式意圖通過指定action和category等屬性,系統根據這些信息進行分析後尋找目標Activity
Intent intent = new Intent(MainActivity.this,SecondActivity.class);    
//創建一個Intent對象,其中第1個參數爲Context表示當前的Activity對象第2個參數表示要啓動的目標Activity。
startActivity(intent);    //調用Activity的startActivity方法啓動目標組件

 

        Intent 過濾器是 Android 平臺的一項非常強大的功能。藉助這項功能,您不但可以根據顯式請求啓動 Activity,還可以根據隱式請求啓動 Activity。例如,顯式請求可能會告訴系統“在 Gmail 應用中啓動‘發送電子郵件’Activity”,而隱式請求可能會告訴系統“在任何能夠完成此工作的 Activity 中啓動‘發送電子郵件’屏幕”。當系統界面詢問用戶使用哪個應用來執行任務時,這就是 intent 過濾器在起作用。
 
        要使用此功能,您需要在 <activity> 元素中聲明 <intent-filter> 屬性。此元素的定義包括 <action> 元素,以及可選的 <category> 元素和/或 <data> 元素。這些元素組合在一起,可以指定 Activity 能夠響應的 intent 類型。例如,以下代碼段展示瞭如何配置一個發送文本數據並接收其他 Activity 的文本數據發送請求的 Activity:
    <activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">
        <intent-filter>
            <action android:name="android.intent.action.SEND" />    //設置action動作,當代碼中的action與該action相匹配時啓動該組件。
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain" />
        </intent-filter>
    </activity>
  • 當發送一個隱式Intent後,Android系統會將他與程序中的每一個組件的過濾器進行匹配,匹配屬性有action、data 、category ,需要這三個屬性都匹配成功才能喚起相應的組件。

  • action:用於指定Intent對象的動作。    

    只要Intent攜帶的action與其中一個<intent- filter>標籤中action的聲明相同action屬性就匹配成功。

<intent-filter>
<action android:name="android.intent.action.EDIT"/>
<action android:name="android.intent. action. VIEW"/>
......
</intent-filter>
  • data:指定數據的URI或者數據MIME類型他的值通常與Intent的action屬性有關聯。

隱式Intent攜帶的data數據只要與IntentFilter中的任意一個data聲明相同data屬性就匹配成功。

<intent-filter>
<data android:mimeType="video/mpeg" android:schemex=ht..."/>
<data android:mimeType="audio/mpeg" android:scheme="tt..."/>
...
</intent-filter>
  • category:用於爲action添加額外信息。

一個IntentFilter可以不聲明category屬性,也可以聲明多個category屬性。

隱式Intent中聲明的category必須全部能夠與某- -個IntentFilter中的category匹配纔算匹配成功

<intent-filter>
<category android:name=" android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>

注意: IntentFilter 中羅列的category屬性數量必須大於或者等於隱式Intent攜帶的category屬性數量時,category 屬性才能匹配成功。如果一個隱式Intent沒有設置category屬性,那麼他可以通過任何一個IntentFilter (過濾器) 的category匹配。

 

 

示例:

    <activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">
        <intent-filter>
            <action android:name="android.intent.action.SEND" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain" />
        </intent-filter>
    </activity>

在此示例中,<action> 元素指定該 Activity 會發送數據。將 <category> 元素聲明爲 DEFAULT 可使 Activity 能夠接收啓動請求。<data> 元素指定此 Activity 可以發送的數據類型。以下代碼段展示瞭如何調用上述 Activity:

    // Create the text message with a string
    Intent sendIntent = new Intent();
    sendIntent.setAction(Intent.ACTION_SEND);
    sendIntent.setType("text/plain");
    sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
    // Start the activity
    startActivity(sendIntent);
4.4Activity之間的跳轉
 
1.數據傳遞
a、方式一:通過intent傳遞屬性
①MainActivity設置intent
Intent intent =new Intent(MainActivity.this,SecondActivity.class);  //設置跳轉Activity
intent.putExtra("studentName","小明");    //設置傳遞屬性
intent.putExtra("age","25");
startActivity(intent);      //啓動意圖

②SecondActivity獲取intent

setContentView(R.layout.activity_second);
Intent intent = getIntent();    //獲取intent
String studentName = intent.getStringExtra("studentName");    //獲取intent屬性
String age = intent.getStringExtra("age");
Toast.makeText(SecondActivity.this,"姓名:"+studentName+"\n年齡:"+age,Toast.LENGTH_SHORT).show();

 

 
b、方式二:使用Bundle傳遞
①MainActivity設置bundle
 
Intent intent =new Intent(MainActivity.this,SecondActivity.class);  //設置跳轉Activity
Bundle bundle = new Bundle();
bundle.putString("studentName","小紅花");
intent.putExtras(bundle);
startActivity(intent);      //啓動意圖

②SecondActivity獲取bundle

Intent intent = getIntent();    //獲取intent
Bundle bundle = intent.getExtras();
String studentName1 = bundle.getString("studentName");
Toast.makeText(SecondActivity.this,"姓名:"+studentName1,Toast.LENGTH_SHORT).show();

2.數據回傳

①MainActivity設置intent

Intent intent2 = new Intent(MainActivity.this,ThirdActivity.class);
startActivityForResult(intent2,1);      // 使用startActivityForResult方法開啓SecondActivity,第1個參數是Intent對象,第2個參數是請求碼,用於標識請求的來源。

②ThirdActivity獲取intent

Intent intent = new Intent();
intent.putExtra("data","hello MainActivity");
setResult(2,intent);    // 在SecondActivity 中添加返回數據。
finish();

③MainActivity接收回傳數據

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(requestCode==1 && resultCode == 2){
        String result = data.getStringExtra("data");
        Toast.makeText(MainActivity.this,result,Toast.LENGTH_SHORT).show();
    }
}
 
 
4.5Activity的任務棧和啓動模式
 
1.Android中的任務棧
任務棧:一種用來存放Activity實例的容器。
特點:先進先出
操作:壓棧和出棧
 

 
 
 
2.Activity的啓動模式
①standard模式:standard模式是Activity的默認啓動方式,每啓動一個Activity就會在棧頂創建一個新的實例。

 
②singleTop模式:singleTop模式會判斷要啓動的Activity實例是否位於棧頂,如果位於棧頂則直接複用,否則創建新的實例。

 
③singleTask模式:singleTask模式下每次啓動該Activity時,系統首先會檢查棧中是否存在當前Activity實例,如果存在則直接使用,並把當前Activity之上的所有實例全部出棧。

 
④singleInstance模式:singleInstance模式會啓動一個新的任務棧來管理Activity實例,無論從哪個任務棧中啓動該Activity,該實例在整個系統中只有一個。

 
 
4.6使用Fragment
 
1.fragment簡介
Fragment(碎片)是一種可以嵌入在Activity中的UI片段,它可以用來描述Activity中的一部分佈局。

            

 
 
2.生命週期
  • Fragment不能獨立存在,必須嵌入到Activity中使用,所以Fragment生命週期直接受所在的Activity影響。
  • 當在Activity中創建Fragment時,Fragment處於啓動狀態,當Activity被暫停時,其中的所有Fragment也被暫停,當Activity被銷燬時,所有在該Activity中的Fragment也被銷燬。當一個Activity處於運行狀態時,可以單獨地對每一個Fragment進行操作,如添加或刪除,當添加時,Fragment處於啓動狀態。當刪除時,Fragment處於銷燬狀態。

 
3.創建Fragment
 
 
public class NewsListFragment extends Fragment{
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
         View v = inflater.inflate(R.layout.fragment, container, false);   
//第一個參數表示Fragment對應的佈局資源ID,第二個參數表示存放Fragment佈局的ViewGroup, 第三個參數表示是否在創建Fragment的佈局時附加到ViewGroup上。
         return v;
     }
 }

 

        注意:Android系統中提供了兩個Fragment類,分別是android.app.Fragment和android.support.v4.app.Fragment。如果NewsListFragment類繼承的是android.app.Fragment類,則程序只能兼容3.0版本以上的Android系統,如果NewsListFragment類繼承的是android.support.v4.app.Fragment類,則程序可以兼容1.6版本以上的Android系統。

 

 

4.在Activity中添加Fragment

        在Activity中使用Fragment時,可以通過兩種方式將Fragment添加到Activity中,一種是通過佈局文件添加,一種是通過代碼動態添加。

 

① 在自定義佈局中添加Fragment

    <fragment
        android:name="cn.itcast.NewsListFragment"    //自定義Fragment的完整路徑
         android:id="@+id/newslist"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
    </fragment>

②在代碼中動態添加

在Activity中動態添加Fragment的步驟創建需要創建一個Fragment的實例對象。

a) 獲取FragmentManager(Fragment管理器)的實例。 

b) 開啓FragmentTransaction(事務)。 

c) 向Activity的佈局容器(一般爲FrameLayout)中添加Fragment。

d) 通過commit()方法提交事務。

NewsListFragment fragment = new NewsListFragment();    //實例化Fragment對象
FragmentManager fm = getFragmentManager();         //獲取FragmentManager實例
FragmentTransaction beginTransaction = fm.beginTransaction();     //開啓事務
beginTransaction.replace(R.id.ll,fragment);      //添加Fragment
beginTransaction.commit();    //提交事務

 

 
 
 
 
 
 
 
 
 
 
 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章