《Android開發實戰 從學習到產品》李瑞琪編著 學習筆記。
Android最常見四組件:Activity、Service、ContentProvider、BroadcastReceiver。
Activity:Android開發最重要的組件,Android應用程序界面,凡是在應用中能看到的東西都是放在Activity中的。
一、Activity生命週期
1、概述
Activityt由Activity棧進行管理,新Activity將被加到Activity棧頂,之前的Activity將位於該新Activity底部。Activity的四種狀態:
- 當Activity位於棧頂,處於屏幕最前方,運行狀態;
- 當Activity失去焦點但任對用戶可見(棧頂Activity透明或未鋪滿屏幕等),暫停狀態;
- 當Activity完全被其他Activity遮擋時,Activity對用戶不可見,處於停止狀態;
- 當Activity被人爲或系統原因銷燬,處於銷燬狀態。
開發過程中寫的Activity一般都繼承Activity類並重寫相應的回調方法,Activity生命週期流程圖如下:
由圖知Activity生命週期的7個事件:
- onCreate():Activity第一次被創建時調用,可在此方法中綁定數據或創建其他視圖控件。
- onStart():當Activity變爲用戶可見之前調用。
- onResume():當Activity可以與用戶交互之前調用,即Activity對象到達Activity棧頂即將成爲前臺進程時調用。
- onPause():當系統調用其他Activity對象時調用(注:新Activity對象必須等待該方法執行完畢再顯示出來,多數情況下onPause()方法要關閉onResume()中打開的方法)。
- onStop():當Activity不可視時調用。
- onDestroy():當銷燬Activity對象時調用。
- onRestart():當處於onStop()狀態的Activity又變爲可視時調用。
除這些方法外,還有3個關鍵的週期循環:
- Activity的完整週期 從第一次調用onCreate(Bundle)設置所有“全局"狀態及完成初始化開始,直至調用onDestroy()釋放所有系統資源。
- Activity的可視生命週期 自onStart()調用開始至onStop()調用爲止,用戶屏幕可見此Activity。
- Activity前臺生命週期 自onResume()調用起,至onPause()調用爲止,該期間Activity位於前臺最上面並與用戶進行交互。
2、實例:
package com.example.day0907_lifeactivity;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
protected void onDestroy(){
super.onDestroy();
Log.i("LifeActivity","onDestroy");
}
protected void onPause(){
super.onPause();
Log.i("LifeActivity","onPause");
}
protected void onResume(){
super.onResume();
Log.i("LifeActivity","onResume");
}
protected void onRestart(){
super.onRestart();
Log.i("LifeActivity","onRestart");
}
protected void onStart(){
super.onStart();
Log.i("LifeActivity","onStart");
}
protected void onStop(){
super.onStop();
Log.i("LifeActivity","onStop");
}
/*onWindowFocusChanged()方法:在Activity窗口獲得或失去焦點時被調動
(在onResume()之後或onPause()之後調用)*/
public void onWindowFocusChanged(boolean hasFocus){
super.onWindowFocusChanged(hasFocus);
Log.i("LifeActivity","onWindowFocusChanged");
}
/*在Activity被覆蓋或退居後臺之後,系統資源不足將其殺死時;用戶改變屏幕方向;
當前Activity跳轉到其他Activity或按Home鍵回到主屏,自身退居後臺時 被調用
調用在onPause()之前*/
protected void onSaveInstanceState(Bundle outState){
Log.i("LifeActivity","onSaveInstanceState");
super.onSaveInstanceState(outState);
}
/*當Activity被覆蓋或局後臺,系統資源不足將其殺死,然後用戶又回到Activity時;
* 用戶改變屏幕方向重建過程中 被調用。調用在onStart()之後*/
protected void onRestoreInstanceState(Bundle savedInstanceState){
Log.i("LifeActivity","onRestoreInstanceState");
super.onRestoreInstanceState(savedInstanceState);
}
}
點擊Android Studio左下角logcat查看日誌(設置查看日誌level爲info,關鍵字爲LifeActivity):
(1).初次運行Activity時:系統調用onCreate和onStart後調用onResume,Activity進入運行狀態。
(2).在模擬機上按Home鍵回主屏幕或跳轉Activity:退居後臺後,Activity窗口焦點發生變化,故先調用onWindowFocusChanged方法,再依次調用各個方法。
(3).重回原Activity:先調用onRestart方法使用戶可見,再調用…
(4). 退出程序:最後調用的onDestroy方法銷燬Activity。
(5).橫屏:期間調用了一次onDestroy方法銷燬Activity及onStart方法打開Activity,故調用了一次onSaveInstanceState方法保存臨時數據,和一次onRestoreInstanceState方法恢復數據。
二、Intent與Activity之間的跳轉
Intent:完成組件之間的通信。(此處僅介紹完成Activity間的通信),Intent應用場合主要三種:
①.啓動一個Activity。
②.啓動一個Service。
③.啓動一個BroadCast。
當使用一個Intent進行組件通信時,需要先實例化一個Intent對象,此時需要設置Intent屬性:
Action(要執行的動作):如ACTION_CALL表示撥打電話、ACTION_EDIT表示調用編輯器、ACTION_SYNC表示同步數據…
Data(執行動作所操作的數據):在Intent中使用指向數據的URI來表示。
Type(顯示指定Intent數據類型):不同動作URI數據類型不同。
Category(執行動作的附加信息)
Component(指定Intent目標組件的類名稱):通常Android根據Intent包含的上述等屬性進行查找,若設置該屬性則查找過程不需執行。
Extras(其他所有附加信息的集合):爲組件提供擴展信息。
另外,使用Intent時根據是否明確指定Intent對象的接收者,分顯示(即在構造Intent對象時就指定接受者)和隱式(在構造Intent對象時不指定接受者,Android需對其進行解析:查找AndroidManifest.xml文件中所有IntentFilter及其定義的Intent,找到最匹配的Intent【判斷Intent的Action、Type、Category找到最匹配的Intent】)的Intent。
1.顯式意圖
要求必須知道被激活組件的包和class
在該項目內創建新Empty Activity(new->)取名爲SecondaryActivity,在activity_secondary.xml內放置一個TextView控件編輯其text內容爲“第二個Activity!”以作標記。
在activity_main.xml內放置一個Button按鈕,使得單擊跳轉到SecondaryActivity界面,並在MainActivity.java內代碼實現跳轉功能:
package com.example.day0907_lifeactivity;
import android.content.Intent;
import androidx.appcompat.app.AppCompatActivity;
import android.view.View;
import android.os.Bundle;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//R類:將Android的資源文件存儲爲鍵值對的一個類(系統自建,勿改),findViewById獲得View控件對象的方法
button = (Button)findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
public void onClick(android.view.View view){
//跳轉到第二個Activity
gotoSecondaryActivity();
}
});
}
private void gotoSecondaryActivity(){
Intent toSecondary = new Intent(); //創建一個意圖
toSecondary.setClass(this,SecondaryActivity.class);//指定跳轉SecondaryActivity
toSecondary.putExtra("name","Ricky"); //設置傳遞字符串
toSecondary.putExtra("age",25); //設置傳遞int類型內容
//上述兩行代碼可改爲如下代碼 android中使用Bundle來共享變量
// Bundle bundle = new Bundle();
// bundle.putString("name","Ricky");
// bundle.putInt("age",25);
// toSecondary.putExtras(bundle);
startActivity(toSecondary);
}
}
在SecondaryActivity.java內代碼接受數據:
package com.example.day0907_lifeactivity;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
public class SecondaryActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_secondary);
Intent intent_accept = getIntent(); //創建一個接收意圖
Bundle bundle = intent_accept.getExtras(); //創建一個Bundle對象用於接收Intent數據
String name = bundle.getString("name"); //獲取Intent的內容name
int age = bundle.getInt("age"); //獲取Intent的內容age
Log.i("SencodaryActivity", name + " " + age);
}
}
程序效果圖:
2.隱式意圖
*可以不知道被激活組件的包和class,只通過指定action就進行跳轉,如果一個Activity想要啓動另一個應用的Activity就只能使用隱式意圖。
3.帶回調方法的意圖
有時需定義在MainActivity中的某一控件啓動SecondaryActivity並當SecondaryAActivity結束時返回給MainActivity一個執行結果。
4.跳轉中對象參數的傳遞
在Android開發中,有時多個Activity之間需要進行對象的傳遞,使用Intent也可以完成這一功能。
MainActivity.java 內的gotoSecondaryActivity方法改爲:
private void gotoSecondaryActivity(){
Intent toSecondary = new Intent(); //創建一個意圖
toSecondary.setClass(this,SecondaryActivity.class);//指定跳轉SecondaryActivity
Bundle bundle = new Bundle();
User user = new User();
user.setAge(25);
user.setName("Ricky");
bundle.putSerializable("user",user);
toSecondary.putExtras(bundle);
startActivity(toSecondary);
//startActivityForResult(toSecondary,RequestCode);//啓動帶請求碼意圖
}
SecondaryActivity.java 內的onCreate方法改爲:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_secondary);
Intent intent = getIntent(); //創建接收意圖
Bundle bundle = intent.getExtras();
User user = (User)bundle.get("user"); //???
Log.i("SecodaryActivity", user.getName()+" "+user.getAge());
}
則單擊第一個Activity中按鈕,日誌顯示爲:
三、Activity啓動模式
Task:以棧來管理Activity。
Activity四種啓動模式:standard、singleTop、singleTask、singleInstance。
- standard:默認啓動模式,若不指定launchMode屬性,就會自動使用這種啓動模式。
聲明爲這種啓動模式的Activity可以被實例化多次,一個任務當中也可以包含多個Activity的實例。 - singleTop:在AndroidManifest.xml中配置的android:launchMode的屬性爲singleTop。singleTop模式,若要啓動的Activity在當前任務中已存在,且處於棧頂的位置,則系統不會再創建一個該Activity實例,而是調用棧頂Activity的onNewIntent()方法。
例:若Task返回棧中有4個Activity:A-B-C-D,D位於棧頂,A位於棧底,若要求再啓動儀一次D,若D啓動模式爲standard則系統再創建一個D實例,此棧內元素爲A-B-C-D-D;若D啓動模式爲singleTop,系統直接調用D的onNewIntent()方法,此時棧內元素任爲A-B-C-D。 - singleTask:該啓動模式表示,系統會創建一個新任務,並將啓動的Activity放入這個新任務的底部,但是若該任務中已經存在該Activity的實例,不會新創建該Activity的實例而是調用該Activity的onNewIntent()方法,故該啓動模式下Activity在同一個任務中只會存在一個實例。
singleTask模式默認情況下只有啓動其他應用程序的Activity纔會創建一個新任務,啓動自己程序中的Activity還是會使用相同的任務。
- singleInstance:singleInstance模式啓動Activity會創建一個新的Task,這種Activity所在的Task中始終只會有一個Activity。通過這個Activity打開其他Activity會被放入別的任務當中。
standard模式是Android默認啓動模式,可能造成多次啓動問題,如用戶手誤多次點擊一個跳轉到新Activity按鈕,系統會創建多個新Activity,而用戶只需一個。singleTop模式可避免這個問題,該模式在啓動Activity時,如果發現該返回棧中的棧頂已是該Activity時,就認爲可以直接使用它而不會創建新的Activity實例。若要啓動的Activity不在棧頂,還是會創建該Activity的實例。將啓動模式設置爲singleTask,每次啓動Activity時系統首先在返回棧中檢查是否有該Activity的實例,若有就直接使用該Activity的實例,並將這個Activity上的所有活動統統出棧,若沒有就會創建一個新的Activity。而singleInstance模式的活動將會啓用一個新的返回棧來管理這個活動,解決了多個應用訪問一個Activity時的共享問題。