Android學習(一)——四大組件之Activity

Activity基礎使用

Activity 是一個Android項目頁面的基礎

我們自行創建的Activity本身是繼承自Activity類,然而後期Android更新了AppCompatActivity,FragmentActivity等Activity的子類,這些我們有機會再說,Activity有一些方法是用來標記生命週期的

Activity的生命週期

生命週期圖

之前看見過很多生命週期圖,但是我還是覺得看這張更舒服,更直白一點。

其中這裏麪包括幾個回調方法,分別代表Activity的生命週期:

  • onCreate():在這個Activity首次被創建時會調用這個方法,裏面一般用來初始化一些UI元素,數據或者某些需要在頁面渲染之前就初始化的東西。onCreacte方法裏面有個Bundle對象的參數savedInstanceState,我們可以使用它進行Activity的狀態恢復。
  • onStart():在Activity創建之後會首先執行這個方法,在執行完onStop之後重新喚起這個頁面也會調用這個方法,通常在執行完onStart之後,下一步是使頁面進入到運行狀態,所以一般後面會緊跟着執行OnResume()方法使頁面進入到Resumed狀態,然而若是有什麼異常狀況也會導致頁面失效,繼而執行了onStop();你可以在這個方法裏開始某些啓動頁面就要做的事情,比如啓動某個動畫,啓動播放器,啓動某個前臺服務等需要在屏幕出現一些內容的操作。
  • onResume():在將一個 activity 移到前臺之前調用。你可以在這個方法中重新播放動畫、更新 UI 元素、重啓相機預覽、恢復音頻/視頻播放或者初始化你在 onPause() 中釋放的組件。
  • onPause(): 在將一個 activity 移到後臺之前調用。在這個方法中,應該停止和 activity 有關的展示類動作,比如動畫,頁面背景音效等。
  • onStop(): 在onPause()調用過後,activity 進入後臺之前調用。這個方法是保存數據到磁盤的好地方。如果 activity 回到前臺,它後面是 onRestart() 方法,如果它即將從內存移除,則它後面是 onDestroy() 方法。
  • onRestart(): 在關閉一個 activity且並未銷燬,又重新打開它之前調用。它後面總是 onStart() 方法。
  • onDestroy(): 這是 activity 被銷燬之前你能從系統接收到的最後一個回調。在這個方法中如果你在這個頁面還有資源未被釋放,需要在這裏釋放,否則會發生內存泄漏問題。

一個Activity的生命週期大致就分這幾個節點,當你寫一個頁面的時候你首先要考慮好在每個生命週期節點應該做那些事情,這樣就不會導致你的Activity看起來很亂,也要知道一些資源的生成釋放的時機,防止內存泄露或者還未生成資源就調用等問題

創建一個Activity

這個很簡單,AndroidStudio已經給我做好了一鍵生成的功能

生成一個Activity

這個不僅僅能生成一個空的Activity,還能生成很多不同功能的Activity,比如登錄模塊的模板LoginActivity等

但是如果你一定要手動生成一個Activity,那就要有以下操作:
1. 新建一個類繼承Activity(或者其他Activity的子類)
2. 在res/layout中新建一個layout.xml文件
3. 在Activity的onCreate方法裏 setContentView(R.layout.layout);
4. 在AndroidManifest.xml中的application節點下面註冊。

這樣你的Activity就創建好了,然而如果你創建一個新的Activity是沒有地方調用的,那就沒什麼意義了,通常你新建一個新的項目的時候IDE會默認給你新建一個MainActivity,這個Activity是整個程序的入口你在AndroidManifest.xml文件中會看見這個Activity的節點下面有下面這樣的標籤

MainTag

當一個Activity帶有這組標籤的時候,他就被標記爲APP的入口Activity,也就是APP啓動的第一個Activity。

啓動一個Activity

啓動一個Activity方式通常有兩種startActivity和startActivityForResult

這兩中方式一個是單純的啓動這個Activity,一個是啓動這個Activity並期待它有返回一些東西

startActivity(Intent intent)

  • 這是一個簡單的啓動方式,這個方法是Context類的,由於我們的所有Activity都繼承自Activity類,Activity又是繼承自Context類的,所以我們可以直接調用這個方法,他們之間的傳值用Intent
    Intent intent = new Intent();
    intent.setClass(當前Activity.this,目標Activity.class);
    startActivity(intent);

Activity之間的通信只能使用Intent進行

startActivityForResult()

  • 這是一種期待下個Activity返回動作的啓動方式,這個方法是Activity類的,所以如果你只是拿到Activity的Context,是不能使用這個方法的,除非你把Context實例化成Activity。
    Intent intent = new Intent();
    intent.setClass(當前Activity.this,目標Activity.class);
    startActivityForResult(intent,REQUEST_CODE);

這個時候你下一個頁面如果結束有動作或者數據要傳回到這個頁面的時候你需要在目標Activity中使用setResult方法

    Intent data= new Intent();
    data.putExtra("tag","target")
    setResult((RESULT_CODE,data));

這樣你的目標activity中的“target”字符串就通過data這個Intent傳回到了你之前的Activity,如果你想要獲取到這個data,你需要重寫Activity裏的一個方法onActivityResult:

     @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(requestCode = REQUEST_CODE && resultCode == RESULT_CODE){
             String tag = data.getStringExtra("tag")
         }
    }

這樣就拿到了目標Activity回傳回來的tag,這裏面requestCode就是在startActivityForResult時傳過去的自己定義的一個int值,而resultCode是你setResult時傳的值,這樣當你匹配到這兩個值就是你之前定義的那兩個值時,就說明是目標返回的了。

Created with Raphaël 2.1.0當前Activity當前Activity目標Activity目標Activity我給你個Intent啊,還帶着REQUEST_CODE(並記下了REQUEST_CODE);我還你個data啊,這是我的RESULT_CODE;兩個都對上了,嗯,這個就是它給我返的data

大概的流程就是這樣,啓動方式一般就這兩種

Activity的四大啓動模式

Activity還有四大啓動模式,分別是standard、singleTop、singleTask、singleInstance

啓動一個應用,系統就會爲之創建一個棧,來放置根Activity。默認情況下,一個Activity啓動另一個Activity時,兩個Activity是放置在同一個棧中的,後者被壓入前者所在的棧,當用戶按下後退鍵,或者finish()掉的時候後者就會從棧裏彈出,這樣一來就可以描述成Activity是像紙張一樣一張一張的摞起來的你啓動一個Activity,就是把他放到這個棧的棧頂,每退出一個Activity,就把他從棧裏拿出來,而你拿出來的時候必須按照順序拿,這個時候我們四大啓動模式就有了用武之地。

配置Activity的啓動模式是在AndroidManifest中的activity標籤內添加android:launchMode屬性

standard-默認模式

<activity 
    android:name=".SecondActivity" 
    android:launchMode="standard">

這個就是最標準的啓動方式,系統默認也是這種,一般我們可以不寫。這種方式就是正常的方式,最新的最先結束掉,每次啓動一個Activity都會重寫創建一個新的實例,不管這個實例存不存在,這種模式下,誰啓動了該模式的Activity,該Activity就屬於啓動它的Activity的任務棧中。這個Activity它的onCreate(),onStart(),onResume()方法都會被調用。

singleTop-棧頂複用模式

<activity 
    android:name=".SecondActivity" 
    android:launchMode="singleTop">

這種方式如果棧頂不是目標Activity的話,與standard方式一樣,但是如果目標Activity在棧頂的話,那麼這個Activity不會被重寫創建,同時它的onNewIntent方法會被調用,而且它本身的onCreate()與onStart()方法不會唄調用

singleTask-棧內複用模式

<activity 
    android:name=".SecondActivity" 
    android:launchMode="singleTask">

這個模式下,如果目標Activity在棧頂,則處理方式與SingleTop相同,如果目標Activity不在棧內,則處理方式與standard相同;但是如果這個Activity在棧內卻不在棧頂,那麼則會把它上面的Activity全部出棧並把目標Activity置頂,同時它的onNewIntent方法會被調用。

singleInstance-全局唯一模式

<activity 
    android:name=".SecondActivity" 
    android:launchMode="singleInstance">

該模式具備singleTask模式的所有特性,然而更牛逼的是,整個系統中就會只剩這一個實例,以singleInstance模式啓動的Activity在整個系統中是單例的,如果在啓動這樣的Activiyt時,已經存在了一個實例,那麼會把它所在的任務調度到前臺,重用這個實例。

關閉Activity

通常我們關閉一個Activity的方法就是調用Activity的finish()方法

當我們調用finish()方法以後,後面的代碼將不會執行,所以如果你是用startActivityForResult方式啓動的Activity,那麼你的setResult方法一定要放在finish()之前,否則無效。

配置變化

當發生屏幕旋轉,鍵盤顯示等操作時,會導致Activity重啓,這樣有些操作就會被中斷

處理方式推薦兩種:

1.重寫onConfigurationChanged() 方法
2.重寫onSaveInstanceState()方法

重寫onConfigurationChanged() 方法

首先在AndroidManifest的activity節點內添加android:configChanges屬性

<activity 
    android:name=".newprogressplayer.MusicPlayerActivity"
    android:configChanges="orientation|screenSize"
    />

然後在該Activity類內部重寫onConfigurationChanged方法

 @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }

你可以對 newConfig對象進行檢查,讀取 configuration 的字段,進行適當的修改界面上所用的資源。

重寫onSaveInstanceState()方法

持有一個狀態對象,將它傳遞給 activity 的重建的實例。你可以實現 onSaveInstanceState() 回調來達到這個目的

 @Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);
    }

在這種方式下,Bundle只能儲存序列化的對象,而在配置變化發生時進行序列化和反序列化數據會導致較大的性能開銷。它會消耗大量內存,並降低 activity 的重啓速度。

總結

這裏只是簡單介紹了一下Activity的基礎知識,編程裏面水深了去了,總有一些神奇的操作能讓你重新認識這個你本來認爲你已經會的東西,所以,活到老學到老,我先記一筆,回頭忘了或者不清晰的時候再看看。

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