編輯:關於Android編程
來自:https://developer.android.com/training/basics/intents/index.html
前言:我們都知道在APP中共享數據是非常重要的。比如我們經常會在微信中打開騰訊新聞APP進行新聞的查看,然後還可以選擇是留在騰訊新聞APP界面還是返回微信原界面,這就涉及到APP之間進行數據傳輸問題。還有一個強需求場景就是:在圖庫中選擇圖片進行發送,這時候就會彈出各種供選擇的APP,我一般選擇發送到電腦,然後就會啟動QQ中的發送到電腦的Activity界面,實現圖片的發送。所以,掌握怎樣在APP之間傳遞數據是非常重要的。
Android 應用一般具有若干個Activity。每個Activity顯示一個用戶界面,用戶可通過該界面執行特定任務(比如,查看地圖或拍照)。要將用戶從一個Activity轉至另一Activity,您的應用必須使用Intent
定義您的應用做某事的“意向”。當您使用諸如startActivity()
的方法將Intent
傳遞至系統時,系統會使用Intent
識別和啟動相應的應用組件。使用意向甚至可以讓您的應用開始另一個應用中包含的Activity。
Intent
可以為顯式以便啟動特定組件(特定的Activity
實例)或隱式以便啟動處理意向操作(比如“拍攝照片”)的任何組件。
向另一個應用發送用戶
Android 最重要的功能之一是應用能夠基於它要執行的“操作”向另一個應用發送用戶。 例如,如果您的應用有您要在地圖上顯示的公司地址,您無需在顯示地圖的應用中構建Activity。而是可以創建使用Intent
查看地址的請求。Android 系統之後啟動可以在地圖上顯示該地址的應用。
您必須使用意向在自己應用中的Activity之間進行導航。您通常使用明確意向執行此操作,該意向定義您希望啟動的組件的確切類名稱。 但是,當您希望另一應用執行操作時,比如“查看地圖”,您必須使用隱含意向。
隱含意向不聲明要啟動的組件的類名稱,而是聲明要執行的操作。 該操作指定您要執行的操作,比如查看、編輯、發送或獲取某項。 意向通常還包含與操作關聯的數據,比如您要查看的地址或您要發送的電子郵件消息。根據要創建的意向,數據可能是Uri
、多種其他數據類型之一,或意向可能根本就不需要數據。
如果您的數據是Uri
,有一個簡單的Intent()
構造函數,您可用來定義操作和數據。
例如,此處顯示如何使用指定電話號碼的Uri
數據創建發起電話呼叫的意向:
Uri number = Uri.parse("tel:5551234"); Intent callIntent = new Intent(Intent.ACTION_DIAL, number);
當您的應用通過調用startActivity()
調用此意向時,“電話”應用會發起向指定電話號碼的呼叫。
這裡有一些其他意向及其操作和Uri
數據對:
// Map point based on address Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California"); // Or map point based on latitude/longitude // Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z param is zoom level Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);查看網頁:
Uri webpage = Uri.parse("http://www.android.com"); Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);
其他類型的隱含意向需要提供不同數據類型(比如,字符串)的“額外”數據。 您可以使用各種putExtra()
方法添加一條或多條額外數據。
默認情況下,系統基於所包含的Uri
數據確定意向需要的相應 MIME 類型。如果您未在意向中包含Uri
,您通常應使用setType()
指定與意向關聯的數據的類型。設置 MIME 類型可進一步指定哪些類型的Activity應接收意向。
此處有更多添加額外數據以指定所需操作的意向:
Intent emailIntent = new Intent(Intent.ACTION_SEND); // The intent does not have a URI, so declare the "text/plain" MIME type emailIntent.setType(HTTP.PLAIN_TEXT_TYPE); emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"[email protected]"}); // recipients emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject"); emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text"); emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment")); // You can also attach multiple items by passing an ArrayList of Uris
Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI); Calendar beginTime = Calendar.getInstance().set(2012, 0, 19, 7, 30); Calendar endTime = Calendar.getInstance().set(2012, 0, 19, 10, 30); calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis()); calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis()); calendarIntent.putExtra(Events.TITLE, "Ninja class"); calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo");
注意:只有 API 級別 14 或更高級別支持此日歷事件意向。
注意:盡可能具體地定義您的Intent
非常重要。例如,如果您想要使用ACTION_VIEW
意向顯示圖像,您應指定image/*
的 MIME 類型。 這可防止可“查看”數據的其他類型的應用(比如地圖應用)被意向觸發。
盡管 Android 平台保證某些意向可以分解為內置應用之一(比如,“電話”、“電子郵件”或“日歷”應用),您應在調用意向之前始終包含確認步驟。
注意:如果您調用了意向,但設備上沒有可用於處理意向的應用,您的應用將崩潰。
要確認是否存在可響應意向的可用Activity,請調用queryIntentActivities()
來獲取能夠處理您的Intent
的Activity列表。如果返回的List
不為空,您可以安全地使用該意向。例如:
PackageManager packageManager = getPackageManager(); List activities = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); boolean isIntentSafe = activities.size() > 0;
如果isIntentSafe
是true
,則至少有一個應用將響應該意向。 如果它是false
,則沒有任何應用處理該意向。
一旦您已創建您的Intent
並設置附加信息,調用startActivity()
將其發送給系統 。如果系統識別可處理意向的多個Activity,它會為用戶顯示對話框供其選擇要使用的應用,如圖 1 所示。如果只有一個Activity處理意向,系統會立即開始這個Activity。
startActivity(intent);
此處顯示完整的示例:如何創建查看地圖的意向,確認是否存在處理意向的應用,然後啟動它:
// Build the intent Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California"); Intent mapIntent = new Intent(Intent.ACTION_VIEW, location); // Verify it resolves PackageManager packageManager = getPackageManager(); Listactivities = packageManager.queryIntentActivities(mapIntent, 0); boolean isIntentSafe = activities.size() > 0; // Start an activity if it's safe if (isIntentSafe) { startActivity(mapIntent); }
注意,當您通過將您的Intent
傳遞至startActivity()
而開始Activity時,有多個應用響應意向,用戶可以選擇默認使用哪個應用(通過選中對話框底部的復選框;見圖 1)。當執行用戶通常希望每次使用相同應用進行的操作時,比如當打開網頁(用戶可能只使用一個網頁浏覽器)或拍照(用戶可能習慣使用一個照相機)時,這非常有用。
但是,如果要執行的操作可由多個應用處理並且用戶可能習慣於每次選擇不同的應用,—比如“共享”操作,用戶有多個應用分享項目—,您應明確顯示選擇器對話框,如圖 2 所示。選擇器對話框強制用戶選擇用於每次操作的應用(用戶不能對此操作選擇默認的應用)。
Intent intent = new Intent(Intent.ACTION_SEND); ... // Always use string resources for UI text. // This says something like "Share this photo with" String title = getResources().getString(R.string.chooser_title); // Create intent to show chooser Intent chooser = Intent.createChooser(intent, title); // Verify the intent will resolve to at least one activity if (intent.resolveActivity(getPackageManager()) != null) { startActivity(chooser); }
這將顯示一個對話框,其中有響應傳遞給createChooser()
方法的意向的應用列表,並且將提供的文本用作對話框標題。
獲取Activity的結果
開始並不一定是單向的另一個Activity。您還可以開始另一個Activity並 接收返回的結果。要接收結果,請調用startActivityForResult()
(而不是startActivity()
)。
例如,您的應用可啟動照相機應用並接收拍攝的照片作為結果。或者,您可以啟動“聯系人”應用以便用戶選擇聯系人,並且您將接收聯系人詳細信息作為結果。
當然,響應的Activity必須設計為返回結果。當它這樣做時,它會作為另一Intent
對象發送結果。您的Activity在onActivityResult()
回調中接收它。
注意:當您調用startActivityForResult()
時,您可以使用明確或隱含意向。當開始您自己的Activity以接收結果時,您應使用明確意向確保您可收到預期結果。
開始針對結果的Activity時,您所使用的Intent
對象並沒有什麼特別之處,但您需要向startActivityForResult()
方法傳遞額外的整數參數。
該整數參數是識別您的請求的“請求代碼”。當您收到結果Intent
時,回調提供相同的請求代碼,以便您的應用可以正確識別結果並確定如何處理它。
例如,此處顯示如何開始允許用戶選擇聯系人的Activity:
static final int PICK_CONTACT_REQUEST = 1; // The request code ... private void pickContact() { Intent pickContactIntent = new Intent(Intent.ACTION_PICK, Uri.parse("content://contacts")); pickContactIntent.setType(Phone.CONTENT_TYPE); // Show user only contacts w/ phone numbers startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST); }
當用戶完成後續Activity並且返回時,系統會調用您的ActivityonActivityResult()
的方法。此方法包括三個參數:
startActivityForResult()
傳遞的請求代碼。RESULT_OK
;如果用戶退出或操作出於某種原因失敗,則是RESULT_CANCELED
。Intent
。
本例說明您可以如何處理“選擇聯系人”意向的結果。
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // Check which request we're responding to if (requestCode == PICK_CONTACT_REQUEST) { // Make sure the request was successful if (resultCode == RESULT_OK) { // The user picked a contact. // The Intent's data Uri identifies which contact was selected. // Do something with the contact here (bigger example below) } } }
在本例中,Android的“聯系人”應用返回的結果Intent
提供識別用戶所選聯系人的內容Uri
。
為了成功處理結果,您必須了解結果的Intent
的格式。當返回結果的Activity是您自己的Activity之一時,這便非常容易。 Andriod平台附帶的應用提供它們自己的API,您可用這些API獲取特定結果數據。 例如,“聯系人” 應用(在一些較舊的版本中是 Contacts 應用)始終返回帶內容 URI(識別所選聯系人)的結果,並且“照相機” 應用在"data"
額外項中返回Bitmap
(請參閱有關拍攝照片的課程)。
顯示如何從“聯系人”應用獲取結果的代碼不會詳細說明如何實際從結果讀取數據,但它需要對內容提供商進行更深入的探討。但是,如果您很好奇,此處提供了更多的代碼向您展示如何查詢結果數據,從所選聯系人獲取電話號碼:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // Check which request it is that we're responding to if (requestCode == PICK_CONTACT_REQUEST) { // Make sure the request was successful if (resultCode == RESULT_OK) { // Get the URI that points to the selected contact Uri contactUri = data.getData(); // We only need the NUMBER column, because there will be only one row in the result String[] projection = {Phone.NUMBER}; // Perform the query on the contact to get the NUMBER column // We don't need a selection or sort order (there's only one result for the given URI) // CAUTION: The query() method should be called from a separate thread to avoid blocking // your app's UI thread. (For simplicity of the sample, this code doesn't do that.) // Consider using CursorLoader to perform the query. Cursor cursor = getContentResolver() .query(contactUri, projection, null, null, null); cursor.moveToFirst(); // Retrieve the phone number from the NUMBER column int column = cursor.getColumnIndex(Phone.NUMBER); String number = cursor.getString(column); // Do something with the phone number... } } }
注意:在 Android 2.3(API 級別 9)之前,在
Contacts Provider
上執行查詢(如以上所示)需要您的應用聲明READ_CONTACTS
權限(請參閱安全與權限)。 但是,自 Android 2.3 版本開始,“聯系人”應用授予您的應用在聯系人提供商向您返回結果時從聯系人提供商臨時讀取信息的權限。該臨時權限僅適用於所請求的特定聯系人,因此您只能查詢意向的Uri
指定的聯系人,除非您聲明READ_CONTACTS
權限。
允許其他應用開始您的Activity
前兩課重點講述一方面:從您的應用開始另一個應用的Activity。但如果您的應用可以執行對另一個應用可能有用的操作,您的應用應准備好響應來自其他應用的操作請求。例如,如果您構建一款可與用戶的好友分享消息或照片的社交應用,您最關注的是支持ACTION_SEND
意向以便用戶可以從另一應用發起“共享”操作並且啟動您的應用執行該操作。
要允許其他應用開始您的Activity,您需要
在相應元素的宣示說明文件中添加一個元素。
當您的應用安裝在設備上時,系統會識別您的意向過濾器並添加信息至所有已安裝應用支持的意向內部目錄。當應用通過隱含意向調用startActivity()
或startActivityForResult()
時,系統會找到可以響應該意向的Activity。
為了正確定義您的Activity可處理的意向,您添加的每個意向過濾器在操作類型和Activity接受的數據方面應盡可能具體。
如果Activity具有滿足以下Intent
對象條件的意向過濾器,系統可能向Activity發送給定的Intent
:
ACTION_SEND
或ACTION_VIEW
。
使用元素在您的意向過濾器中指定此值。您在此元素中指定的值必須是操作的完整字符串名稱,而不是API常數(請參閱以下示例)。
用元素在您的意向過濾器中指定此內容。使用此元素中的一個或多個屬性,您可以只指定MIME類型、URI前綴、URI架構或這些的組合以及其他指示所接受數據類型的項。
注意:如果您無需聲明關於數據的具體信息Uri
(比如,您的Activity處理其他類型的“額外”數據而不是 URI 的時間),您應只指定android:mimeType
屬性聲明您的Activity處理的數據類型,比如text/plain
或image/jpeg
。
CATEGORY_DEFAULT
進行定義。
用
元素在您的意向過濾器中指定此內容。
在您的意向過濾器中,您可以通過聲明嵌套在
元素中的具有相應 XML 元素的各項,來聲明您的Activity接受的條件。
例如,此處有一個在數據類型為文本或圖像時處理ACTION_SEND
意向的意向過濾器:
每個入站意向僅指定一項操作和一個數據類型,但可以在每個
中聲明、
和元素的多個實例。
如果任何兩對操作和數據的行為相斥,您應創建單獨的意向過濾器指定與哪種數據類型配對時哪些操作可接受。
比如,假定您的Activity同時處理ACTION_SEND
和ACTION_SENDTO
意向的文本和圖像。在這種情況下,您必須為兩個操作定義兩種不同的意向過濾器,因為ACTION_SENDTO
意向必須使用數據Uri
指定使用send
或sendto
URI架構的收件人地址。 例如:
注意:為了接收隱含意向,您必須在意向過濾器中包含CATEGORY_DEFAULT
類別。方法startActivity()
和startActivityForResult()
就像聲明CATEGORY_DEFAULT
類別那樣處理所有意向。如果您不在意向過濾器中聲明它,則沒有隱含意向分解為您的Activity。
如需了解有關發送和接收ACTION_SEND
執行社交共享行為的意向的詳細信息,請參閱有關從其他應用接收簡單數據的課程。
為了決定在您的Activity執行哪種操作,您可讀取用於開始Activity的Intent
。
當您的Activity開始時,調用getIntent()
檢索開始Activity的Intent
。您可以在Activity生命周期的任何時間執行此操作,但您通常應在早期回調時(比如,onCreate()
或onStart()
)執行。
例如:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Get the intent that started this activity Intent intent = getIntent(); //在啟動Activity的時候獲得Intent,進而獲得數據然後顯示出來 Uri data = intent.getData(); // Figure out what to do based on the intent type if (intent.getType().indexOf("image/") != -1) { // Handle intents with image data ... } else if (intent.getType().equals("text/plain")) { // Handle intents with text ... } }
setResult()
指定結果代碼和結果Intent
。當您的操作完成且用戶應返回原始Activity時,調用finish()
關閉(和銷毀)您的Activity。 例如:
// Create intent to deliver some kind of result data Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri"); setResult(Activity.RESULT_OK, result); finish();
您必須始終為結果指定結果代碼。通常,它為RESULT_OK
或RESULT_CANCELED
。您之後可以根據需要為Intent
提供額外的數據。
注意:結果默認設置為RESULT_CANCELED
。因此,如果用戶在完成操作動作或設置結果之前按了返回按鈕,原始Activity會收到“已取消”的結果。
Intent
,您可以調用setResult()
並且僅傳遞結果代碼。 例如:
setResult(RESULT_COLOR_RED); finish();
在這種情況下,只有幾個可能的結果,因此結果代碼是一個本地定義的整數(大於 0)。 當您向自己應用中的Activity返回結果時,這將非常有效,因為接收結果的Activity可引用公共常數來確定結果代碼的值。
注意:無需檢查您的Activity是使用startActivity()
還是startActivityForResult()
開始的。如果開始您的Activity的意向可能需要結果,只需調用setResult()
。如果原始Activity已調用startActivityForResult()
,則系統將向其傳遞您提供給setResult()
的結果;否則,會忽略結果。
下面是HTC官方的一個圖片,展示了Android系統從發布最終到用戶手中的一個完整的過程: Awesome Infographic: HTC Shows Us “Th
由於不是系統級的應用, 也沒有獲得ROOT權限, 所以自己實現任務管理器其實意義並不是很大, 就像沒有root的手機安裝了LBE這類的手機助手, 雖然也帶一鍵清理內存清理
一丶PagerSlidingTabStrp運用扣丁音樂1.0前部分(gif圖大小限制)演示:視頻教程中是直接將PagerSlidingTabStrp例子的主頁面拿來做主頁
這篇來介紹一下適配器模式(Adapter Pattern),適配器模式在開發中使用的頻率也是很高的,像 ListView 和 RecyclerView 的 Adapter