Intent及其七大屬性及intent-filter設置

Intent及其七大屬性

一、任務與回退棧:

(一)、任務Task:

①. 概念:

一個任務(task)就是在執行某項工作時與用戶進行交互的Activity的集合。這些Activity按照被打開的順序依次被安排在一個堆棧中(回退棧)。

②. 主屏頁面:

設備的主屏是大多數任務的啟動位置,當用戶觸摸一個應用程序啟動器圖標(或者app快捷圖標),應用程序的任務就會在前臺顯示。如果相關應用程序的任務不存在,那麼就會有一個新的任務被創建,並且應用程序打開的“主”Activity會作為任務中的根Activity。

(二)、回退棧:

①. 概念:

在當前的Activity啟動了另一個Activity時,這個新的Activity被放到了堆棧的頂部,並且帶有焦點。前一個Activity並沒有消失,而是保存在回退棧中,此時它處於停止狀態。

當用戶按下回退按鈕時,當前的Activity會被從回退棧的頂部彈出(這個Activity被銷燬)而前一個Activity被恢復。堆棧中的Activity不會被重新排列。因此,回退棧的操作跟後進先出的棧對象結構是一樣的。在用戶按下回退按鈕時,當前Activity被銷燬,並且前一個Activity被恢復。如果用戶繼續按回退按鈕,那麼回退棧中的每個Activity會被依次彈出,前一個Activity會被顯示,直到用戶返回主屏(或者返回到任務開始時運行的那個Activity)。當所有的Activity從回退棧中被刪除時,這個任務就不再存在了。

【注意:】後臺中可以同時擁有多個任務,但是如果用戶同時運行了很多後臺任務,系統為了回收內存可能銷燬一些後臺的Activity,從而導致Activity的狀態丟失。

因為回退堆棧中的Activity不曾被重新排列,因此如果允許用戶從多個Activity中啟動一個特殊的Activity,那麼就會創建一個新的Activity實例,並且在堆棧的頂部彈出(而不是把之前的Activity實例帶到堆棧的頂端)。這樣在你的應用程序中一個Activity就可能被實例化多次(甚至來自不同任務)。

(三)、Activity和Task的默認行為的總結:

①. 當Activity A啟動Activity B時,ActivityA被終止,但是系統保留了它的狀態(如滾動條的位置和錄入表單的文本)。如果用戶在Activity B中按回退按鈕,Activity A會使用被保存的狀態來進行恢復。

②. 當用戶通過按主頁(Home)按鈕離開一個任務時,當前的Activity會被終止,並且被放入後臺。系統會保留任務中每個Activity的狀態。如果用戶隨後通過選擇啟動圖標來恢復這個任務,那麼任務會來到前臺,並且恢復了堆棧頂部的Activity。

③. 如果用戶按下回退按鈕,當前的Activity會從堆棧中被彈出並且被銷燬。堆棧中的前一個Activity會被恢復。Activity被銷燬時,系統不會保留Activity的狀態。

④. Activity能夠被實例化多次,甚至來自其他任務。

五、Activity啟動模式:

在Android中每個界面都是一個Activity,切換界面操作其實是多個不同Activity之間的實例化操作。在Android中Activity的啟動模式決定了Activity的啟動運行方式。Android中Activity的啟動

模式分為四種:

(一)、Activity啟動模式設置:

(二)、Activity的四種啟動模式:

①. standard(備註:standard是系統默認的啟動模式。)

標準啟動模式,每次激活Activity時都會創建Activity,並放入任務棧中。每個窗體的

getTaskId()保持不變,但是this.hashCode()發生改變。

②. singleTop

如果在任務的棧頂正好存在該Activity的實例, 就重用該實例,而不會創建新的Activity對象,不過它會調用onNewIntent()方法。如果棧頂部不存在就會創建新的實例並放入棧頂(即使棧中已經存在該Activity實例,只要不在棧頂,都會創建實例)。會回調onNewIntent()方法。

③. singleTask

如果在棧中已經有該Activity的實例,就重用該實例(會調用實例的onNewIntent())。

重用時,會讓該實例回到棧頂,因此在它上面的實例將會被移除棧。如果棧中不存在該實例,將會創建新的實例放入棧中。

和singleTop在名字上即可看出區別,即singleTop每次只檢測當前棧頂的Activity是否是我們需要請求創建的,而singleTask則會檢測棧中全部的Activity對象,從上向下,如果檢測到是我們所請求的,則會消滅此Activity對象上面的對象,直接把檢測到的我們需要的Activity置為棧頂。

④. singleInstance

與singleTask模式的區別是,在singleInstance模式中,存放activity實例的(窗口對象)的

回退棧不能有其他任何窗口對象。因此如果該窗口不存在,則要新建任務來存放該singleI

nstance模式窗口。也就是說getTaskId()會發現任務id發生了變化。

此啟動模式和我們使用的瀏覽器工作原理類似,在多個程序中訪問瀏覽器時,如果當前瀏覽器沒有打開,則打開瀏覽器,否則會在當前打開的瀏覽器中訪問。此模式會節省大量的系統資源,因為他能保證要請求的Activity對象在當前的棧中只存在一個。總之,在開發Android項目時,巧妙設置Activity的啟動模式會節省系統開銷和提高程序運行效率。

Intent及其七大屬性及intent-filter設置

一、知識點回顧:Activity

(一)、如何實現Activity頁面跳轉?

示例代碼:

//第一種方式:

Intent intent = new Intent(MainActivity.this,NextActivity.class);

startActivity(intent);

//第二種方式:

Intent intent = new Intent();

intent.setClass(MainActivity.this, NextActivity.class);

startActivity(intent);

//其實還有很多種Intent實現頁面跳轉的寫法。

二、Intent對象介紹:

(一)、Intent基本介紹:

1、Intent 用於封裝程序的”調用意圖“。兩個Activity之間,可以把需要交換的數據封裝成Bundle對象,然後使用Intent攜帶Bundle對象,實現兩個Activity之間的數據交換;

2、Intent還是各種應用程序組件之間通信的重要媒介。不管想啟動一個Acitivity、Service還是BroadcastReceiver,Android均使用統一的Intent對象來封裝這種”啟動意圖“。很明顯使用Intent提供了一致的編程模型;

3、Intent還有一個好處,如果應用程序只是想啟動具有某種特徵的組件,並不想和某個具體的組件耦合,則可以通過在intent-filter中配置相應的屬性進行處理,與stucts2中的MVC框架思路類似。

4、Intent對象大致包括7大屬性:ComponentName、 Action 、 Category 、 Data 、Type、 Extra 、Flag。

(二)、Intent啟動不同組件的方法:

1、啟動Activity:

  • startActivity()

  • startActivtyForResult()

2、啟動Service:【後面詳細講】

  • ComponetName startService()

  • boolean bindService()

3、啟動BroadcastReceiver:【後面詳細講】

  • sendBroadcast()

  • sendOrderedBroadcast ()

  • sendStickyBroadcast()

  • sendStickyOrderedBroadcast()

三、Intent的七大屬性:【重要】

Intent對象大致包括7大屬性:ComponentName、 Action 、 Category 、 Data 、Type、 Extra 、Flag。

  • Action作為標識符,代表一個Intent,當一個Activity需要外部協助處理時,就會發出一個Intent,如果一個程序能完成相應功能,只要在intent-filter加上這個這個intent就可以了。

  • Data保存需要傳遞的數據格式,比如:tel://

  • Extras保存需要傳遞的額外數據。

  • Category表示Intent的種類,從android上啟動Activity有多種方式,比如 程序列表、桌面圖標、點擊Home激活的桌面等等,Category則用來標識這些Activity的圖標會出現在哪些啟動的上下文環境裡。

(一)、ComponentName屬性:

1、指定了ComponentName屬性的Intent已經明確了它將要啟動哪個組件,因此這種Intent被稱為顯式Intent,沒有指定ComponentName屬性的Intent被稱為隱式Intent。隱式Intent沒有明確要啟動哪個組件,應用會根據Intent指定的規則去啟動符合條件的組件。

2、示例代碼:

Intent intent = new Intent();

ComponentName cName = new ComponentName(MainActivity.this,NextActivity.class);

intent.setComponent(cName);

startActivity(intent);

//實際上,以上的寫法都被簡化為以下寫法:

Intent intent = new Intent(MainActivity.this,NextActivity.class);

startActivity(intent);

//也就是說,平時我們最常用的Intent頁面跳轉的寫法就調用的是顯式Intent。

(二)、Action、Category屬性與intent-filter配置:

通常,Action、Category屬性結合使用,定義這兩個屬性都是在配置文件的節點中。Intent通過定義Action屬性(其實就是一段自定義的字符串),這樣就可以把Intent與具體的某個Activity分離,實現瞭解耦。否則,每次跳轉,都要寫成類似new Intent(MainActivity.this,NextActivity.class)這樣的形式,也就是說必須將要跳轉的目標Activity的名字寫出來,這樣的編碼其實是“硬編碼”,並沒有實現松耦合。調用Intent對象的setAction()方法實現頁面跳轉雖然略微複雜(需要在AndroidManifest.xml文件中配置),但是實現瞭解耦。

1、示例代碼:

Intent intent = new Intent();

intent.setAction("com.steven.android06lifecycle.nextactivity");

startActivity(intent);

//在配置文件中註冊Activity的時候需要聲明:

//當某個頁面是默認啟動頁面時,需要定義Action、Category的屬性必須為以下字符串:【設置任務入口】

2、常用Action屬性常量:

Intent對象不僅可以啟動本應用內的程序組件,也可以啟動Android系統的其他應用的組件,包括系統內置的程序組件(需要設置權限)。

  • ACTION_MAIN:(android.intent.action.MAIN)Android程序入口。

  • 每個Android應用必須且只能包含一個此類型的Action聲明。【如果設置多個,則哪個在前,執行哪個。】

  • ACTION_VIEW: (android.intent.action.VIEW) 顯示指定數據。

  • ACTION_EDIT: (android.intent.action.EDIT) 編輯指定數據。

  • ACTION_DIAL: (android.intent.action.DIAL) 顯示撥號面板。

  • ACTION_CALL: (android.intent.action.CALL) 直接呼叫Data中所帶的號碼。

  • ACTION_ANSWER: (android.intent.action.ANSWER) 接聽來電。

  • ACTION_SEND: (android.intent.action.SEND) 向其他人發送數據(例如:彩信/email)。

  • ACTION_SENDTO: (android.intent.action.SENDTO) 向其他人發送短信。

  • ACTION_SEARCH: (android.intent.action.SEARCH) 執行搜索。

  • ACTION_GET_CONTENT: (android.intent.action.GET_CONTENT) 讓用戶選擇數據,並返回所選數據。

(三)、Category 屬性:

Category屬性為Action增加額外的附加類別信息。CATEGORY_LAUNCHER意味著在加載程序的時候Acticity出現在最上面,而CATEGORY_HOME表示頁面跳轉到HOME界面。

1、實現頁面跳轉到HOME界面的代碼:【記憶】

Intent intent = new Intent();

intent.setAction(Intent.ACTION_MAIN);

intent.addCategory(Intent.CATEGOTY_HOME);

startActivity(intent);

2、常用Category屬性常量:

  • CATEGORY_DEFAULT: (android.intent.category.DEFAULT) Android系統中默認的執行方式,按照普通Activity的執行方式執行。

  • CATEGORY_HOME: (android.intent.category.HOME) 設置該組件為Home Activity。

  • CATEGORY_PREFERENCE: (android.intent.category.PREFERENCE) 設置該組件為Preference。

  • CATEGORY_LAUNCHER: (android.intent.category.LAUNCHER) 設置該組件為在當前應用程序啟動器中優先級最高的Activity,通常與入口ACTION_MAIN配合使用。

  • CATEGORY_BROWSABLE: (android.intent.category.BROWSABLE) 設置該組件可以使用瀏覽器啟動。

(四)、Data屬性:

1、Data屬性通常用於向Action屬性提供操作的數據。Data屬性的值是個Uri對象。

Uri的格式如下:scheme://host:port/path

http://www.baidu.com:8080/a.jpg

2、系統內置的幾個Data屬性常量:

  • tel://:號碼數據格式,後跟電話號碼。

  • mailto://:郵件數據格式,後跟郵件收件人地址。

  • smsto://:短息數據格式,後跟短信接收號碼。

  • content://:內容數據格式,後跟需要讀取的內容。

  • file://:文件數據格式,後跟文件路徑。

  • market://search?q=pname:pkgname:市場數據格式,在Google Market裡搜索包名為pkgname的應用。

  • geo://latitude, longitude:經緯數據格式,在地圖上顯示經緯度所指定的位置。

3、Intent利用Action屬性和Data屬性啟動Android系統內置組件的代碼:【不需要記憶,用到的時候查找資料】

(1)、撥打電話:

Intent intent=new Intent();

intent.setAction(Intent.ACTION_CALL);

//intent.setAction("android.intent.action.CALL"); //以下各項皆如此,都有兩種寫法。

intent.setData(Uri.parse("tel:1320010001"));

startActivity(intent);

//調用撥號面板:

Intent intent=new Intent();

intent.setAction(Intent.ACTION_DIAL);

intent.setData(Uri.parse("tel:1320010001"));

startActivity(intent);

//調用撥號面板:

Intent intent=new Intent();

intent.setAction(Intent.ACTION_VIEW);

intent.setData(Uri.parse("tel:1320010001"));

startActivity(intent);

(2)、利用Uri打開瀏覽器、打開地圖等:

Uri uri = Uri.parse("http://www.google.com"); //瀏覽器

Uri uri=Uri.parse("geo:39.899533,116.036476"); //打開地圖定位

Intent intent = new Intent();

intent.setAction(Intent.ACTION_VIEW);

intent.setData(uri);

startActivity(intent);

(五)、Type屬性:

1、Type屬性用於指定Data所指定的Uri對應的MIME類型。MIME只要符合“abc/xyz”這樣的字符串格式即可。

2、 Intent利用Action、Data和Type屬性啟動Android系統內置組件的代碼:

(三)、播放視頻:

Intent intent = new Intent();

Uri uri = Uri.parse("file:///sdcard/media.mp4");

intent.setAction(Intent.ACTION_VIEW);

intent.setDataAndType(uri, "video/*");

startActivity(intent);

(六)、Extra屬性:

1、通過intent.putExtra(鍵, 值)的形式在多個Activity之間進行數據交換。

2、系統內置的幾個Extra常量:

  • EXTRA_BCC:存放郵件密送人地址的字符串數組。

  • EXTRA_CC:存放郵件抄送人地址的字符串數組。

  • EXTRA_EMAIL:存放郵件地址的字符串數組。

  • EXTRA_SUBJECT:存放郵件主題字符串。

  • EXTRA_TEXT:存放郵件內容。

  • EXTRA_KEY_EVENT:以KeyEvent對象方式存放觸發Intent的按鍵。

  • EXTRA_PHONE_NUMBER:存放調用ACTION_CALL時的電話號碼。

3、 Intent利用Action、Data和Type、Extra屬性啟動Android系統內置組件的代碼:

(1)、調用發送短信的程序

Intent intent = new Intent();

intent.setAction(Intent.ACTION_VIEW);

intent.setType("vnd.android-dir/mms-sms");

intent.putExtra("sms_body", "信息內容...");

startActivity(intent);

//發送短信息

Uri uri = Uri.parse("smsto:13200100001");

Intent intent = new Intent();

intent.setAction(Intent. ACTION_SENDTO );

intent.setData(uri);

intent.putExtra("sms_body", "信息內容...");

startActivity( intent );

//發送彩信,設備會提示選擇合適的程序發送

Uri uri = Uri.parse("content://media/external/images/media/23"); //設備中的資源(圖像或其他資源)

Intent intent = new Intent();

intent.setAction(Intent. ACTION_SEND );

intent.setType("image/png");

intent.putExtra("sms_body", "內容");

intent.putExtra(Intent.EXTRA_STREAM, uri);

startActivity(it);

(2)、發送Email:

Intent intent=new Intent();

intent.setAction(Intent. ACTION_SEND );

String[] tos={"[email protected]"};

String[] ccs={"[email protected]"};

intent.putExtra(Intent.EXTRA_EMAIL, tos);

intent.putExtra(Intent.EXTRA_CC, ccs);

intent.putExtra(Intent.EXTRA_TEXT, "The email body text");

intent.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");

intent.setType("message/rfc822");

startActivity(Intent.createChooser(intent, "Choose Email Client"));

4、 Intent利用Action屬性中的ACTION_GET_CONTENT獲取返回值:

//選擇圖片 requestCode 返回的標識

Intent intent = new Intent();

intent.setAction(Intent. ACTION_GET_CONTENT );

intent.setType( "image/*" );

Intent wrapperIntent = Intent.createChooser(intent, null);

startActivityForResult(wrapperIntent, requestCode);

//添加音頻

Intent intent = new Intent();

intent.setAction(Intent. ACTION_GET_CONTENT );

intent.setType( "video/*" );

Intent wrapperIntent = Intent.createChooser(intent, null);

startActivityForResult(wrapperIntent, requestCode);

//視頻

Intent intent = new Intent();

intent.setAction(Intent. ACTION_GET_CONTENT );

intent.setType( "video/*" );

Intent wrapperIntent = Intent.createChooser(intent, null);

startActivityForResult(wrapperIntent, requestCode);

//錄音

Intent intent = new Intent();

intent.setAction(Intent. ACTION_GET_CONTENT );

intent.setType( "audio/amr" );

intent.setClassName("com.android.soundrecorder","com.android.soundrecorder.SoundRecorder");

startActivityForResult(intent, requestCode);

(七)、Flags屬性:Intent可調用addFlags()方法來為Intent添加控制標記。

1、FLAG_ACTIVITY_CLEAR_TOP:(效果同Activity LaunchMode的singleTask)

如果在棧中已經有該Activity的實例,就重用該實例。重用時,會讓該實例回到棧頂,因此在它上面的實例將會被移除棧。如果棧中不存在該實例,將會創建新的實例放入棧中。

2、FLAG_ACTIVITY_SINGLE_TOP:(效果同Activity LaunchMode的singleTop)

如果在任務的棧頂正好存在該Activity的實例, 就重用該實例,而不會創建新的Activity對象。

3、FLAG_ACTIVITY_NEW_TASK:

【備註:】以下幾個為了解。

4、FLAG_ACTIVITY_MULTIPLE_TASK:

5、FLAG_ACTIVITY_BROUGHT_TO_FRONT:

6、FLAG_ACTIVITY_RESET_TASK_IF_NEEDED:

示例代碼:

Intent intent = new Intent(this, MainActivity.class); //將Activity棧中處於MainActivity主頁面之上的Activity都彈出。 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent);

【備註:】【重點,需要認真理解】

例如:

如果依次啟動了四個Activity:A、B、C、D。

在D Activity裡,跳到B Activity,同時希望D 和 C 都finish掉,可以在startActivity(intent)裡的intent裡添加flags標記,如下所示:

Intent intent = new Intent(this, B.class);

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

startActivity(intent);

這樣啟動B Activity的同時,就會把D、C都finished掉。

如果B Activity的launchMode是默認的“standard”,則B Activity會首先finished掉舊的B頁面,再啟動一個新的Activity B。 如果不想重新再創建一個新的B Activity,而是重用之前的B Activity,可以將B Activity的launchMode設置為“singleTask”。【特別需要注意的是:在部分手機中,如三星手機。即便是singleTask也會產生新的頁面,而不是重用之前的頁面。】

四、Activity的launchMode【知識點回顧】:

1、standard: (備註:standard是系統默認的啟動模式。)

標準啟動模式,每次激活Activity時都會創建Activity,並放入任務棧中。

如果啟動此Activity的Intent中沒有設置FLAG_ACTIVITY_NEW_TASK標誌, 則這個Activity與啟動他的Activity在同一個Task中,如果設置了Activity請參考上面FLAG_ACTIVITY_NEW_TASK的詳細說明,"launchMode"設置為"standard"的Activity可以被實例化多次, 可以在Task中的任何位置, 對於一個新的Intent請求就會實例化一次.

2、singleTop:

如果在任務的棧頂正好存在該Activity的實例, 就重用該實例,而不會創建新的Activity對象,不過它會調用onNewIntent()方法。如果棧頂部不存在就會創建新的實例並放入棧頂(即使棧中已經存在該Activity實例,只要不在棧頂,都會創建實例)。

如果啟動此Activity的Intent中沒有設置FLAG_ACTIVITY_NEW_TASK標誌, 則這個Activity與啟動他的Activity在同一個Task中,如果設置了Activity請參考上面FLAG_ACTIVITY_NEW_TASK的詳細說明,"launchMode"設置為"singleTop"的Activity可以被實例化多次, 可以在Task中的任何位置, 對於一個新的Intent請求如果在Task棧頂, 則會用棧頂的Activity響影Intent請求,而不會重新實例化對象接收請求, 如果沒有在棧頂, 則會實例化一個新的對象接收Intent請求.

3、singleTask:

如果在棧中已經有該Activity的實例,就重用該實例(會調用實例的onNewIntent())。重用時,會讓該實例回到棧頂,因此在它上面的實例將會被移除棧。如果棧中不存在該實例,將會創建新的實例放入棧中。

和singleTop在名字上即可看出區別,即singleTop每次只檢測當前棧頂的Activity是否是我們需要請求創建的,而singleTask則會檢測棧中全部的Activity對象,從上向下,如果檢測到是我們所請求的則會消滅此Activity對象上面的對象,直接把檢測到的我們需要的Activity置為棧頂。

"launchMode"設置為"singleTask"的Activity總是在棧底, 只能被實例化一次, 它允許其它Activity壓入"singleTask"的Activity所在的Task棧,如果有新的Intent請求有此標誌的Activity, 則系統會清除有此標誌的Task棧中的全部Activity,並把此Activity顯示出來.

4、singleInstance:

在一個新棧中創建該Activity實例,並讓多個應用共享該Activity實例。一旦這種模式的Activity實例存在於某個棧中,任何應用再激活這個Activity時都會重用該棧中的實例,其效果相當於多個應用程序共享一個應用,不管誰激活該Activity都會進入同一個應用中。此啟動模式和我們使用的瀏覽器工作原理類似,在多個程序中訪問瀏覽器時,如果當前瀏覽器沒有打開,則打開瀏覽器,否則會在當前打開的瀏覽器中訪問。此模式會節省大量的系統資源,因為他能保證要請求的Activity對象在當前的棧中只存在一個。

"launchMode"設置為"singleInstance"的Activity總是在棧底, 只能被實例化一次, 不允許其它的Activity壓入"singleInstance"的Activity所在Task棧, 即整個Task棧中只能有這麼一個Activity.


分享到:


相關文章: