文章目錄
- Intent
- 顯式 Intent
- 定義兩個 xml 文件
- android:orientation
- match_parent 和 wrap_content
- Intent函數
- 定義兩個 Activity
- 隱式 Intent
- 更多隱式 Intent 的用法
- 用隱式 Intent 打開系統瀏覽器
- 自建 Activity 以響應打開網頁的 Intent
- 向下一個活動傳遞數據
- 返回數據給上一個活動
Intent
如何在切換 Actiity
時攜帶數據是一個重要問題。我們定義兩個 xml
文件,通過 Intent
實現在活動間跳轉。
什么是
xml
文件?
xml
即可擴展標記語言,是互聯網數據傳輸的重要工具,它可以跨越互聯網任何的平臺,在服務器之間穿梭結構化數據,不受編程語言和操作系統的限制,可以說它是一個擁有互聯網最高級別通行證的數據攜帶者。
xml
用于標記電子文件使其具有結構性的標記語言,可以用來標記數據、定義數據類型,是一種允許用戶對自己的標記語言進行定義的源語言。xml
是標準通用標記語言(SGML)的子集,非常適合 Web
傳輸。
Inten啟動組件的方法:
組件名稱 | 方法名稱 |
---|---|
Activity | startActvity() |
startActivity() | |
– | – |
Service | startService() |
bindService() | |
– | – |
Broadcasts | sendBroadcasts() |
sendOrderedBroadcasts() | |
sendStickyBroadcasts() |
顯式 Intent
定義兩個 xml 文件
定義一個 first_layout.xml
:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/button_1"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="點擊有驚喜~"></Button></LinearLayout>
定義一個 second_layout.xml
:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".SecondActivity"><Buttonandroid:layout_height="wrap_content"android:layout_width="match_parent"android:id="@+id/button_2"android:text="再點一次~"></Button></LinearLayout>
android:orientation
orientation
定義了頁面組件排列方式是垂直(vertical)還是水平(horizontal)。
match_parent 和 wrap_content
Android
中所有的控件都具有 layout_width
和 layout_height
這兩個屬性,可選值有3種:match_parent
、fill_parent
、wrap_content
。
其中 match_parent
和 fill_parent
的意義相同,但官方更推薦 match_parent
。
match_parent
表示讓當前控件的大小和父布局的大小一樣,也就是由父布局來決定當前控件的大小。wrap_content
表示讓當前的控件大小能夠剛好包含里面的內容,也就是由控件內容決定當前控件的大小。
Intent函數
Intent
函數接收兩個參數:
- 第一個參數
Context
為上下文,一般使用this
即可。 - 第二個參數為要啟動的目標
Activity
。
函數內部調用了 ComponentName
函數,該函數可以啟動其他應用的 Activity、Service:
- pkg: Activity、Service 所在應用的包名。
- cls: Activity、Service 的包名+類名。
定義兩個 Activity
MainActivity
:
package com.example.intent_test;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);this.setContentView(R.layout.first_layout);Button button1 = (Button)this.findViewById(R.id.button_1);button1.setOnClickListener((View view)->{// 顯式IntentIntent intent = new Intent(this, SecondActivity.class);this.startActivity(intent);});}
}
SecondActivity
:
package com.example.intent_test;import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;import androidx.appcompat.app.AppCompatActivity;public class SecondActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);this.setContentView(R.layout.second_layout);Button button2 = (Button)this.findViewById(R.id.button_2);button2.setOnClickListener((View view)->{// 顯式IntentIntent intent = new Intent(this, MainActivity.class);this.startActivity(intent);});}
}
定義兩個 Activity 之后,我嘗試運行時曾出現報錯,原因是修改 AndroidManifest.xml
文件時不小心刪了一段配置代碼……所以說還是能不碰 AndroidManifest.xml
就不碰它(對于新手而言),如果有同學也出現報錯,可以參考一下我的 AndroidManifest.xml
,檢查一下自己的是否有問題:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.intent_test"><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.Intenttest"><activity android:name=".SecondActivity"/><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>
運行結果:
運行 MainActivity
:
點擊之后跳轉:
點擊再點一次后回跳回圖一。
隱式 Intent
在 AndroidManifest.xml
中修改 .SecondActivity
的 activity
屬性:
action
標簽指定當前活動可以響應 com.example.activitytest.ACTION_START
這個活動,而 category
標簽包含一些附加信息,表明只有在 action
和 category
中的內容同時匹配上 Intent
的內容的時候,SecondActivity
才可以響應 Intent
。
在 first_layout.xml
中添加第二個按鈕,(因為 Android 布局界面和業務邏輯分離,因此本質上是在 MainActivity
的頁面布局上添加 button3
):
在 MainActivity
中為 button3
綁定 隱式Intent
:
即使不為 Intent
指定 category
標簽(未調用 addCategory()
),它也會在調用 startActivity()
方法時自動添加默認的 category
(即 android.intent.category.DEFAULT
)。
每個 Intent 中只能指定一個 action,但卻能指定多個 categoryo 。
運行結果:
更多隱式 Intent 的用法
用隱式 Intent 打開系統瀏覽器
指定 Intent.ACTION_VIEW
為 action
,這是一個 Android 統內置的動作,常量值為 android.intent.action.VIEW
,然后通過 Uri.parse
方法,解析網址成一個 Uri
對象,調用 setDate
將其傳遞進去。
setData
方法可以接受一個 Uri
對象,指定當前 Intent
正在操作的數據。通常數據都是以字符串的形式傳入到 Uri.parse
方法中解析產生。
自建 Activity 以響應打開網頁的 Intent
與之對應,我們可以在 <intent-filter>
標簽中再配置一個 <data>
標簽,用于更加精確地指定當前活動能夠響應什么類型的數據。下面是 <data>
標簽中可以配置的內容:
android:scheme
//用于指定數據的協議部分,如http
android:host
//用于指定數據的主機名部分,如www.baidu.com
android:port
//用于指定數據的端口部分,一般跟隨在主機名后
android:path
//用于指定主機名和端口之后的部分,如一段網址中跟在域名之后的內容
android:mimeType
//用于指定可以處理的數據類型,允許使用通配符的方式進行指定
新建 ThirdActivity
,無需添加多余代碼,默認樣式即可:
重點在于修改 AndroidManifest.xml
中 ThirdActivity
的配置:
Intent 只有一個 action 標簽,但可以有多個 category 標簽。
<action android:name="android.intent.action.VIEW" />
出現該 action
標簽必須配置下面的 category
標簽,否則會報錯:
<category android:name="android.intent.category.BROWSABLE" />
android:scheme
的值由被打開網頁的 Url
決定:
<data android:scheme="http" />
運行結果:
但實際上通過自定義的 Activity 打開是沒有任何內容的,因為我們沒有配置相應的 xml
布局也沒有豐富 ThirdActivity
的邏輯代碼:
向下一個活動傳遞數據
兩個 Activity 之間傳遞數據也是使用 Intent,通過 putExtra()
方法的重載,可以把我們想要傳遞的數據暫存在 Intent 中,啟動了另一個活動之后,只需要把這些數據再從 Intent 中取出就可以了。
Intent.putExtra(String name, @Nullable String value) :
向 Intent 中寫入數據。Intent.getxxxExtra:
向 Intent 中取得數據。
MainActivity
中有一個字符串,現在想把它傳遞到下一個活動當中:
然后在 SecondActivity
中取出數據:
- 首先通過
getIntent
方法獲取到用于啟動SecondActivity
的Intent
; - 然后調用
getStringExtra
方法,傳入相應的鍵值(即消息的名稱),就可以得到相應的數據了; Log.d
用于打印日志以便于尋找bug
;.show()
用于顯示Toast
信息。
Toast.makeText
是 Andriod 的消息模式:
context
:當前的上下文環境。可用getApplicationContext()
或this
;text
:要顯示的字符串。也可是R.string
中字符串ID
;duration
:顯示的時間長短。Toast
默認的有兩個LENGTH_LONG
和LENGTH_SHORT
,也可以使用毫秒如 2000ms。
運行結果:
返回數據給上一個活動
在 SecondActivity
中構建一個 Intent
用于傳遞數據,然后調用了 setResult
方法,這個方法專用于向上一個活動返回數據,它有兩個參數:
public final void setResult(int resultCode, Intent data) {synchronized (this) {mResultCode = resultCode;mResultData = data;}
}
resultCode
:用于向上一個活動返回處理結果,一般只用RESULT_OK
或者RESULT_CANCELED
這兩個值;data
:將帶有數據的Intent
傳遞回去。
通過 finish()
方法來銷毀活動,也可以使用回退鍵銷毀活動,但要重寫一下 onBackPressed
方法:
接下來實現對 MainActivity
的編寫:
Activity
中有 startActivityFroResult
方法,也是用于啟動活動的,且在活動銷毀時返回一個結果給上一個活動。該方法接受兩個參數:
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {startActivityForResult(intent, requestCode, null);
}
Intent:
啟動的 Activity;requestCode:
請求碼,用于在之后的回調中判斷數據來源。
startActivityForResult
方法在 SecondActivity
活動銷毀之后會回調 MainActivity
活動的 onActivityResult
方法,因此需要在 MainActivity
中重寫來得到返回的數據。onActivityResult
方法有三個參數:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
}
- 請求碼
requestCode
:就是startActivityForResult
中傳入的int
值; resultCode
:返回數據時傳入的處理結果;data
:攜帶著返回數據的Intent
。
運行結果: