🏆作者簡介:|康有為| ,大四在讀,目前在小米安卓實習,畢業入職
🏆本文收錄于 ?安卓學習大全,歡迎關注
🏆安卓學習資料推薦:
? ? ? ? 視頻:b站搜動腦學院 視頻鏈接 (他們的視頻后面一部分沒再更新,看看前面也挺好的)
? ? ? ? 書籍:《第一行代碼》(第3版) by 郭霖 (z-lib.org)
? ? ? ? 思維導圖: https://www.processon.com/view/link/62427cb2e0b34d0730e20e00(來自動腦學院)
目錄
一、Activity入門
Activity的創建
1. 在layout目錄下創建XML文件
2. 創建與XML文件對應的Java代碼
3. 在AndroidManifest.xml中注冊頁面配置
Activity的跳轉
Activity快捷創建
二、Activity的基本用法
在Activity中使用Toast
三、Activity的啟動和結束
四、Activity的生命周期
分析Activity生命周期
將上文的細節提煉
狀態之間的切換過程
Activity A 啟動一個透明的 Activity B
異常情況下的生命周期
常見異常情況
1.資源相關的系統配置發生改變導致Activity被殺死并重新創建
2.系統內存不足導致低優先級的Activity被殺死
一、Activity入門
Activity可以理解為程序的一個界面或一個屏幕。
在Android中,Activity 是一個用于展示用戶界面和處理用戶交互的基本組件。它代表了用戶與應用程序之間的單一屏幕,用戶在應用程序中進行的每個操作通常都與一個 Activity 相關聯。在Android應用程序中,通常會包含多個活動,每個活動都代表應用程序的一個界面或一個屏幕
先用Androidstudio創建一個Empty Views Activity 的 HelloWorld程序,java語言的
Activity的創建
完整的頁面創建過程包括三個步驟,也就是創建下面的三個文件
1. 在layout目錄下創建XML文件
創建成功后,添加下面代碼
并在res/values/strings.xml文件 中添加文字
<resources><string name="app_name">HelloWorld-Java</string><string name="text2">文字2222222</string>
</resources>
2. 創建與XML文件對應的Java代碼
寫代碼:
1.繼承AppCompatActivity
2.重寫onCreate方法(寫onCreate會有提示,自動補全)
重寫時選擇這個protect修飾的這個onCreate方法
3.寫上:setContentView(R.layout.activity_main2);
package com.example.helloworld_java;import android.os.Bundle;import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;public class MainActivity2 extends AppCompatActivity {@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main2);}
}
3. 在AndroidManifest.xml中注冊頁面配置
在這里加入一行代碼,將這個activity注冊到清單文件
<activity android:name=".MainActivity2"/>
?
因為MainActivity2 不是主activity,所以不用再修改 intent-filter的代碼。
至此就創建好了 Activity2
Activity的跳轉
我們想顯示Activity2,就需要從主Activity中跳轉到2,所以寫一個按鈕,加上點擊跳轉的事件,跳轉到2。
在主Activity中加上按鈕
<Buttonandroid:id="@+id/button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="跳轉" />
?編寫跳轉事件(要寫到主Activity中的onCreate方法里面,從主Activity 跳轉到 其他Activity)
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent();intent.setClass(MainActivity.this,MainActivity2.class);startActivity(intent);}
});
?效果
Activity快捷創建
直接在java文件包那里快捷創建
這樣layout里面也會自動幫我們創建好文件
清單文件中也會自動幫我們注冊好
快捷創建的layout中的xml文件,根是androidx.constraintlayout.widget.ConstraintLayout ,我們可以換成LinearLayout 。
?androidx.constraintlayout.widget.ConstraintLayout 和 LinearLayout 是 Android 開發中常用的兩種布局管理器,它們在布局設計和子視圖排列方面有一些不同之處。
二、Activity的基本用法
在Activity中使用Toast
Toast是Android系統提供的一種非常好的提醒方式,在程序中可以使用它將一些短小的信息通 知給用戶,這些信息會在一段時間后自動消失,并且不會占用任何屏幕空間。
在Android中,Toast 是一種簡單的通知方式,可以在屏幕底部顯示一小段時間的消息。以下是在 Activity 中使用 Toast 的基本步驟:
- 創建 Toast 對象: 使用 Toast.makeText() 方法創建一個 Toast 對象。
- 設置顯示文本: 使用 setText() 方法設置要顯示的文本內容。
- 設置時長: 使用 setDuration() 方法設置 Toast 的顯示時長,可以選擇 Toast.LENGTH_SHORT(短時,大約2秒)或 Toast.LENGTH_LONG(長時,大約3.5秒)。
- 顯示 Toast: 調用 show() 方法顯示 Toast。
以下是一個簡單的示例:
import android.os.Bundle;
import android.view.Gravity;
import android.widget.Toast;import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 創建一個Toast對象Toast toast = Toast.makeText(this, "Hello, this is a Toast!", Toast.LENGTH_SHORT);// 設置Toast的顯示位置(可選)toast.setGravity(Gravity.CENTER, 0, 0);// 顯示Toasttoast.show();}
}
效果:
三、Activity的啟動和結束
從當前頁面跳到新頁面,跳轉代碼如下:
startActivity(new Intent(源頁面.this,目標頁面.class));
從A -- 》 B ,那么B就是啟動了
從當前頁面回到上一個頁面,相當于關閉當前頁面,返回代碼如下:
finish();//結束當前的活動頁面
B結束之后,就返回到了A
示例
從A跳到B的java代碼,xml里面寫個按鈕就行。
從B跳回A,也就是直接執行 finish 就行
四、Activity的生命周期
分析Activity生命周期
什么是 生命周期,就是從生到死的過程。
正常情況下,新建一個Activity A會順序經歷如下幾個生命周期:
- onCreate:A正在被創建,這個方法中,我們可以做一些Activity的初始化操作。例如布局文件的加載與事件的綁定(setContentView,findViewById,setOnClickListener等)。
- onStart: A 正在被啟動,A 由不可見變為可見時調用,此時 A 還無法與用戶交互。此時可以做一些數據的初始化操作(開啟線程去拉本地數據庫數據,或從后臺拉數據)。
- onResume: A 已經可見,并出現在前臺,該Activity位于返回棧棧頂,可以響應用戶的操作,即可以與用戶交互了。
如果此時用戶拉起另一個Activity B, Activity A會順序經歷如下幾個生命周期:
4. onPause: 表示 A 正在停止,準備從前臺返回至后臺,此時可以做一些停止動畫,數據存儲等工作。值得注意的是,在onPause生命周期進行的工作不能太耗時,不然會影響 B 的顯示。(Activity A的onPause執行完后,Activity B的onResume才會執行)。
5. onStop: 在 A 完全不可見時調用,緊隨著onPause執行,表 A 即將停止,此時 A 已經不在前臺,可以做一些稍微重量級的回收工作,但同樣不能太耗時,(如果此時新打開的Activity B是對話框式的Activity,背景存在一定區域是透明的,則Activity A的onStop不會調用)。
6. onDestroy:表示 A 即將被銷毀,在這里可以進行資源的回收、釋放工作。一般是經過用戶按下back鍵或者系統資源緊張時,將Activity A釋放掉以獲得更多的內存時調用。
Activity B經歷了onResume生命周期后已經顯示在前臺,如果此時按下back返回鍵,從 B 頁面返回,而 A 還停留在onStop,沒有經過onDestroy生命周期的話,A 會經歷如下幾個生命周期后重新顯示:
7. onRestart: A 由onStop停止狀態,轉為運行狀態時調用,表 A 正在被重新啟動。
8. onStart
9. onResume
可以看到,排除Activity退到后臺的情況,Activity從創建到銷毀,總共會經過6個生命周期,分別是onCreate,onStart,onResume,onPause,onStop,onDestroy。
通過上面的文字描述,看這個圖應該已經很清楚了,不過,未提到的是,上圖中onPause()還有個箭頭指向了onResume(),這是一種極端情況。即考慮當Activity A 跳轉到Activity B 的情況,此時 A 還在執行onPause() , B 還未顯示出來。快速地從B回到A,此時會直接執行 A 的onResume()而不會走onRestart()。不過一般很難復現這種操作,大家留個心眼就行。
將上文的細節提煉
- onStart、onResume、onPause、onStop看起來回調調用的時機差不多,它們倆區別在哪呢?
onStart和onStop是從Activity是否可見的角度來回調的,而onResume和onPause則是從Activity是否位于前臺、是否可以與用戶交互的角度來回調的,除了這方面的差別,在時機使用過程中,它們沒有其他明顯區別。
- 從Activity A 跳轉到Activity B,是先執行 A 的onPause(),還是先執行 B 的onResume()呢?
這部分設計Activity跳轉的源碼,源碼邏輯太深、太復雜就不先在基礎篇討論了,大家目前 先記住結論就好:A 的onPause()會先執行,然后才執行 B 的onResume(),這個細節也是面試中可能會問到的點。
- 在onPause中不能進行耗時的操作,否則會影響新Activity的顯示,稍微重一點的操作可以放在onStop中,但依然不能太耗時。
狀態之間的切換過程
打開新頁面的方法調用順序為:
onCreate→onStart→onResume
關閉舊頁面的方法調用順序為:
onPause→onStop→onDestroy
Activity A 啟動一個透明的 Activity B
- 如果 Activity A 啟動一個透明的 Activity B,會經歷哪些生命周期呢?
這是面試容易遇到的一個問題,因為 B 頁面透明, 所以跳轉到 B 頁面后,A 頁面依然可見,因此就不會調用 Activity A 的 onStop 方法。
一般情況,A/B 均不是透明頁面:
A 跳轉 B 頁面會經歷的生命周期:A.onPause() -> B.onCreate() -> B.onStart() -> B.onResume() -> A.onStop。
從 B 頁面返回 A 頁面經歷的生命周期:B.onPause() -> A.onRestart() -> A.onStart() -> A.onResume() -> B.onStop()。
B是透明頁面的情況:
如果 B 是透明的,A 跳轉到 B:A.onPause() -> B.onCreate() -> B.onStart() -> B.onResume()。
從 B 返回 A:B.onPause() -> A.onResume() -> B.onStop()
異常情況下的生命周期
考慮一種異常情況,Activity C 打開了Actvity D后,C進入了停止狀態(調用了onStop()),此時系統內存不足,需要回收 C(調用C的onDestroy()) ,當用戶從 D 返回到 C,C 會被重新創建(調用onCreate())。如果原來 C 里邊有臨時狀態存儲著,比如TextView中的文字。那么從 D 返回 C 時,C因為重新創建,如果TextView未指定ID,那它原來的文字就會消失,這一定程度影響了用戶的體驗。
因此為了優化用戶體驗,Activity提供了一個onSaveInstanceState()回調方法,這個方法可以保證異常情況下,在Activity被回收之前一定會被調用。
onSaveInstanceState()方法會攜帶一個bundle參數,我們可以通過bundle對象,存儲一些簡單的狀態信息。
Activity重新創建后,系統會調用onRestoreInstanceState(),并把Activity銷毀時onSaveInstanceState()方法所保存的Bundle對象作為參數同時傳遞給onRestoreInstanceState()和onCreate()。
你可以選擇這兩個方法中任意一個來恢復數據,二者的區別是:onRestoreInstanceState一旦被調用,其bundle對象一定是有值的,而onCreate在正常啟動Activity的情況下bundle對象是無值的。
調用時機
onSaveInstanceState()在onStop()之前調用,onRestoreInstanceState()會在onStart()之后調用。
異常情況下,Activity數據的存儲和恢復的生命過程都是一樣的。
常見異常情況
常見的異常情況主要有以下兩種:
1.資源相關的系統配置發生改變導致Activity被殺死并重新創建
首先說說什么是系統配置信息。
不同手機設備的分辨率不同,要將圖片適配不同大小的手機屏幕,我們通常會在drawable-xhdpi,drawable-xxhdpi,drawable-xxxhdpi等目錄中存放對應大小的圖片Resource文件。
當App啟動時,系統就會根據當前設備的屏幕情況去加載合適的Resource資源。同一臺設備的橫屏和豎屏時的屏幕大小也是不一樣的,如果當前Activity處于豎屏狀態,突然旋轉至橫屏,那么此時系統的屏幕配置發生了改變。
默認情況下,Activity會被銷毀并重建。因為這種銷毀是一種非用戶主導的、異常的情況,Activity會調用onSaveInstanceState()方法后銷毀,重建時會再調用onRestoreInstanceState()方法,即走一遍異常情況的生命周期。
如何避免這種因為系統配置更改而導致Activity重建的異常情況?
如果app在應用配置變更期間無需更新資源,我們可以在AndroidManifest.xml文件中相應的Activity聲明,自行處理相關配置的變更,從而阻止系統重建Activity。
只需指定相關的configChanges屬性。比如下面的例子,就阻止了當屏幕發生旋轉時Activity的系統自動重建。
<activity android:name=".MainActivity"android:configChanges="orientation|screenSize" />
當configChanges中指定的配置發生變化時,系統會調用Activity的onConfigurationChanged()方法,如果有需要處理配置變更的話,可以在這個方法手動處理。一般我們在屏幕旋轉時,希望Activity能保持原樣,不重建就好了,所以空實現該方法即可。
當然,需要自行處理時,比如檢查當前設備的方向,你可以這么寫:
override fun onConfigurationChanged(newConfig: Configuration) {super.onConfigurationChanged(newConfig)// Checks the orientation of the screenif (newConfig.orientation === Configuration.ORIENTATION_LANDSCAPE) {Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show()} else if (newConfig.orientation === Configuration.ORIENTATION_PORTRAIT) {Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show()}
}
configChanges屬性可以指定很多屬性,如果你還想指定更多配置,不同配置間用"|"分隔,比如上面那樣。
部分常用的configChanges配置項目如下:
2.系統內存不足導致低優先級的Activity被殺死
這種情況就是我們分析異常情況下的生命周期時舉的例子。Activity C 跳轉至Activity D,C 處于后臺,當系統內存資源不足時,C的優先級較低,會被系統銷毀以獲得更多的內存,然后再從 D 回到 C ,C 會被重建,走一遍異常時的數據存儲和恢復的生命過程。
Activity按照優先級從高到低,可以分為如下三中情況:
- 前臺Activity,正在與用戶交互的Activity,其優先級最高。
- 可見但非前臺Activity,比如Activity中彈出了一個對話框,導致Activity可見但出于后臺,無法與用戶直接交互。
- 后臺Activity,已經被暫停的Activity,比如執行了onStop,用戶看不見,優先級最低。
當系統內存不足時,系統會按照上述優先級的順序去殺死Activity所在的進程。并在后續通過onSaveInstanceState()和onRestoreInstanceState()去存儲和恢復數據。
如果一個進程中沒有四大組件在執行,那么這個進程將會很快被系統殺死,因此一些后臺工作不適合脫離四大組件而單獨運行在后臺中。比較好的方法是將后臺的工作放到Service服務中,從而保證進程有一定的優先級,就不會容易被系統殺死了。