說說 Activity 那些事
Activity就是每一個應用的界面,凡事顯示在app中的界面都是Activity或者由Activity啟動。
基本使用
- 使用as快捷建立Activity
- 常規創建
- 在app/src/main/AndroidManifest.xml注冊
- 編寫java代碼繼承自Activity或者它的子類
自動創建的Activity如下所示:
就是一個activity的標簽
傳遞數據
我們現在創建兩個Activity由MainActivity向SecondActivity傳遞一個字符串“HelloWorld”
- 在MianActivity中設置帶有數據的intent
- startActivityForResult啟動activity,第二個參數是請求碼
- 重寫onActivityResult接受數據
SecondActivity
setResult(666);
String hello = getIntent().getBundleExtra("hello").getString("nihao");
設置結果碼—>拿到數據
完整代碼
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//在按鈕中注冊的方法
public void start(View view) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
Bundle bundle = new Bundle();
bundle.putString("nihao", "HelloWorld");
intent.putExtra("hello", bundle);
startActivityForResult(intent, 0);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == 666) {
System.out.println("世界你好");
}
}
}
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
setResult(666);
String hello = getIntent().getBundleExtra("hello").getString("nihao");
TextView textView = (TextView) findViewById(R.id.tv);
textView.setText(hello);
}
//在按鈕中注冊的方法
public void finsh(View view) {
this.finish();
}
}
生命周期
- onCreate方法負責初始化數據、視圖、綁定事件的監聽
- onStart和onStop是從是否可見的角度分析
- onResume和onPause是從是否在前臺的角度分析
- onStart可見不能獲得焦點—>onResume可見能獲得焦點—->onPause可見不能獲得焦點—->onStop不可見不能獲得焦點
Android官方周期
正常的生命周期
onCreate—->onStart——>onResume——>onPause—–>onStop—–onDestory正好6個生命周期
異常生命周期
用戶按主頁鍵
然后再次返回這個activity:
突然來一個電話
生命周期和上面的一樣
當要啟動的另一個Activity主題色是透明的時候那么這時這個Activity不會調用onStop方法
也就是說它還可見,符合邏輯
系統配置改變比如說屏幕旋轉
當前的Activity被銷毀重新創建
在屏幕旋轉的時候會調用onSaveInstanceState和onRestoreInstanceState用來保存和恢復組件的狀態(注意as默認創建的Activity繼承自AppCompatActivity,這里的兩個方法要使用使用AppCompatActivity中的)
當狀態改變調用onSaveInstanceState保存狀態然后調用onRestoreInstanceState恢復狀態:
旋轉屏幕時狀態分析
當屏幕發生旋轉后數據會保存到savedInstanceState和onCreate方法中的savedInstanceState
protected void onRestoreInstanceState(Bundle savedInstanceState)
橙色線表示屏幕旋轉
那么會保存view的哪些信息呢?這要看對應的view的onSaveInstanceState方法,比如EditText的正在編輯的信息就會丟失。
那么怎么屏蔽屏幕旋轉的信息呢???
—————–看法寶——————-
只要在activity注冊的時候加入configChanges標簽就可以,注意假如是屏蔽旋轉的話應該是orientation|screenSize兩個屬性
從此媽媽再也不用擔心我的學習了,哈哈哈!!!!
####鎖屏和屏幕解鎖
只是調用了onPause和onStop沒有銷毀Activity
###可見性
activity的完整生存期會在 onCreate() 調用和 onDestroy() 調用之間發生。
activity的可見生存期會在 onStart() 調用和 onStop() 調用之間發生。系統會在activity的整個生存期內多次調用 onStart() 和onStop(), 因為activity可能會在顯示和隱藏之間不斷地來回切換。
activity的前后臺切換會在 onResume() 調用和 onPause() 之間發生。 因為這個狀態可能會經常發生轉換,為了避免切換遲緩引起的用戶等待,這兩個方法中的代碼應該相當地輕量化。
activity回收和保存信息
onSaveInstanceState方法
在activity 可能被回收之前 調用,用來保存自己的狀態和信息,以便回收后重建時恢復數據(在onCreate()或onRestoreInstanceState()中恢復)。旋轉屏幕重建activity會調用該方法,但其他情況在onRause()和onStop()狀態的activity不一定會調用 ,下面是該方法的文檔說明。
系統靈活的來決定調不調用該方法, 但是如果要調用就一定發生在onStop方法之前,但并不保證發生在onPause的前面還是后面。
onRestoreInstanceState方法
這個方法在onStart 和 onPostCreate之間調用,在onCreate中也可以狀態恢復,但有時候需要所有布局初始化完成后再恢復狀態。
啟動模式
就是啟動Activity的方式:
只要在Activity中指定launchMode屬性就可以完成啟動模式的改變。
在上面的案例中我們從MainActivity到SecondActivity有木有發現不按下結束鍵只是返回也能返回到MainActivity,我擦MainActivty那家伙還活著呢??讓我們探究下正常的啟動模式
正常的啟動模式
就是先啟動的Activity先入棧,出棧是最后出棧,所以當SecondActivity死后,可以看見MianActivity,在MainActivity中添加一個不斷重新啟動自己的button
然后進入Terminal:adb shell 然后dumpsys activity
查看當前運行的activity:
每一個都在棧中。
新建一個Activity2項目在其中只是設置一個按鈕,啟動Activity項目中的MianActivity:
發現Activity中的Mian在項目2的棧內,于是有一個結論:
正常模式啟動的Activity,誰啟動它,它就在那一個棧
跨應用啟動Activity代碼
Intent intent = new Intent(); intent.setClassName("win.haotinayi.activity","win.haotinayi.activity.MainActivity");
就是設置包名,在設置Activity的全名
SingleTop
就是當要啟動的Activity恰好在棧頂的時候,那么就不再重復創建:
無論怎么啟動都只有一個實例。
SingleTask
棧內單例模式,分為三種情況:
- 當有Activity需要的棧時,并且是棧頂,啥也不說了,直接復用
- 當有Activity需要的棧時,并且不是棧頂,那么在它上面的全部干掉,自己當大哥
- 當沒有Activity需要的棧時,創建棧
把MianActivity設置成SingleTask模式,首先打開Activity項目,讓兩個Activity同時存在:
并且MianActivity不是棧頂,然后在通過Activity2打開MainActivity:
SecondActivity被干掉了,大哥是MianActivity,那么什么是Activity的需要棧呢? 默認是包名
使用屬性taskAffinity可以改掉,現在來一個惡作劇:
這時再次啟動項目發現,項目的棧改變了:
SingleInstance
Activity只能單獨存在一個棧中,換句話說就是整個手機就你一個實例
使用Intent來標示啟動模式
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
####標志的分類
- FLAG_ACTIVITY_NEW_TASK
與”singleTask”模式相同,在新的 task 中啟動 activity。如果要啟動的 activity 已經運行于某 task 中,則那個 task 將調入前臺。
- FLAG_ACTIVITY_SINGLE_TOP
與 “singleTop”模式相同,如果要啟動的 activity位于back stack 頂,系統不會重新創建目標Activity實例,而是直接復用Task棧頂的Activity。
- FLAG_ACTIVITY_CLEAR_TOP
此種模式在launchMode中沒有對應的屬性值。如果要啟動的 activity 已經在當前 task 中運行,則不再啟動一個新的實例,且所有在其上面的 activity 將被銷毀。
Activity優先級
從高到低排序:
- 顯示且能獲得焦點(前臺)的Activity
- 顯示不能獲得焦點(非前臺),一個打開Dialog的Activity
- 不可見,已經處于暫停或者直接onStop后的Activity
當內存不足的時候低優先級的Activity就會被殺掉,如果一個組件沒有放在四大組件中,那么很快被殺死,所以后臺任務最好放到一個四大組件中,防止被干掉。
注意
Activity的全屏
// 去除標題欄
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature要在setContentView調用之前否則會崩潰
Activity的公開性
一般設置Activity為非公開的
<activity
......
android:exported="false" />
注意:非公開的Activity不能設置intent-filter,以免被其他activity喚醒(如果擁有相同的intent-filter)。
來自:http://haotianyi.win/2017/03/01/01-說說Activity那些事/