四大组件---Activity
2019獨角獸企業重金招聘Python工程師標準>>>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Activity
1. 創建Activity
1.1定義Class 繼承Activity? 重寫onCreate(Bundle state)方法
2..1AndroidManifest.xml配置Activity?? android:name
2. Activity跳轉
//顯式Intent
Intent intent = new Intent(this,SecondActivity.class); startActivity(intent);Intent intent = new Intent(); intent.setClass(this,SecondActivity.class); startActivity(intent);//隱士Intent
String action = "intent.con.qu.custom"; Intent intent = new Intent(action ); startActivity(intent );3. Activity傳值
Activity之間通過Intent可以傳遞那些數據類型?
基本數據類型、對象(自定義)類型、集合類型()
3.1.基本數據類型
mIntent.putExtra(“info”,data); Bundle bundle = new Bundle(); bundle.putStringExtra(“info”,data); mIntent.putBundleExtra(“bundle”,bundle)3.2.對象類型
Android 中自定義的對象序列化的問題有兩個選擇Parcelable、Serializable.
序列化原因:
1.永久性保存對象,保存對象的字節序列到本地文件中;
2.通過序列化對象在網絡中傳遞對象;
3.通過序列化在進程間傳遞對象.?
選擇原則:
1.在使用內存的時候,Parcelable 類比Serializable性能高,所以推薦使用Parcelable類.
2.Serializable在序列化的時候會產生大量的臨時變量,從而引起頻繁的GC.
3.Parcelable不能使用在要將數據存儲在磁盤上的情況,因為Parcelable不能很好的保證數據的持續性在外界有變化的情況下.盡管Serializable效率低點,也不提倡用,但在這種情況下,還是建議你用Serializable .
傳遞Serializable對象
//發送方 Intent intent = new Intent(); intent.setClass(FirstActivity.this, SecondActivity.class); Bundle bundle = new Bundle(); bundle.putString("name",name); bundle.putSerializable(“person”,person); //person必須實現Serializable接口 intent.putExtras(bundle); //intent.putExtra("person", person); startActivity(intent); //接收方 Bundle bundle = getIntent().getExtras(); String name = bundle.getString("name"); Person person = (Person)bundle.getSerializableExtra("person");//獲取Person對象傳遞Parcelable對象
Parcelable接口是Android特定序列化接口,它比Serializable接口更有效,通常用于Binder和AIDL場景中.
Parcelable接口序列化的數據可以存儲在Parcel中,繼承Parcelable接口的類必須具有一個CREATOR的靜態變量.
public class Mp3Info implements Parcelable { private String id;private String mp3Name;private String mp3Size;private String lrcName;private String lrcSize;public Mp3Info() {super();}public Mp3Info(String id, String mp3Name, String mp3Size, String lrcName,String lrcSize) {super();this.id = id;this.mp3Name = mp3Name;this.mp3Size = mp3Size;this.lrcName = lrcName;this.lrcSize = lrcSize;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getMp3Name() {return mp3Name;}public void setMp3Name(String mp3Name) {this.mp3Name = mp3Name;}public String getMp3Size() {return mp3Size;}public void setMp3Size(String mp3Size) {this.mp3Size = mp3Size;} public String getLrcName() {return lrcName;}public void setLrcName(String lrcName) {this.lrcName = lrcName;}public String getLrcSize() {return lrcSize;}public void setLrcSize(String lrcSize) {this.lrcSize = lrcSize;}public static final Parcelable.Creator<Mp3Info> CREATOR = new Creator<Mp3Info>() {@Overridepublic Mp3Info createFromParcel(Parcel source) {Mp3Info mp3Info = new Mp3Info();mp3Info.id = source.readString();mp3Info.mp3Name = source.readString();mp3Info.mp3Size = source.readString();mp3Info.lrcName = source.readString();mp3Info.lrcSize = source.readString();return mp3Info;}@Overridepublic Mp3Info[] newArray(int size) {return new Mp3Info[size];}};@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeString(id);dest.writeString(mp3Name);dest.writeString(mp3Size);dest.writeString(lrcName);dest.writeString(lrcSize);}@Overridepublic String toString() {return "Mp3Info [id=" + id + ", lrcName=" + lrcName + ", lrcSize="+ lrcSize + ", mp3Name=" + mp3Name + ", mp3Size=" + mp3Size+ "]";} }3.3.集合類型
ArrayList<Mp3Info> mp3List = new ArrayList<Mp3Info>();4. Activity返回值
發送方:
startActivityForResult(intent,requestCode);onActivityResult(responseCode,requestCode,intent){}接收方:
public void goFirst(View v){String str = et.getText().toString();Intent intent = new Intent();intent.putExtra(“back”,str+””)setResult(responseCode,intent);finish(); }5. Activity生命周期
談一談Activity的生命周期?筆試? 面試? 3? 7? 分別
Activity的生命周期中啟動,停止必然會調用的方法是?
啟動? onResume
停止? onPause
了解Activity的生命周期的根本目的就是為了設計用戶體驗更加良好的應用。因為Activity就相當于MVC中的C層,是為了更好的向用戶展現數據,并與之交互。
了解Activity的生命周期和各回調方法的觸發時機,我們可以更好的在合適的地方向用戶展現數據(因為每個應用每個Activity的作用不同,所以具體每個回調方法的最佳實踐不好把握,但是只要遵循最基本的原則即可),保證數據的完整性和程序的良好運行。
除了我們自行啟動(start)或者結束(finish)一個Activity,我們并不能直接控制一個Activity 的生命狀態,我們只能通過實現Activity生命狀態的表現——即回調方法來達到管理Activity生命周期的變化。
5.1.Activity生命周期
一個Activity可以基本上存在三種狀態:
恢復
這項Activity是在屏幕前的,并有用戶取得其焦點。(此狀態,有時也簡稱為“運行”。)
暫停
另一個Activity在屏幕前,取得焦點,但原來的Activity仍然可見。也就是說,另一個Activity是這一個頂部可見,或者是部分透明的或不覆蓋整個屏幕。暫停的Activity完全是存在的( Activity 對象保留在內存中,它維護所有狀態和成員信息,并保持窗口管理器的聯系),但在極低的內存的情況下,可以被系統終止。
停止
Activity完全被另一個Activity遮住了(現在Activity是在“background”)。停止Activity也仍然存在( Activity 對象保留在內存中,它保持狀態和成員信息,但不和窗口管理器有關聯)。然而,它已不再是對用戶可見,其他地方需要內存時,它可以被系統終止。
如果一項Activity被暫停或停止,該系統可以從內存中刪除它,要求它結束(調用它的finish() 方法),或者干脆殺死它的進程。Activity再次打開時(在被結束或被殺死),它必須創造所有的一切。
實現生命周期回調函數
當Activity按照如上所述在不同狀態轉進,出的時,是通過各種回調方法進行通知的。所有的回調方法是鉤子,當的Activity狀態變化時您可以覆蓋他們來做適當的工作時。以下的Activity,包括基本生命周期的每一個方法:
public class ExampleActivity extends Activity {@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// The activity is being created.}@Overrideprotected void onStart() {super.onStart();// The activity is about to become visible.}@Overrideprotected void onResume() {super.onResume();// The activity has become visible (it is now "resumed").}@Overrideprotected void onPause() {super.onPause();// Another activity is taking focus (this activity is about to be "paused").}@Overrideprotected void onStop() {super.onStop();// The activity is no longer visible (it is now "stopped")}@Overrideprotected void onDestroy() {super.onDestroy();// The activity is about to be destroyed.} }注意:在做任何事情之前,實現這些生命周期方法,必須始終調用父類的實現,如上面的例子所示。
綜合來看,這些方法定義一個Activity的整個生命周期。通過實現這些方法,您可以監視Activity生命周期的三個嵌套循環:
Activity的整個存在周期發生在 OnCreate() 調用和 OnDestroy( 調用之間。Activity調用 OnCreate() 執行“全局”狀態設置(如定義布局),并調用 OnDestroy( 釋放所有剩余資源 。例如,如果Activity有一個線程在后臺運行,從網絡上下載數據,它可能會調用 OnCreate() 創建該線程 ,然后由 OnDestroy( 停止線程的 。
Activity的可見周期發生在 OnStart() 調用和 onStop() 調用之間。在這段時間內,用戶可以看到屏幕上的Activity,并與它進行交互。例如,一個新的Activity時啟動時,onStop()被調用,這時Activity不再可見。這兩種方法之間,你可以維持運行Activity所需要的資源,提供給用戶。例如,你可以在調用OnStart()
注冊 BroadcastReceiver 監測影響你用戶界面的變化,當用戶可以不再看到你內容時,在 onStop() 時注銷。在整個存在周期的Activity,Activity在可見和不可見的變化中,系統可能會多次調用OnStart() 和 OnStop () 。
Activity的前臺周期發生在 onResume() 調用和 onPause() 調用之間。在這段時間內,該Activity顯示在屏幕上,在所有其他Activity之前,具有用戶輸入焦點。一個Activity經常在前臺后臺之間轉換,例如,當設備進入睡眠狀態,或彈出一個對話框是 onPause()被稱調用。因為這種狀態轉換,在這兩種方法中的代碼應該是相當輕量級的,以避免緩慢的轉換,使用戶等待。
圖1說明了這些循環和Activity可能采取狀態之間轉換的路徑。矩形代表可以實現在Activity狀態轉化之間要執行操作的回調方法。
1.啟動onCreate()->onStart()->onResume() 2.按back鍵onPause()->onStop()->onDestroy() 再次啟動:onCreate()->onStart()->onResume() 3.按home鍵onPause()->onStop() 再次啟動時:onRestart()->onStart()->onResume() 4.切換到SecondActivity:FirstActivity.onPause()->FirstActivity.onStop() 再次啟動時: FirstActivity.onRestart()->FirstActivity.onStart()->FirstActivity.onResume() 5.切換SecondActivity (FirstActivity.finish()): FirstActivity.onPause()->FirstActivity.onStop()->FirstActivity.onDestroy() 再次啟動時: FirstActivity.onCreate ()->FirstActivity.onStart()->FirstActivity.onResume() 6.切換到SecondActivity (SecondActivity主題為Dialog): FirstActivity.onPause() 再次啟動時: FirstActivity.onRestart()->FirstActivity.onStart()->FirstActivity.onResume() 7.配置改變Activity生命周期 某些設備配置在運行時可以改變(如屏幕方向,鍵盤的可用性,和語言)。當這種變化發生時,Android重新運行Activity(系統調用的 onDestroy() ,然后立即調用的 onCreate()) 。這種行為旨在幫助您用您所提供的(如不同的屏幕方向和大小不同的布局)的替代資源進行應用程序自動重載,以適應新的配置。AndroidManifest.xml<activity android:name=”…” android:configChanges="keyboardHidden|orientation|screenSize"/>5.2.Activity回調方法的作用
回調方法的作用,就是通知我們Activity生命周期的改變,然后我們可以處理這種改變,以便程序不會崩潰或者數據丟失等等,也就是擁有更好的用戶體檢,那么這么多回調方法里到底應該怎么做呢?
1、onCreate
最重要是在里面調用setContentView,還可以在里面初始化各控件、設置監聽、并初始化一些全局的變量。
因為在Activity的一次生命周期中,onCreate方法只會執行一次。在Paused和Stopped狀態下恢復或重啟的下,這些控件、監聽和全局變量也不會丟失。即便是內存不足,被回收了,再次Recreate的話,又是一次新的生命周期的開始,又會執行onCreate方法。
還可以在onCreate執行數據操作,比如從Cursor中檢索數據等等,但是如果你每次進入這個Activity都可能需要更新數據,那么最好放在onStart里面。(這個需要根據實際情況來確定)
2、onDestory
確定某些資源是否沒有被釋放,做一些最終的清理工作,比如在這個Activity的onCreate中開啟的某個線程,那么就要在onDestory中確定它是否結束了,如果沒有,就結束它。
3、onStart和onRestart、onStop
Activity進入到Stopped狀態之后,它極有可能被系統所回收,在某些極端情況下,系統可能是直接殺死應用程序的進程,而不是調用onDestory方法,所以我們需要在onStop方法中盡可能的釋放那些用戶暫時不需要使用的資源,防止內存泄露。
盡管onPause在onStop之前執行,但是onPause只適合做一些輕量級的操作,更多的耗時耗資源的操作還是要放在onStop里面,比如說對數據保存,需要用到的數據庫操作。
因為從Stopped狀態重啟之后, onStart和onRestart方法都會被執行,所以我們要判斷哪些操作分別要放在哪個方法里面 。因為可能在onStop方法里面釋放了一些資源,那么我們必須要重啟他們,這個時候這些重啟的操作放在onStart方法里面就比較好(因為onCreate之后也需要開啟這些資源)。那些因為Stopped之后引發的需要單獨操作的代碼,就可以放在onRestart里面。
4、onResume和onPause
onPause和onResume中做的操作,其實意義上和onStart和inStop差不多,只不過是要更輕量級的,因為onPause不能阻塞轉變到下一個Activity。
比如:停止動畫、取消broadcast receivers。當然相應的需要在onResume中重啟或初始化等等。
有時候也需要在onPause判斷用戶是調用finish結束這個Activity,還是暫時離開,以便區分處理。這時候可以調用isFinishing()方法來判斷。如果是用戶finish這個Activity,那么返回為true,如果只是暫時離開或者被系統回收的話,就返回false。
6. Activity狀態保存
Android里面保存數據狀態有哪幾種方式?
onPause()????????????? 用來持久化數據狀態
onsavedInstanceState()?? 保存數據狀態
一般來說, 調用Activity的onPause()和onStop()方法后的activity實例仍然存在于內存中, activity的所有信息和狀態數據不會消失, 當activity重新回到前臺之后, 所有的改變都會得到保留.
但是當系統內存不足時, 調用onPause()和onStop()方法后的activity可能會被系統摧毀, 此時內存中就不會存有該activity的實例對象了. 如果之后這個activity重新回到前臺, 之前所作的改變就會消失. 為了避免此種情況的發生, 開發者可以覆寫onSaveInstanceState()方法. onSaveInstanceState()方法接受一個Bundle類型的參數, 開發者可以將狀態數據存儲到這個Bundle對象中, 這樣即使activity被系統摧毀, 當用戶重新啟動這個activity而調用它的onCreate()方法時, 上述的Bundle對象會作為實參傳遞給onCreate()方法, 開發者可以從Bundle對象中取出保存的數據, 然后利用這些數據將activity恢復到被摧毀之前的狀態.
public class MainActivity extends Activity {public static final int SECOND_ACTIVITY = 0;private String temp;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 從savedInstanceState中恢復數據, 如果沒有數據需要恢復savedInstanceState為nullif (savedInstanceState != null) {temp = savedInstanceState.getString("temp");System.out.println("onCreate: temp = " + temp);}}public void onResume() {super.onResume();temp = "xing";System.out.println("onResume: temp = " + temp);// 切換屏幕方向會導致activity的摧毀和重建 Ctrl+F12if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);System.out.println("屏幕切換");}}// 將數據保存到outState對象中, 該對象會在重建activity時傳遞給onCreate方法@Overrideprotected void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);outState.putString("temp", temp);} }需要注意的是, onSaveInstanceState()方法并不是一定會被調用的, 因為有些場景是不需要保存狀態數據的. 比如用戶按下BACK鍵退出activity時, 用戶顯然想要關閉這個activity, 此時是沒有必要保存數據以供下次恢復的, 也就是onSaveInstanceState()方法不會被調用. 如果調用onSaveInstanceState()方法, 調用將發生在onPause()或onStop()方法之前.
onSaveInstanceState()方法的默認實現
如果開發者沒有覆寫onSaveInstanceState()方法, 此方法的默認實現會自動保存activity中的某些狀態數據, 比如activity中各種UI控件的狀態. android應用框架中定義的幾乎所有UI控件都恰當的實現了onSaveInstanceState()方法, 因此當activity被摧毀和重建時, 這些UI控件會自動保存和恢復狀態數據. 比如EditText控件會自動保存和恢復輸入的數據, 而CheckBox控件會自動保存和恢復選中狀態. 開發者只需要為這些控件指定一個唯一的ID(通過設置android:id屬性即可), 剩余的事情就可以自動完成了. 如果沒有為控件指定ID, 則這個控件就不會進行自動的數據保存和恢復操作.
由上所述, 如果開發者需要覆寫onSaveInstanceState()方法, 一般會在第一行代碼中調用該方法的默認實現: super.onSaveInstanceState(outState).
是否需要覆寫onSaveInstanceState()方法
既然該方法的默認實現可以自動的保存UI控件的狀態數據, 那什么時候需要覆寫該方法呢?
如果需要保存額外的數據時, 就需要覆寫onSaveInstanceState()方法. 如需要保存類中成員變量的值(見上例).
onSaveInstanceState()方法適合保存什么數據
由于onSaveInstanceState()方法方法不一定會被調用, 因此不適合在該方法中保存持久化數據, 例如向數據庫中插入記錄等. 保存持久化數據的操作應該放在onPause()中. onSaveInstanceState()方法只適合保存瞬態數據, 比如UI控件的狀態, 成員變量的值等.
引發activity摧毀和重建的其他情形
除了系統處于內存不足的原因會摧毀activity之外, 某些系統設置的改變也會導致activity的摧毀和重建. 例如改變屏幕方向(見上例), 改變設備語言設定, 鍵盤彈出等.
onSaveInstanceState保存數據
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><VideoViewandroid:id="@+id/videoView"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout>public class MainActivity extends Activity {private static final String TAG = "MainActivity";private VideoView videoView;private static final String VIDEO_PATH = Environment.getExternalStorageDirectory()+ File.separator+ "videoyueyu.3gp";@Overridepublic void onCreate(Bundle savedInstanceState) {//savedInstanceState就是保存的Activity一些狀態super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Log.v(TAG, "onCreate");if (videoView == null) {videoView = (VideoView) this.findViewById(R.id.videoView);MediaController controller = new MediaController(this);videoView.setMediaController(controller);videoView.setVideoPath(VIDEO_PATH);videoView.requestFocus();}/*if (savedInstanceState != null&& savedInstanceState.getInt("currentPosition") != 0) {videoView.seekTo(savedInstanceState.getInt("currentPosition"));}*/videoView.start();}@Overrideprotected void onDestroy() {super.onDestroy();Log.v(TAG, "onDestroy");}@Overrideprotected void onPause() { //onPause()適合用于數據的持久化保存super.onPause();Log.v(TAG, "onPause");}@Overrideprotected void onRestart() {super.onRestart();Log.v(TAG, "onRestart");}@Overrideprotected void onResume() {super.onResume();Log.v(TAG, "onResume");}@Overrideprotected void onStart() {super.onStart();Log.v(TAG, "onStart");}@Overrideprotected void onStop() {super.onStop();Log.v(TAG, "onStop");}@Overrideprotected void onRestoreInstanceState(Bundle savedInstanceState) {super.onRestoreInstanceState(savedInstanceState);Log.v(TAG, "onRestoreInstanceState");if (savedInstanceState != null&& savedInstanceState.getInt("currentPosition") != 0) {videoView.seekTo(savedInstanceState.getInt("currentPosition"));}}@Overrideprotected void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);//onSaveInstanceState()只適合用于保存一些臨時性的狀態Log.v(TAG, "onSaveInstanceState");//橫豎屏切換時保存播放狀態outState.putInt("currentPosition", videoView.getCurrentPosition());} }onPause保存數據
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><EditTextandroid:id="@+id/editText"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"/><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="發送"/> </LinearLayout>public class MainActivity extends AppCompatActivity {public static final String PREFS_NAME = "MyPrefsFile";private SharedPreferences settings;private EditText editText;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);settings = getSharedPreferences(PREFS_NAME, 0);editText = (EditText)findViewById(R.id.editText);}@Overrideprotected void onPause() {super.onPause();String content = editText.getText().toString();SharedPreferences.Editor edit = settings.edit();edit.putString("content",content);edit.commit();}@Overrideprotected void onResume() {super.onResume();String content = settings.getString("content","");editText.setText(content);SharedPreferences.Editor edit = settings.edit();edit.clear();edit.commit();} }7. Activity棧(Task)
8. Activity加載模式
Activity launchMode是什么意思?
當啟動一個Activity的時候,如何實例化這個Activity
取值有四個:
Standard?? ?????默認,每次都創建新的實例
SingleTop? ??????Activity位于棧頂的時候不創建,其它位置同Standard
SingleTask? ?????Actiivty在Task中已經被創建了,以后打開不再創建
SingleInstance?? 系統中只有一個實例
應用中的每一個Activity都是進行不同的事物處理。以郵件客戶端為例,InboxActivity目的就是為了展示收件箱,這個Activity不建議創建成多個實例。而ComposeMailActivity則是用來撰寫郵件,可以實例化多個此Activity對象。合理地設計Activity對象是否使用已有的實例還是多次創建,會使得交互設計更加良好,也能避免很多問題。至于想要達到前面的目標,就需要使用今天的Activity啟動模式。
使用很簡單,只需要在manifest中對應的Activity元素加入android:launchMode屬性即可。如下述代碼
<activityandroid:name=".SingleTaskActivity"android:launchMode="singleTask"> </activity>介紹launchMode的四個取值
8.1. standard
這是launchMode的默認值,Activity不包含android:launchMode或者顯示設置為standard的Activity就會使用這種模式。
一旦設置成這個值,每當有一次Intent請求,就會創建一個新的Activity實例。舉個例子,如果有10個撰寫郵件的Intent,那么就會創建10個ComposeMailActivity的實例來處理這些Intent。結果很明顯,這種模式會創建某個Activity的多個實例。
8.2. singleTop
singleTop其實和standard幾乎一樣,使用singleTop的Activity也可以創建很多個實例。唯一不同的就是,如果調用的目標Activity已經位于調用者的Task的棧頂,則不創建新實例,而是使用當前的這個Activity實例,并調用這個實例的onNewIntent方法。
在singleTop這種模式下,我們需要處理應用這個模式的Activity的onCreate和onNewIntent兩個方法,確保邏輯正常。
關于singleTop一個典型的使用場景就是搜索功能。假設有一個搜索框,每次搜索查詢都會將我們引導至SearchActivity查看結果,為了更好的交互體驗,我們在結果頁頂部也放置這樣的搜索框。
假設一下,SearchActivity啟動模式為standard,那么每一個搜索都會創建一個新的SearchActivity實例,10次查詢就是10個Activity。當我們想要退回到非SearchActivity,我們需要按返回鍵10次,這顯然太不合理了。
但是如果我們使用singleTop的話,如果SearchActivity在棧頂,當有了新的查詢時,不再重新創建SearchAc實例,而是使用當前的SearchActivity來更新結果。當我們需要返回到非SearchActivity只需要按一次返回鍵即可。使用了singleTop顯然比之前要合理。
1.只有在調用者和目標Activity在同一Task中,并且目標Activity位于棧頂,才使用現有目標Activity實例,否則創建新的目標Activity實例。
2.如果是外部程序啟動singleTop的Activity,在Android 5.0之前新創建的Activity會位于調用者的Task中,5.0及以后會放入新的Task中。
8.3. singleTask
singleTask這個模式和前面提到的standard和singleTop截然不同。使用singleTask啟動模式的Activity在系統中只會存在一個實例。如果這個實例已經存在,intent就會通過onNewIntent傳遞到這個Activity。否則新的Activity實例被創建。
同一程序內
如果系統中不存在singleTask Activity的實例,那么就需要創建這個Activity的實例,并且將這個實例放入和調用者相同的Task中并位于棧頂。如果singleTask Activity實例已然存在,那么在Activity回退棧中,所有位于該Activity上面的Activity實例都將被銷毀掉(銷毀過程會調用Activity生命周期回調),這樣使得singleTask Activity實例位于棧頂。與此同時,Intent會通過onNewIntent傳遞到這個SingleTask Activity實例。
在Google關于singleTask的文檔有這樣一段描述
The system creates a new task and instantiates the activity at the root of the new task.
意思為 系統會創建一個新的Task,并創建Activity實例放入這個新的Task的底部。
實現文檔的描述,我們需要在設置launchMode為singleTask的同時,再加上taskAffinity屬性即可。
跨應用之間
在跨應用Intent傳遞時,如果系統中不存在singleTaskActivity的實例,那么講創建一個新的Task,然后創建SingleTask Activity的實例,將其放入新的Task中。
如果singleTask Activity所在的應用進程存在,但是singleTask Activity實例不存在,那么從別的應用啟動這個Activity,新的Activity實例會被創建,并放入到所屬進程所在的Task中,并位于棧頂位置。
該模式的使用場景多類似于郵件客戶端的收件箱或者社交應用的時間線Activity。上述兩種場景需要對應的Activity只保持一個實例即可,但是也要謹慎使用這種模式,因為它可以在用戶未感知的情況下銷毀掉其他Activity。
8.4. singleInstance
這個模式和singleTask差不多,因為他們在系統中都只有一份實例。唯一不同的就是存放singleInstance Activity實例的Task只能存放一個該模式的Activity實例。如果從singleInstance Activity實例啟動另一個Activity,那么這個Activity實例會放入其他的Task中。同理,如果singleInstance Activity被別的Activity啟動,它也會放入不同于調用者的Task中。
這種模式的使用情況比較罕見,在Launcher中可能使用。或者你確定你需要使Activity只有一個實例。建議謹慎使用。
9. Activity親和性
什么是Activity的親和性?
Activity的歸屬,當啟動一個Activity,它應該在哪個Task中,Activity與Task的吸附關系。
以下情況會影響Activity與Task的關系:
1. <activity android:taskAffinity=”…” android: allowTaskReparenting =”…”/>
2.啟動Activity,Intent.setFlags(Intent.FLAG_ACTIVIETY_NEW_TASK)
? <activity android:taskAffinity=”…”/>
Activity的歸屬,也就是Activity應該在哪個Task中,Activity與Task的吸附關系。我們知道,一般情況下在同一個應用中,啟動的Activity都在同一個Task中,它們在該Task中度過自己的生命周期,這些Activity是從一而終的好榜樣。
每個Activity都有taskAffinity屬性,這個屬性指出了它希望進入的Task。如果一個Activity沒有顯式的指明該Activity的taskAffinity,那么它的這個屬性就等于Application指明的taskAffinity,如果Application也沒有指明,那么該taskAffinity的值就等于包名。而Task也有自己的affinity屬性,它的值等于它的根Activity的taskAffinity的值。
一開始,創建的Activity都會在創建它的Task中,并且大部分都在這里度過了它的整個生命。然而有一些情況,創建的Activity會被分配其它的Task中去,有的甚至,本來在一個Task中,之后出現了轉移。我們首先分析一下android文檔給我們介紹的兩種情況。
第一種情況。如果該Activity的allowTaskReparenting設置為true,它進入后臺,當一個和它有相同affinity的Task進入前臺時,它會重新宿主,進入到該前臺的task中。
首先,我們啟動app1,加載Activity1,然后按Home鍵,使該task(假設為task1)進入后臺。然后啟動app2,默認加載Activity2。本來應該是顯示Activity2,但是我們卻看到了Activity1。實際上Activity2也被加載了,只是Activity1重新宿主,所以看到了Activity1。
第二種情況。如果加載某個Activity的intent,Flag被設置成FLAG_ACTIVITY_NEW_TASK時,它會首先檢查是否存在與自己taskAffinity相同的Task,如果存在,那么它會直接宿主到該Task中,如果不存在則重新創建Task。
<activity android:name=".SecondActivity"? android:taskAffinity="com.sina.cn"/>Intent intent = new Intent(FirstActivity.this,SecondActivity.class);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(intent);?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
轉載于:https://my.oschina.net/quguangle/blog/789985
總結
以上是生活随笔為你收集整理的四大组件---Activity的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用 Core Graphics 绘制基
- 下一篇: 从竞品数据搜集切入,NiucoData要