安卓的Activity活動棧
多個安卓Activity中的先後次序問題,需要用活動棧機制
如圖:
- 每當新打開一個Activity時,會入棧,此時只有這個Activity是活動狀態
- 除了棧頂的Activity其餘的都處於暫停或者停止狀態
- 如果內存不足,需要殺死Activity時,會釋放資源使Activity處於非活動狀態
安卓Activity的活動狀態
分爲四種:
- 活動狀態:在活動棧處於棧頂的Activity,能被用戶看到且可以交互,簡單來說就是屏幕當前的Activity
- 暫停狀態:當前Activity被部分遮擋,不再處於活動棧棧頂,並且無法交互。這裏的部分遮擋是要被Activity遮擋,彈出框之類的不算被遮擋
- 停止狀態:當前Activity被完全遮擋。比如按下HOME鍵或者跳轉到別的頁面
- 非活動狀態:不是上面三種狀態的Activity,例如被銷燬的Activity
Activity活動狀態切換觸發回調方法
如圖,轉化過程如下:
- 當Activity生成時調用onCreate、onStart、onResume(相當於可以交互了),之後Activity開始運行
- 如果Acttvity處於暫停狀態,會調用onPause
- Acitivty重新可以交互時調用onResume
- Activity變成停止狀態,調用onPause和onStop
- Activity從停止狀態變成活動狀態,會調用onRestart和onStart和onResume方法
- 當前Activity從活動狀態直接被銷燬依次調用onPause、onStop、onDestory
- 當Activity處於暫停狀態或者停止狀態時,如果內存不足需要殺死Activty,進程終止,再打開需要重新生成
代碼:
package net.onest.activitych0402;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
public class MainActivity extends AppCompatActivity {
private EditText etMsg;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e("MainActivity","onCreate");
etMsg = findViewById(R.id.et_msg);
if (null != savedInstanceState){
Log.e("onCreate",savedInstanceState.getString("msg"));
}
}
@Override
protected void onStart() {
super.onStart();
Log.e("MainActivity","onStart");
}
@Override
protected void onRestart() {
super.onRestart();
Log.e("MainActivity","onRestart");
}
@Override
protected void onResume() {
super.onResume();
Log.e("MainActivity","onResume");
//將數據進行恢復(讀取文件,查詢數據庫等)
}
@Override
protected void onPause() {
super.onPause();
Log.e("MainActivity","onPause");
//將頁面的用戶數據進行保存(文件、數據庫中)
}
@Override
protected void onStop() {
super.onStop();
Log.e("MainActivity","onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.e("MainActivity","onDestroy");
}
public void buttonClicked(View view) {
switch (view.getId()){
case R.id.btn_dialog:
Intent intent = new Intent();
intent.setClass(MainActivity.this,
DialogActivity.class);
startActivity(intent);
break;
case R.id.btn_new:
Intent intent1 = new Intent();
intent1.setClass(MainActivity.this,
NewActivity.class);
startActivity(intent1);
// finish();
break;
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
Log.e("MainActivity","onSaveInstanceState");
super.onSaveInstanceState(outState);
//保存用戶數據
outState.putString("msg",etMsg.getText().toString());
}
@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
Log.e("MainActivity","onRestoreInstanceState");
super.onRestoreInstanceState(savedInstanceState);
//恢復用戶數據
String content = savedInstanceState.getString("msg");
//顯示到界面
etMsg.setText(content);
}
}
PS:
1. 如果想處於暫停狀態,需要一個Activity覆蓋到當前的Activity上面,並且不是完全覆蓋,操作如下:
在資源目錄下的values的styles.xml文件中,寫一個樣式,例如:
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
// 這裏item是定義自己獨特的地方的標籤,我們需簡要吧windowIsFloating設置爲true
<style name="DialogActivity" parent="AppTheme">
<item name="android:windowIsFloating">true</item>
</style>
</resources>
在manifests中設置activity的樣式
<activity
android:name=".DialogActivity"
android:theme="@style/DialogActivity" /> <!--此處樣式改成上面寫好的那個-->
跳轉到這樣生成的Activity上,原來的就會處於暫停狀態
2.
在返回時使用finish方法結束當前Activity,而不是去跳轉回原來的Activity,
如果跳轉回去就會產生兩個不一樣的Activity
// 比如我從MainActivity跳轉到NewActivity
Intent intent = new Intent();
intent.setClass(MainActivity.this,NewActivity.class);
startActivity(intent);
// 如果在NewActivity中使用finish方法就會回到MainActivity中,並且只有一個
// 如果用下面的這種方法,會產生兩個MainActivity,假如第一個Activity中已經寫好部分信息,跳轉回去產生新的MainActivity中不會有那部分信息
Intent intent = new Intent();
intent.setClass(NewActivity.this,MainActivity.class);
startActivity(intent);
3.ToolBar工具欄
我們需要在XML中先設置一個樣式=>沒有ActivityBar的樣式
資源位置還在剛纔的styles.xml文件中寫
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> => 此處parent爲重點
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
然後在佈局中添加一個ToolBar(需要有這個的佈局中寫)
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
app:title="新的Activity"
app:navigationIcon="@drawable/back"/> => 這個地方設置返回按鈕
最後在java代碼中替換掉ActivityBar
Toolbar toolbar = (Toolbar) findViewById(R.id.toolBar); // 找到組件
toolbar.setTitle("ToolBarDemo"); // 設置標題
setSupportActionBar(toolbar); // 替換
手機的橫豎屏轉換時的問題
當橫豎屏轉換時,會將原來的Activity銷燬,產生一個新的Activity,導致的問題是原來寫好的內容沒了。
此時有兩種方法可以解決:
- 藉助onPause和onRestart方法將數據存到文本或者數據庫中
- 藉助兩個回調方法臨時保持狀態(第一個方法也是兩個回調方法,不是那兩個)
第二種的實現方式爲重寫onSaveInstanceState和onRestoreInstanceState方法,兩個方法都有參數Bundle,藉助於Bundle存鍵值對即可,例如:
@Override
protected void onSaveInstanceState(Bundle outState) {
Log.e("MainActivity","onSaveInstanceState");
super.onSaveInstanceState(outState);
//保存用戶數據
outState.putString("msg",etMsg.getText().toString());
}
@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
Log.e("MainActivity","onRestoreInstanceState");
super.onRestoreInstanceState(savedInstanceState);
//恢復用戶數據
String content = savedInstanceState.getString("msg");
//顯示到界面
etMsg.setText(content);
}