文章目錄
- Android第一行代碼
-
- Activity
-
- 1、Activity基本用法
- 2、建立和加載布局
-
- 加載布局(在Activity中加載布局)
- 在AndroidManifest檔案中注冊(所有的activity都要在AndroidManifest.xml中進行注冊)
- 配置主Activity(activity标簽内部添加标簽)
- 在Activity中使用Toast
- 在活動中使用Menu()
- 三、使用Intent在活動之間穿梭
-
- 1、使用顯示Intent
-
- 顯示Intent
- 隐式Intent(不指明具體想要啟動哪個活動)
-
- 更多隐式Intent的用法
- 向下一個活動傳遞資料(放入Intent,從Intent取出)
- 傳回資料給上一個活動(startActivityForResult())
- 活動的生命周期
-
- 傳回棧
- 活動狀态(運作、暫停、停止、銷毀)
- 活動的生存期(7個回調函數,OnCreate、onStart、onResume、onPause、onStop、onDestroy、onRestart)
- 體驗活動的生命周期
- 活動被回收了怎麼辦(onSaveInstanceState())
- 活動的啟動模式(standard、singleTop、singletask、singleInstance)
-
- standard
- singleTop
- singleTask
- singleInstance
- 活動的最佳實踐
-
- 如何判斷程式的目前頁面是哪個活動?
- 随時退出程式(用專門的集合類對所有活動進行管理)
Android第一行代碼
Activity
1、Activity基本用法
一種可以包含使用者界面的元件,一個應用可以包含0或多個活動
在建立activity的時候:
- 1、如果勾選Generate Layout File表示會自動為FirstActivity建立一個對應的布局檔案
- 2、勾選Launcher Activity表示會自動将FirstActivity設定為目前項目的主Activity
- 3、任何Activity都應該重寫onCreate()方法。
2、建立和加載布局
Android程式講究邏輯和視圖分離,最好每一個Activity都能對應一個布局,布局是用來顯示頁面内容的。
在建立好Layout檔案之後,會布局編輯器,視窗左下角有兩個切換卡:
- Design:可視化布局編輯器,在這可以通過拖放的方式編輯布局。
- Text:通過XML檔案的方式編輯布局。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button 1"
/>
</LinearLayout>
上面線性布局中添加了一個Button元素,并在内部增加了幾個屬性:
- 1、android:id 給目前的元素定義一個唯一的辨別符。
- 2、在XML中引用一個id,就是用@id/id_name這種文法,如果在XML中定義一個id,則需要使用@+id/id_name這種文法
- 3、android:layout_width 指定目前元素的寬度。
- 4、android:layout_height 指定目前元素的高度。warp_content表示目前元素的高度隻要能剛好包含裡面的内容就行
- 5、android:text 指定了元素顯示的文字内容
右側工具欄Preview用來預覽目前布局
加載布局(在Activity中加載布局)
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class FirstActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//傳入布局檔案的id
setContentView(R.layout.first_layout);
}
}
在setContentView()方法用來給目前的Activity加載布局。一般會傳入一個布局檔案的id。項目中的任何資源都會在R檔案中生成一個相應的資源id。
在AndroidManifest檔案中注冊(所有的activity都要在AndroidManifest.xml中進行注冊)
AndroidManifest.xml檔案
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.activitytest">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".FirstActivity"></activity>
</application>
</manifest>
所有的activity都要在AndroidManifest.xml中進行注冊才能生效。Activity的聲明要放在< application>标簽内。這裡是通過Activity标簽來對Activity進行注冊的。
在< activity>标簽内,我們使用android:name來指定具體注冊哪一個Activity,.FirstActivity是com.example.activitytest.FirstActivity的縮寫。因為manifest标簽中已經通過package屬性制定了程式的包名。是以才可以省略。
配置主Activity(activity标簽内部添加标簽)
如果不配置主Activity,那麼程式就不知道啟動哪個Activity。配置主Activity就是要在标簽的内部加入标簽。并且在這個标簽内部添加和
修改後的AndroidManifest.xml檔案
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.activitytest">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
在Activity中使用Toast
Toast是Android提供的一個很好的提醒方式,可以将一些短小的資訊通知給使用者,并在一段按後自動消失。
package com.example.activitytest;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class FirstActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_layout);
//findViewById()這個方法擷取在布局檔案中定義的元素
//findViewById方法傳回的是一個View對象,我們可以向下轉型将其轉成Button對象
Button button1 = findViewById(R.id.button1);
//通過調用setOnClickListener方法為按鈕注冊一個監聽器
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//makeText靜态方法建立一個Toast對象,然後調用show将toast顯示出來即可。
//makeText的三個參數,
// 第一個參數是Context即Toast要求的上下文,由于活動本身就是一個Context對象,是以這裡直接傳入FirstActivity.this即可
//第二個參數是Toast顯示的文本内容
//第三個參數是Toast顯示的時長
Toast.makeText(FirstActivity.this,"You clicked Button 1",Toast.LENGTH_SHORT).show();
}
});
}
}
在活動中使用Menu()
res目錄下建立menu目錄,在menu檔案夾中建立Menu resource file。
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/add_item"
android:title="Add" />
<item
android:id="@+id/remove_item"
android:title="Remove"/>
</menu>
标簽用來建立具體的菜單項,然後通過android:id給這個菜單項指定一個唯一的辨別,android:title給菜單項指定一個名稱。
package com.example.activitytest;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class FirstActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_layout);
//findViewById()這個方法擷取在布局檔案中定義的元素
//findViewById方法傳回的是一個View對象,我們可以向下轉型将其轉成Button對象
Button button1 = findViewById(R.id.button1);
//通過調用setOnClickListener方法為按鈕注冊一個監聽器
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//makeText靜态方法建立一個Toast對象,然後調用show将toast顯示出來即可。
//makeText的三個參數,
// 第一個參數是Context即Toast要求的上下文,由于活動本身就是一個Context對象,是以這裡直接傳入FirstActivity.this即可
//第二個參數是Toast顯示的文本内容
//第三個參數是Toast顯示的時長
Toast.makeText(FirstActivity.this,"You clicked Button 1",Toast.LENGTH_SHORT).show();
}
});
}
//重寫方法可以使用快捷鍵Ctrl+O
//Menu是一個接口
@Override
public boolean onCreateOptionsMenu(Menu menu) {
//Inflater [ɪnf'leɪtər] 打氣筒,充氣機,網絡
//getMenuInflater()方法可以獲得MenuInflater對象
//然後調用它的inflate()方法就可以給目前活動建立菜單
//inflate第一個參數指定我們通過哪一個資源檔案來建立菜單,這裡指定main.xml
//第二個參數指定我們的菜單項添加到哪一個Menu對象中
getMenuInflater().inflate(R.menu.main,menu);
//表示允許将建立的菜單顯示出來
//false表示建立的菜單将無法顯示
return true;
}
//定義菜單響應事件
//MenuItem是一個接口
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.add_item:
Toast.makeText(this, "You clicked add", Toast.LENGTH_SHORT).show();
break;
case R.id.remove_item:
Toast.makeText(this, "You clicked Remove", Toast.LENGTH_SHORT).show();
break;
default:
}
return true;
}
}
三、使用Intent在活動之間穿梭
如果有多個活動,在啟動器中點選應用的圖示隻會進入到該應用的主活動。如何跳轉其他活動呢?
Intent分為兩種:顯示Intent和隐式Intent
1、使用顯示Intent
建立第二個Activity即SecondActivity,并生成對應的layout檔案,AndroidStudio會自動在AndroidManifest中進行注冊,由于不是主活動,不需要在AndroidManifest.xml中的activity标簽中配置< intent-filter>标簽中的内容。一系列操作結束後,如何啟動這第二個活動?
Intent [ɪn’tent] 專注、意圖
Intent是Android程式中各元件之間進行互動的一個重要的方式,它不僅可以指明目前元件想要執行的動作,還可以在不同元件之間進行傳遞資料。
Intent一般可被用于啟動活動、啟動服務以及發送廣播等場景。
顯示Intent
Intent的多個構造函數的重載:
- Intent(Context packageContext,Class<?> cls),第一個參數Context要求提供一個啟動活動的上下文,第二個參數Class則是指定想要啟動活動的目标活動
startActivity()方法是專門用于啟動活動的。他接收一個Intent參數,把建構好的Intent傳入startActivity()方法就可以啟動目标活動。
//在主活動的onCreate函數中添加如下代碼即可點選button1按鈕啟動SecondActivity了。
button1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
//FirstActivity作為上下文,SecondActivity為目标活動
//那麼我們的意圖就非常明顯了,即在FirstActivity的基礎上打開SecondActivity,并通過startActivity來執行
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
startActivity(intent);
}
})
隐式Intent(不指明具體想要啟動哪個活動)
不明确指出我們想要啟動哪一個活動,而是指定一系列更為抽象的action和category等資訊,然後交給系統去分析這個Intent,并幫我們找出合适的活動去啟動。
通過在< activity>标簽下配置< intent-filter>的内容,可以指定目前活動能夠響應的action和category
如:
<activity android:name=".SecondActivity">
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
從上面的配置在AndroidManifest.xml的action可以看出,指明了目前活動可以響應com.example.activitytest.ACTION_START這個action。而< category>标簽則包含了一些附加資訊,更精确指明了目前活動能夠響應的Intent中還可能帶有的category,隻有< action> < category>中的内容同時能夠比對上Intent中指定的action和category的時候,這個活動才能響應該Intent
比如FirstActivity的onCreate下面的代碼就可以啟動上面所定義的activity:
button1.setOnClickListener(new View.onClickListener(){
@Override
public void onClick(View v){
//因爲上面xml檔案指明了activity的action為com.example.activitytest.ACTION_START
//建立Intent(意向),要傳入相應參數
//就會調用相應的activity
Intent intent = new Intent("com.example.activitytest.ACTION_START");
startActivity(intent);
}
})
更多隐式Intent的用法
Intent讓多個應用程式之間的功能共享成為可能,比如你打電話,沒必要自己去實作一個撥打電話功能,隻需要調用系統的撥打電話功能即可。
button1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
//Intent.ACTION_VIEW在Intent類中定義為
//public static final String ACTION_VIEW = "android.intent.action.VIEW";
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
}
});
在上面的代碼中首先指定了意向的action為Intent.ACTION_VIEW。setData制定了目前正在操作的資料,而這些資料通常都是以字元串的形式傳入到Uri.parse()方法中解析産生的。
<activity android:name=".ThirdActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="tel" />
</intent-filter>
</activity>
如果在Intent中設定了Data,我們可以在中再配置一個标簽,用于精确制定目前活動能夠響應什麼類型的資料。标簽中主要可以配置以下内容:
- 1、andorid:scheme:用于指定資料的協定部分,如上例中的http部分
- 2、android:host:用于指定資料的主機名部分,如上例中的www.baidu.com
- 3、android:port:用于指定資料的端口部分,一般緊随在主機名之後
- 4、android:path:用于制定主機名和端口之後的部分,如一段網址中跟在域名之後的内容
- 5、andorid:mimeType:用于指定可以處理的資料類型,允許使用通配符的方式進行指定。
隻有标簽中指定的内容和Intent中攜帶的Data完全一緻時,目前活動才能夠響應該Intent。
向下一個活動傳遞資料(放入Intent,從Intent取出)
在啟動活動的時候傳遞資料的思路很簡單,Intent中提供了一系列putExtra()方法的重載,可以吧我們想要傳遞的資料暫存在Intent中,啟動另外一個活動的時候,隻需要把資料從Intent中再取出即可。
例子:
想把FisrtActivity中的一個字元串傳遞到SecondActivity中。
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String data = "Hello SecondActivity";
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
intent.putExtra("extra_data",data);
startActivity(intent);
}
});
在SecondActivity将傳遞的資料取出,并列印:
public class SecondActivity extends AppCompatActivity {
//Bundle主要用于傳遞資料,它儲存的是資料,是以key-value(鍵值對)的形式存在的
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_layout);
Intent intent = getIntent();
String data = intent.getStringExtra("extra_data");
Log.d("SecondActivity",data);
}
}
getIntent()用于擷取到用于啟動SecondActivity的Intent,然後調用getStringExtra()方法來擷取傳遞的資料。。
傳回資料給上一個活動(startActivityForResult())
Activity中還有一個startActivityForResult()也是用來啟動活動的,但是這個方法期望在活動銷毀的時候能夠傳回一個結果給上一個活動。
startActivityForResult方法的兩個參數:
- 1、Intent
- 2、請求碼,用于在之後的回調中判斷資料的來源。
例子:
修改FirstActivity中按鈕的點選事件
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
startActivityForResult(intent,1);
}
});
startActivityForResult()方法用來啟動SecondActivity,請求碼隻要唯一即可。
SecondActivity中給按鈕添加點選事件,并在點選事件中添加傳回資料的邏輯。
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_layout);
Button button2 = (Button)findViewById(R.id.button_2);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
//把資料放入Intent中
intent.putExtra("data_return","Hello FirstActivity");
//專門向上一個活動傳回處理結果
setResult(RESULT_OK,intent);
finish();
}
});
}
}
setResult()方法專門用于向上一個活動傳回資料。有兩個參數:
- 第一個參數用于向上一個活動傳回處理結果,一般是RESULT_OK或RESULT_CANCELED
- 第二個為Intent,調用finish()來銷毀目前活動。
由于使用startActivityForResult()來啟動SecondActivity,在SecondActivity被銷毀之後會回調上一個活動的onActivityResult()方法。是以需要在FirstActivity中重寫這個方法來得到傳回的資料。
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
switch (requestCode){
case 1:
if (requestCode == RESULT_OK){
String returnedData = data.getStringExtra("data_return");
Log.d("FirstActivity",returnedData);
}
break;
default:
}
}
- 1、requestCode為啟動活動時傳入的請求碼
- 2、resultCode即在傳回資料時傳入的處理結果
- 3、Intent
上面是通過點選按鈕,如果通過Back回到FirstActivity是資料就無法傳回。可以在SecondActivity中重寫onBackPressed()方法解決:
@Override
public void onBackPressed(){
Intent intent = new Intent();
intent.putExtra("data_return","Hello FirstActivity");
setResult(RESULT_OK,intent);
finish();
}
活動的生命周期
傳回棧
Android的活動是可以層層疊加的,我們每啟動一個新的活動,就會覆寫在原活動之上,點選back就會銷毀最上面的活動,下面的一個活動就會重新顯示出來。
==Android是使用任務來管理活動的,一個任務就是一組存放在棧中的活動的集合,這個棧就稱為傳回棧。==每啟動一個新的活動,就會入棧,處于棧頂的位置,按下back或者調用finish()方法去銷毀一個活動的時候,處于棧頂的活動就會出棧,前一個入棧的活動就會重新處于棧頂的位置,系統總是會顯示處于棧頂的活動給使用者。
活動狀态(運作、暫停、停止、銷毀)
- 1、運作狀态:活動位于棧頂,系統最不願意回收,因為會給使用者帶來非常差的體驗)
- 2、暫停狀态:不處于棧頂,但是仍然可見(因為并不是每個活動都會占滿整個螢幕),這時活動處于暫停狀态。系統也不願意去回收這種活動,因為回收可見東西都會給使用者體驗帶來不好的影響,隻有在記憶體極低的情況下,系統才會考慮回收這種活動。
- 3、停止狀态:當活動不在棧頂位置且完全不可見的時候,系統仍然回味這種活動儲存相應的狀态和成員變量,但是這并不是完全可靠的,當其他地方需要記憶體的時候,處于停止狀态的活動可能會被系統回收
- 4、銷毀狀态:一個活動從棧中移除就變成了銷毀狀态。
活動的生存期(7個回調函數,OnCreate、onStart、onResume、onPause、onStop、onDestroy、onRestart)
Activity定義了7個回調函數,覆寫了活動生命周期的每一個環節。
- 1、onCreate:每個活動都會重寫這個方法,會在活動第一次被建立的時候調用,你應該在這個方法中完成活動的初始化,比如加載布局、綁定事件等
- 2、onStart:這個方法在活動由不可見變為可見的時候調用
- 3、onResume:恢複。這個方法在活動準備好和使用者進行互動的時候調用,此時的活動位于傳回棧的棧頂,并且處于運作狀态。
- 4、onPause:這個方法在系統準備去啟動或者恢複另一個活動的時候調用,我們常常會在這個方法中将一些消耗cpu的資源釋放掉,以及儲存一些關鍵資料,但是這個方法的執行一定要快,不然會影響到新的棧頂活動的使用。
- 5、onStop:這個方法在活動完全不可見的時候調用,他和onPause的差別在于,如果啟動的新活動是一個對話框式的活動,那麼onPause方法會得到執行,而onStop方法并不會執行
- 6、onDestroy:這個方法在活動被銷毀之前調用,之後活動的狀态将變為銷毀狀态
- 7、onRestart:這個方法在活動由停止變為運作狀态之前調用,也就是活動被重新啟動了。
以上7個方法除了onRestart之外都是兩兩相對的,進而又可以将活動分為3中生存期。
- 完整生存期:活動在onCreate和onDestroy之間所經曆的,就是完整生存期。
- 可見生存期:onStart和onStop之間所經曆的是可見生存期。在可見生存期内,活動對于使用者總是可見的。
- 前台生存期:活動在onResume和onPause方法之間所經曆的就是前台生存期,在前台生存期内,活動總是處于運作狀态的,此時的活動是可以和使用者進行互動的,我們平時看到和接觸最多的也就是這個狀态下的活動。
體驗活動的生命周期
如何将一個普通活動設定為對話框式的活動?下面将DialogActivity設定為對話框式活動
- 修改AndroidManifest.xml的标簽的配置,添加android:theme屬性
<activity android:name=".DialogActivity" android:theme="@android:style/Theme.Dialog">
</activity>
android:theme屬性用于給目前活動指定主題,有很多内置主題,也可以定制自己的主題,@android:style/Theme.Dialog就是讓DialogActivity使用對話框式的主題。
package com.example.activitylifecycletest;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
public static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button startNormalActivity = (Button)findViewById(R.id.start_normal_activity);
final Button startDialogActivity = (Button)findViewById(R.id.start_dialog_activity);
startNormalActivity.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,NormalActivity.class);
startActivity(intent);
}
});
startDialogActivity.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,DialogActivity.class);
startActivity(intent);
}
});
}
@Override
protected void onStart() {
super.onStart();
Log.d(TAG,"onStart");
}
@Override
protected void onResume() {
super.onResume();
Log.d(TAG,"onResume");
}
@Override
protected void onPause() {
super.onPause();
Log.d(TAG,"onPause");
}
@Override
protected void onStop() {
super.onStop();
Log.d(TAG,"onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG,"onDestroy");
}
@Override
protected void onRestart() {
super.onRestart();
Log.d(TAG,"onRestart");
}
}
從上面的代碼可以看到,給兩個按鈕注冊了點選事件
當MainActivity第一次被建立的時候會執行onCreate()、onStart()、onResume()方法。
點選按鈕1會啟動NormalActivity:
- 1、點選第一個按鈕,由于NormalActivity會把MainActivity完全遮擋住,是以onPause()和onStop()方法都會執行。
- 2、按下back,會傳回MainActivity,執行onRestart、onStart、onResume方法
點選按鈕2會啟動DialogActivity:
- 1、點選按鈕2可以看到onPause()方法得到了執行,onStop()并沒有執行。因為DialogActivity并沒有完全遮擋住MainActivity。此時MainActivity隻是進入了暫停狀态。
- 2、按下Back鍵傳回MainActivity也應該隻有onResume()方法會得到執行。
最後在MainActivity按下Back鍵退出程式,依次會執行onPause() onStop() onDestroy()
活動被回收了怎麼辦(onSaveInstanceState())
這個方法保證在活動被回收之前會被調用,是以可以通過這個方法來解決活動被回收時臨時資料得不到儲存的問題
onSaveInstanceState()會攜帶一個Bundle類型的參數,Bundle提供了一系列的方法用于儲存資料,不如putString()方法儲存字元串。
onSaveInstanceState函數的兩個參數:
- 1、鍵
- 2、需要儲存的内容
@Override
protected void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
String tempData = "Something you just typed";
outState.putString("data_key",tempData);
}
資料已經儲存下來了,如何恢複?onCreate()其實有一個Bundle類型的參數,這個參數一般情況下都是null,但是如果在活動被系統回收之前有通過onSaveInstanceState()方法來儲存資料的話,這個參數就會帶有之前所儲存的全部資料。
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
Log.d(TAG,"onCreate");
setContentView(R.layout.activity_main);
if(savedInstanceState != null){
String tempData = savedInstanceState.getString("data_key");
Log.d(TAG,tempData);
}
}
Bundle還可以結合Intent一起用于傳遞資料,首先需要把需要傳遞的資料都儲存在Bundle對象中,然後再将Bundle對象存放在Intent裡,到了目标活動之後先從Intent中取出Bundle,再從Bundle中一一取出資料。
活動的啟動模式(standard、singleTop、singletask、singleInstance)
可以在AndroidManifest.xml中通過标簽指定android:launchMode屬性來選擇啟動模式。
standard
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
Log.d("FirstActivity",this.toString());
setContentView(R.layout.first_layout);
Button button1 = (Button)findViewById(R.id.button_1);
button1.setOnClickListener(new View.onClickListener(){
@Override
public void onClick(View v){
Intent intent = new Intent(FirstActivity.this,FirstActivity.class);
startActivity(intent);
}
});
}
==standard模式下,每當啟動一個新的活動,都會建立該活動的一個新的執行個體。==是以每次點選按鈕,都會建立FirstActivity的執行個體。多次點選,需多次按back鍵才能退出程式。
singleTop
<activity
android:launchMode="singleTop">
</activity>
當啟動模式指定為singleTop,在啟動活動時如果發現傳回棧的棧頂已經是該活動,則認為可以直接使用他,不會再建立新的活動執行個體。但是如果啟動活動不是棧頂,那麼就會建立新的執行個體入棧。
singleTask
當活動的啟動模式為singleTask,每次啟動該活動時系統首先會在傳回棧中檢查是否存在該活動的執行個體,如果發現已經存在,則直接使用該執行個體,并把這個活動之上的所有活動統統出棧,如果沒有則會建立一個新的活動執行個體。
singleInstance
指定為singleInstance模式的活動會啟動一個新的傳回棧來管理這個活動。
如果我們想其他程式和我們的程式可以共享這個活動的執行個體,如何實作?
- 1、前面的三中啟動模式是做不到的,因為每個程式都會有自己的傳回棧,同一個活動在不同的傳回棧中入棧時必然是建立了新的執行個體。
- 2、在singleInstance模式下,會有一個單獨的傳回棧來管理這個活動,不管是哪個應用程式來通路這個活動,都公用的同一個傳回棧,也就解決了共享活動執行個體的問題。
将活動2的運作模式修改成singleTask,在活動1的onCreate中開啟活動2,在活動2的onCreate中開啟活動3,那麼活動1和活動3就會在一個傳回棧中,活動2會在一個單獨的傳回棧中。到活動3點選back,那麼直接會回退到活動1,那麼這個傳回棧就空了,再點選back,就顯示了另一個傳回棧的棧頂活動,即就到了活動2.
活動的最佳實踐
如何判斷程式的目前頁面是哪個活動?
通過new-》java Class來建立一個類BaseActivity類,BaseActivity不需要再AndroidManifest.xml中進行注冊。讓BaseActivity繼承自AppCompatActivity,修改BaseActivity代碼,讓其他活動類繼承自BaseActivity。
public class BaseActivity extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
Log.d("BaseActivity",getClass().getSimpleName());
}
}
修改之後每進入一個活動的頁面,該活動的類名就會被列印出來。這樣我們就可以時時刻刻知曉目前頁面對應的是哪個活動了。
随時退出程式(用專門的集合類對所有活動進行管理)
建立一個ActivityCollector類作為活動管理器。
public class ActivityCollector{
public static List<Activity> activities = new ArrayList();
public static void addActivity(Activity activity){
activities.add(activity);
}
public static void removeActivity(Activity activity){
activities.remove(activity);
}
public static void finishAll(){
for(Activity activity:activities){
if(!activity.isFinishing())
activity.finish();
}
}
}
在BaseActivity的onCreate()方法中調用ActivityCollector的addActivity()方法,onDestroy方法中調用ActivityCollector的removeActivity()方法.