本篇文章包括
概述
數據傳遞
生命週期
啓動模式
Activity 進入和退出動畫
概述
Activity是Android提供給開發者的一個組件,主要用於前臺界面的展示和交互。在android中,使用頻率最高,Android應用程序通常由多個Activity組成,幾乎所有Activity都與用戶交互。
這裏有兩個幾乎所有Activity子類都會實現的方法:
onCreate(Bundle)
是你初始化Activity的地方。最重要的,這裏你經常會調用setContentView(int)並傳入一個佈局資源來定義你的UI,並且通過調用findViewById(int)得到UI中在編程時需要交互的組件。
onPause()
是處理用戶離開你Activity的地方。最重要的,所有用戶行爲導致產生的變化都應該在此節點提交(例如ContentProvider持有數據)。
爲了使用Context.startActivity(),所有Activity類型都必須在包的AndroidManifest.xml中存在對應的聲明。
Activity和AppcompatActivity
繼承AppCompatActivity的界面,界面會有一個默認的actionbar
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
如果繼承activity的話,該actionbar會消失。ActionBar向前兼容,出現在support v7裏,如果需要使用兼容版的actionbar,則繼承support v7提供的ActionBarActivity ,不過點進去ActionBarActivity從源碼看ActionBarActivity實際就是AppCompatActivity,就是帶有標題欄的Activity. 但是目前的v7包下並沒有ActionBarActivity,
所以現在最常用的還是AppcompaActivity,AppcompaActivity其實也是ActionBarActivity 修改而來。
AppcompaActivity相對於Activity的變化;
1 主界面帶有toolbar的標題欄;
2 theme主題只能用android:theme=”@style/AppTheme (appTheme主題或者其子類),而不能用android:style
否則會提示錯誤: Caused by: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
activity實現全屏(去掉標題欄和狀態欄)
1、需要在setContentView方法調用之前設置。
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
2、 定義一個主題,在styles.xml裏面並引用。
<resources>
<style name="Theme.NoTitle_FullScreen">
<item name="android:windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item>
</style>
</resources>
Intent 啓動Activity和傳遞數據
1.intent.putExtra(key,value):
//key一般是String,值爲 java八大基本數據類型及對應的數組,String及對應的數組,序列化 Serializable Parcelable的對象及對應的數組等
2.intent.putExtras(bundle);
3.intent.putExtra(key,bundle)
Main2Activity(目標文件):
1.intent.getXXXExtra(key)獲取值
2.bundle=intent.getExtras()
3.bundle=intent.getExtras(key)
//顯式跳轉
val intent= Intent(this,Main2Activity::class.java)
startActivity(intent)
//傳參
val intent1= Intent(this,Main2Activity::class.java)
intent1.putExtra("name","小明")
startActivity(intent)
//Main2Activity中
val name=intent.getStringExtra("name")
//bundle傳參
val bundle=Bundle()
bundle.putString("name","小明")
val intent2= Intent(this,Main2Activity::class.java)
intent2.putExtras(bundle)
startActivity(intent)
//Main2Activity中
val bundle1=intent.extras
val name1=bundle1.get("name")
startActivityForResult完成activity向第二個activity傳遞數據並且回傳數據。
1.使用startActivityForResult(intent,requestCode(大於等於0))方法激活目標Activity
2.在目標Activity 中調用setResult(resultCode,intent) 設置回傳到源Activity 的結果碼和意圖對象
3.在源Activity 中重寫onActivityResult(requestCode,resultCode,intent)方法得到目標Activity 回傳的數據
//發起者中寫:
val intent3= Intent(this,Main2Activity::class.java)
intent3.putExtra("name","小明")
startActivityForResult(intent3,100)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode==100&&resultCode==200){
val name3=data?.getStringExtra("name")
}
//Main2Activity中
// 收到數據
val name2=intent.getStringExtra("name")
//回傳數據
val intent4= Intent(this,Main2Activity::class.java)
intent4.putExtra("name","小紅")
setResult(200,intent4)
}
}
傳遞對象時候,需要對對象進行序列化Serializable Parcelable
class Student(id:Int,name:String,age:Int) :Serializable{
var id:Int=0
var name:String=""
var age:Int=0
}
val intent5= Intent(this,Main2Activity::class.java)
intent5.putExtra("student",Student(1,"小明",10))
startActivity(intent)
//Main2Activity中
val student= intent.getSerializableExtra("student")
隱式啓動常用於不同應用之間的跳轉(例如打開支付寶微信的支付頁面),也可用於H5與native之間的交互。隱式啓動就是action,category和data的匹配,篇幅有限,請參考添加鏈接安卓Activity隱式啓動全面解析
Intent在傳遞數據時是有大小限制的,這裏官方並未詳細說明,不過通過實驗的方法可以測出數據應該被限制在1MB之內(1024KB)
activity生命週期
Activity的整個生命週期發生在onCreate()和onDestroy()之間,activity在此期間存在。
Activity的可見生命週期發生在onStart()和onStop()之間,activity在此期間狀態可見。
Activity的前景生命週期發生在調用onResume()和調用之間onPause(),activity在此期間處於屏幕最上層,用戶可以與之交互。
1、要保存用戶輸入數據,需要在onPause()中執行,而不是在onStop()和onDestroy()中.因爲如果離開當前activity onPause()一定被調用。
2、onSaveInstanceState()
onCreate就是Android提供給開發者用來對Activity實例對象中的成員做初始化的,
某些設備配置可能會在運行時更改(例如屏幕方向,鍵盤可用性和語言)。發生此類更改時,Android會重新創建正在運行的活動(系統調用onDestroy(),然後立即調用
onCreate()).處理此類重新啓動的最佳方法是使用onSaveInstanceState()和onRestoreInstanceState()(或onCreate())來保存和恢復Activity活動狀態
//用來保存用戶狀態信息onSaveInstanceState() 在Activity受破壞之前,系統會自動調用。系統會傳遞一個Bundle對象,您可以使用諸如putString()和putInt()之類的方
法將關於Activity的狀態信息保存爲名稱 - 值的鍵值對.
然後,如果系統終止您的應用程序進程,系統將重新創建活動並將其Bundle傳遞給Activity的onCreate()和
onRestoreInstanceState()。使用這些方法之一,您可以從中提取已保存的狀態Bundle並恢復活動狀態。如果沒有要恢復的狀態信息,則Bundle傳遞給您的是null
3、當dialog彈出來的時候,如果是單純是創建的dialog,Activity並不會執行生命週期的方法,但是如果是跳轉到一個不是全屏的Activity的話,當然就是按照正常的生
命週期來執行了,即onPasue()->onStop()。
4、設備橫豎屏切換的時候。
不設置Activity的android:configChanges時,切屏會重新調用各個生命週期,切橫屏時會執行一次,切豎屏時會執行兩次;
設置Activity的
android:configChanges="orientation"時,切屏還是會重新調用各個生命週期,切橫、豎屏時只會執行一次;
設置Activity的android:configChanges="orientation|keyboardHidden"時,切屏不會重新調用各個生命週期,只會執行onConfigurationChanged方法;
tips:還有一點,非常重要,一個Android的變更細節!
當API >12時,需要加入screenSize屬性,否則屏幕切換時即使你設置了orientation系統也會重建Activity!
5、有時候activity界面如果有dialog經常會發生activity爲空,直接崩潰,這個時候可以加個判斷
if (!MainActivity.this.isDestroyed()) {
new AlertDialog.Builder(MainActivity.this).setMessage("Show Dialog").show();
}
Activity啓動模式:
Activity四種啓動模式的設定出於兩種目的:
複用機制,節省系統資源,這種情況主要發生在除Standard模式外的三種模式上,通過他們的名字前綴Single也可以看出,跟Java中的單例模式有類似的思想,避免太多的實例對象創建開銷。
根據用戶的交互行爲定義,因爲Activity最終的目的還是完成用戶在各種交互場景下的需求。
在android裏,有4種activity的啓動模式,分別爲:standard (默認) singleTop singleTask singleInstance
當應用運行起來後就會開啓一條線程,線程中會運行一個任務棧,當Activity實例創建後就會放入任務棧中。Activity啓動模式的設置在AndroidManifest.xml文件中,通過配置Activity的屬性android:launchMode=""設置。
1. Standared模式(默認)
我們平時直接創建的Activity都是這種模式的Activity,這種模式的Activity的特點是:只要你創建了Activity實例,一旦激活該Activity,則會向任務棧中加入新創建的實例,退出Activity則會在任務棧中銷燬該實例。
2. SingleTop 棧頂複用模式
棧頂模式,閱讀類app經常會使用。這種模式會考慮當前要激活的Activity實例在任務棧中是否正處於棧頂,如果處於棧頂則無需重新創建新的實例,會重用已存在的實例,否則會在任務棧中創建新的實例。standartd模式是activity的默認模式,大部分情況下,都應該使用這種模式,也就是在配置文件中什麼都不用做,當確實有特殊需求時,再考慮其他模式。
3. SingleTask 棧內複用模式
如果任務棧中存在該模式的Activity實例,則把棧中該實例以上的Activity實例全部移除,調用該實例的newInstance()方法重用該Activity,使該實例處於棧頂位置,否則就重新創建一個新的Activity實例。
4. SingleInstance模式
當該模式Activity實例在任務棧中創建後,只要該實例還在任務棧中,即只要激活的是該類型的Activity,都會通過調用實例的newInstance()方法重用該Activity,此時使用的都是同一個Activity實例,它都會處於任務棧的棧頂。此模式一般用於加載較慢的,比較耗性能且不需要每次都重新創建的Activity。
後臺堆棧
後臺堆棧指的是Activitys在後臺任務中的排列規則,按"後進先出"排列.
例如當前Activity啓動另一個Activity時,新Activity將被推到堆棧頂部並獲得焦點。之前的Activity仍在堆棧中,但已停止。當活動停止時,系統將保留其用戶界面的當前狀態。當用戶按下“ 返回” 按鈕時,當前Activity將從堆棧頂部彈出(活動被銷燬),之前的Activity將恢復(其UI的先前狀態將恢復)。堆棧中的活動永遠不會重新排列,只能在當前Activity啓動時從堆棧推送和彈出到堆棧中,並在用戶使用Back按鈕退出時彈出.因此,後臺堆棧作爲“後進先出”對象結構操作。
當此Activity的實例已經存在,並且此時的啓動模式爲SingleTask和SingleInstance,另外當這個實例位於棧頂且啓動模式爲SingleTop時也會觸發onNewInstent()。此方法會把activity帶到前臺。
activity進入退出動畫
淡入淡出爲例:
首先在res文件夾下建立anim文件夾,然後在裏面建立fade_in.xml和fade_out.xml兩個動畫資源
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fromAlpha="0.0"
android:interpolator="@android:anim/accelerate_interpolator"
android:toAlpha="1.0" />
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromAlpha="1.0"
android:interpolator="@android:anim/accelerate_interpolator"
android:toAlpha="0.0" />
然後在values文件夾下的styles.xml中的resources標籤內寫:
<style name="Anim_fade" parent="android:Theme.NoTitleBar">
<item name="android:windowAnimationStyle">@style/fade</item>
</style>
<style name="fade" parent="@android:style/Animation.Activity">
<item name="android:activityOpenEnterAnimation">@anim/fade_in</item>
<item name="android:activityOpenExitAnimation">@anim/fade_out</item>
<item name="android:activityCloseEnterAnimation">@anim/fade_in</item>
<item name="android:activityCloseExitAnimation">@anim/fade_out</item>
</style>
接下來在Mainfest中的activity中添加上android:theme="@style/Anim_fade"即可。
當然更簡單,更推薦的方法是在oncreate()裏面添加
class Main2Activity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
overridePendingTransition(R.anim.fade_in,R.anim.fade_out)
}
override fun finish() {
super.finish()
overridePendingTransition(R.anim.fade_in,R.anim.fade_out)
}
}
滑動動畫
slide_in_left:從左邊划進來:-100%p—>0
slide_in_right:從右邊划進來:100%p—>0
slide_out_left:從左邊劃出去:0—>-100%p
slide_out_right:從右邊劃出去:0—>100%p
R.anim.slide_in_left.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="2000"
android:fromXDelta="-100%p"
android:toXDelta="0"/>
</set>
R.anim.slide_in_right.xml
R.anim.slide_out_left
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="2000"
android:fromXDelta="0"
android:toXDelta="-100%p"/>
</set>
R.anim.slide_out_right
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="2000"
android:fromXDelta="0"
android:toXDelta="100%p"/>
</set>
R.anim.no_slide.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:duration="300"
android:fromAlpha="1"
android:toAlpha="1" />
</set>
然後在values文件夾下的styles.xml中的resources標籤內寫:
<style name="Anim_translate" parent="android:Theme.NoTitleBar">
<item name="android:windowAnimationStyle">@style/translate</item>
</style>
<style name="translate" parent="@android:style/Animation.Activity">
<item name="android:activityOpenEnterAnimation">@anim/slide_in_left</item>
<item name="android:activityOpenExitAnimation">@anim/slide_out_right</item>
<item name="android:activityCloseEnterAnimation">@anim/slide_in_right</item>
<item name="android:activityCloseExitAnimation">@anim/slide_out_left</item>
</style>
最後引用一下這個主題就好了
android:theme="@style/Anim_translate"