1.當默認創建一個新項目時,開發工具會幫我們創建一個MainActivity.java,以下是用AndroidStudio來創建的部分代碼,MainActivity.java的主要代碼(每個人的開發工具不盡相同,在新建項目時可能會同時生成多幾個方法,這時可以忽略掉它們,因為這不影響研究)
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
2.創建和加載新的布局文件
創建新的布局文件這一步可以自己創建一下,我自己創建的一個新的布局文件名為 activity_second.xml。
布局文件創建好之后,再創建一個新的Activity來加載activity_second.xml,這里我創建的Activity名為Activity_second。代碼如下:
public class Activity_second extends AppCompatActivity{ //1
@Override //2
protected void onCreate(Bundle savedInstanceState) { //3
super.onCreate(savedInstanceState); //4
}
}
此時新鮮滾熱辣的Activity_second.java還未將剛才創建的activity_second.xml加載進去呢!此時我們應該做的就是在上面的標號為4的此行代碼后面進行加載布局文件,使用setContentView( )方法進行加載布局文件。
public class Activity_second extends AppCompatActivity{ //1
@Override //2
protected void onCreate(Bundle savedInstanceState) { //3
super.onCreate(savedInstanceState); //4
setContentView(R.layout.activity_second);//這一步操作就是加載布局文件啦!!
}
}
3.在AndroidManifest.xml清單文件中對Activity_second進行注冊操作
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.andre.testactivityapplication">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 下面這些代碼就是對剛才新建的Activity_second進行注冊-->
<activity android:name=".Activity_second">
</activity>
</application>
</manifest>
4.在代碼中銷毀一個Activity
調用finish( )方法即可以銷毀當前的Activity。我下面的代碼是事先在activity_main.xml中定義了一個Button,并設置該Button的onClick屬性為finishActivity。所以在MainActivity中就可以將該Button的onClick屬性聲明為一個方法用于銷毀當前的Activity了。代碼如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void finishActivity(View view){
finish();
}
}
Activity的交互
5.使用Intent(意圖)來連通各個Activity
首先,Activity之間交互是通過(意圖)Intent來進行的,所以我們應該先要將這個(意圖)Intent構建出來,然后將這個(意圖)Intent作為參數傳入startActivity(intent)方法即可實現Activity之間的交互。
Intent是Android程序中各組件之間進行交互的一種重要方式,它不僅可以指明當前組件想要執行的動作,還可以在不同組件之間傳遞數據。Intent一般可被用于啟動活動、啟動服務、以及發送廣播等場景。
--5.1多個Activity使用顯式Intent來進行交互
Intent有多個構造函數的重載,最常用到的是:Intent(Context packageContext, Class<?> cls)。
Intent intent = new Intent(MainActivity.this,Activity_second.class);
startActivity(intent);
我們首先是構建出了一個意圖Intent,將MainActivity.this作為上下文,傳入Activity_second.class作為目標活動。這個Intent的意圖(目的)就是在MainActivity這個活動的基礎上打開Activity_second這個活動。最后,通過調用startActivity( )方法來執行這個Intent意圖。這種意圖比較明顯,所以稱之為顯式Intent。
--5.2單應用中的多個Activity使用隱式Intent進行交互
隱式Intent就是先找到AndroidManifest.xml清單文件中的要跳轉到的目標Activity注冊處,然后在該處添加一個意圖過濾器<intent-filter></intent-filter>,在這個意圖過濾器中指定action和category等信息。最后交由系統去分析這個Intent并幫我們找出合適的Activity去啟動。
主要的清單文件代碼如下:
<activity android:name=".Activity_second">
<intent-filter>
<action android:name="com.example.andre.testactivityapplication.ACTION_START"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
在調用方MainActivity中的主要代碼如下:
Intent intent = new Intent("com.example.andre.testactivityapplication.ACTION_START");
startActivity(intent);
可以看出這里調用了Intent的另一個構造方法,并將一個在清單里面注冊的一個action字段作為參數,然后再調用startActivity( )方法跳轉到Activity_second中去。
注意:這里看似調用Intent的構造方法時漏掉了清單文件中提及的另外一個category字段,其實這個category字段是系統默認的字段,在調用startActivity( )方法時會自動將這個category字段添加到Intent中的。還有:每個Intent中只能指定一個action字段,但可以指定多個category字段,使用Intent的addCategory( )方法來指定多個category字段,但無論是在清單文件中新增category字段,還是在Activity中增加category字段,都一定要在彼此間進行category字段的全部匹配,<category android:name="android.intent.category.DEFAULT"/>除外。
--5.3更多的隱式Intent的用法
使用隱式Intent不單單可以啟動本程序內部的Activity,還可以啟動其它程序的Activity。比如說你的程序想要打開網頁時,只需要調用系統的瀏覽器來打開網頁就可以了,沒必要自己去做一個瀏覽器出來。下面就來看看在自己程序中如何打開瀏覽器并且訪問百度首頁的。
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.parse("http://www.baidu.com");
intent.setData(uri);
startActivity(intent);
6.Activity之間的數據傳遞
--6.1向下一個Activity傳遞數據
在當前的Activity向下一個Activity傳遞數據,使用的依然是Intent,因為Intent提供了很多的putExtra( )方法的重載,可以重載此方法將想要傳遞的一些數據加載到Intent中,然后在目標Activity中使用getIntent( )方法來獲取上一個傳數據進來的Activity中的Intent,最后調用獲取到的Intent中的getxxx( )來將砸破Intent中的數據取出來,這樣就完成了向下一個Activity傳遞數據啦。
當前Activity中的主要代碼:
String datas = "hello world!";
Intent intent = new Intent(this, Activity_second.class);//使用顯式的Intent方式來啟動Activity_second
intent.putExtra("pass_datas",datas);
startActivity(intent);
需要接收數據的目標Activity的主要代碼:
Intent intent = getIntent();
String getPassDatas = intent.getStringExtra("pass_datas");
--6.2將數據返回給上一個Activity
(這小點里面討論的Activity的啟動模式皆為標準模式)討論的是兩種情形,情景一:當前MainActivity通過按鍵來啟動Activity_second,Activity_second啟動完畢之后再調用finish( )方法將自己結束掉,然后就回到了MainActivity;情景二:在啟動了Activity_second之后,通過返回鍵來返回MainActivity。
情景一(自行設置點擊事件):
MainActivity中的主要代碼如下:
Intent intent = new Intent(this, Activity_second.class);//使用顯式的Intent方式來啟動Activity_second
startActivityForResult(intent,1);//參數1為該請求碼,這里傳入1就可以了,也可以傳其它值
Activity_second中的主要代碼如下:
Intent intent = new Intent();//這個Intent是用來傳數據的,并沒有啟動Activity的意圖
intent.putExtra("return_datas","Datas return to MainActivity!");
setResult(RESULT_OK,intent);
finish();
Activity_second中的代碼setResult(RESULT_OK,intent);這個方法專門用于向上一個Activity返回數據的,這方法里的第一個參數表示向上一個Activity返回處理結果,一般只使用RESULT_OK或RESULT_CANCELED這兩個值,第二個參數是將帶有數據的Intent傳遞回去,最后調用finish( )方法將自己銷毀掉返回到MainActivity中。
由于在MainActivity中是調用了startActivityForResult( )方法來啟動Activity_second的,所以在Activity_second被銷毀之后會回調MainActivity中的onActivityResult()方法,所以還要在onActivityResult()方法中進行相應的處理,具體如下:
@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode){
case 1:
String datas = data.getStringExtra("return_datas");
break;
default:
}
}
onActivityResult(int requestCode, int resultCode, Intent data)方法中帶有三個參數,第一參數requestCode即在MainActivity中啟動Activity_second時手動設置的請求碼,第二個參數resultCode即為Activity_second返回數據時傳入的處理結果,第三個參數data是一個攜帶數據的Intent。由于在一個Activity中有可能會調用startActivityForResult()方法來啟動很多個Activity,所以要用requestCode請求碼來區分當前Activity是啟動了哪個Activity,然后通過resultCode來判斷處理結果是否成功,最后從data中將數據取出來,這樣就完成了情景一的工作了。
情景二:
在Activity_second的時候直接按返回鍵時,這時情景一里面Activity_second的點擊事件就無效了,其實可以通過重寫onBackPressed( )方法來解決這個問題的,代碼如下:
@Overridepublic void onBackPressed() {
super.onBackPressed();
Intent intent = new Intent();//這個Intent是用來傳數據的,并沒有啟動Activity的意圖
intent.putExtra("return_datas","Datas return to MainActivity!");
setResult(RESULT_OK,intent);
}
看到沒,onBackPressed()方法里面的邏輯是從情景一中copy過來的,最后在MainActivity中的代碼跟情景一是一樣的,這樣就可以在該情景中實現數據返回上一個Activity了。
Activity的生命周期與啟動模式
7.Activity的生命周期
以上是Android官方的Activity生命周期回調圖,各個方法功能如下:
onCreate:初始化;
onStart:開始activity,界面可見時調用這個方法;
onResume:獲得界面焦點;
onPause:失去界面焦點;
onStop:界面不可見;
onRestart:重新開始打開一個界面,注意,重新打開的界面要處于未被銷毀狀態;
onDestroy:在銷毀實例對象之前調用這個方法;
Resumed:在這個狀態, activity是在最前端的, 用戶可以與它進行交互。 (通常也被理解為"running" 狀態)
Paused:在這個狀態, activity被另外一個activity所遮蓋:另外的activity來到最前面, 但是半透明的, 不會覆蓋整個屏幕。 被暫停的activity不會再接受用戶的輸入且不會執行任何代碼。 (這里的不會執行任何代碼并不代表了任何后臺線程都不會工作)
Stopped:在這個狀態, activity完全被隱藏, 不被用戶可見。 可以認為是在后臺。 當stopped, activity實例與它的所有狀態信息都會被保留, 但是activity不能執行任何代碼。
其它狀態 (Created與Started)都是短暫的, 系統快速的執行那些回調函數并通過執行下一階段的回調函數移動到下一個狀態。 也就是說, 在系統調用onCreate(), 之后會迅速調用onStart(), 之后再迅速執行onResume()。
上面就是基本的Activity生命周期。
8.Activity的啟動模式
注:該小點所用到的圖片皆為郭霖的《第一行代碼》里面的截圖進行修改。
Activity是使用返回棧來管理Activity的,其中Activity有4種啟動模式:standard;singleTop;singleTask;singleInstance。啟動模式是在清單文件中進行設置的,其中standard模式是默認的啟動模式,可以不用在清單文件中進行添加字段。
--8.1standard模式
在MainActivity中的點擊事件里面加入下面代碼:
Intent intent = new Intent(MainActivity.this, MainActivity.class);
startActivity(intent);
然后點擊2次這個點擊事件的按鈕,此時的返回棧如下圖所示,需要連按3次返回鍵才能退出程序。
--8.2singleTop模式
在此模式下當啟動Activity時,如果發現返回棧的棧頂已經是該Activity時,則直接使用它,不會再創建新的Activity;當該返回棧中存在該Activity時,但它并不在棧頂,此時是會重新創建該Activity的。
這種啟動模式需要到清單文件中進行添加launchMode字段,xml代碼如下:
<activity android:name=".MainActivity"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
在MainActivity中啟動Activity_second,代碼如下:
Intent intent = new Intent(MainActivity.this, Activity_second.class);
startActivity(intent);
接著在Activity_second中啟動MainActivity,代碼如下:
Intent intent = new Intent(Activity_second.this, MainActivity.class);
startActivity(intent);
在這種模式下,當你在Activity_second的點擊按鈕中點擊了無數次,都只會有一個MainActivity在返回棧的棧頂,此時按下2次返回鍵就又回到了MainActivity界面中,再按1次就可以退出該程序,如下圖:
--8.3singleTask模式
在此模式下,每次啟動Activity時系統首先會在返回棧中檢查是否存在該Activity的實例,如果發現已經存在則直接使用該實例,并且把在這個Activity之上的所有Activity全部出棧,如果沒有就會創建一個新的Activity實例。
這種啟動模式需要到清單文件中進行添加launchMode字段,xml代碼如下:
<activity android:name=".MainActivity"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
重新運行程序,在MainActivity界面點擊按鈕進入到Activity_second,然后在Activity_second界面點擊按鈕,又會重新進入到MainActivity。
返回棧流程如下:
--8.4
此模式可以解決共享Activity實例的問題,因為每個應用程序都會有自己的返回棧,同一個Activity在不同的返回棧中入棧時必然是創建了新的實例。而使用singleInstane模式時,會有一個單獨的返回棧來管理這個Activity,從而實現共享Activity實例。
將Activity_second添加launchMode字段,xml代碼如下:
<activity android:name=".Activity_second"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="com.example.andre.testactivityapplication.ACTION_START"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
首先創建了Activity_third并在清單文件中進行注冊
public class Activity_third extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
}
}
然后修改修改Activity_second中的點擊事件
Intent intent = new Intent(Activity_second.this, Activity_third.class);
startActivity(intent);
重新運行程序,在MainActivity界面點擊按鈕進入到Activity_second,然后在Activity_second界面點擊按鈕進入到Activity_third。當按下返回鍵進行返回時,發現Activity_third竟然直接返回到MainActivity,再按下返回鍵又會返回到Activity_second,再按一次返回鍵都會退出程序。
原理是這樣的,由于MainActivity和Activity_third是在同一個返回棧里的,當在Activity_third界面中按下返回鍵,Activity_third就會被出棧,此時MainActivity就處于棧頂了從而顯示出來(也就出現了從Activity_third直接返回到MainActivity的情況),當再次按下返回鍵時,MainActivity就會被出棧,此時當前的返回棧已經空了,于是就顯示了另一個返回棧的棧頂Activity,即Activity_second。最后再次按下返回鍵,所有的返回棧都已經空了,也就 退出了程序。返回棧流程如下: