使用Intent在Activity間傳遞資料(bundle)

不同Activity想傳遞簡單的資料,
可以使用Intent內的Bundle來儲存,
然後再利用Intent本身回傳。

通常只有這兩種情況,而這兩種情況也可能連續發生。
1.  A Activity傳值呼叫B ActivityB Activity取得A給予的值。
Ex:聯絡人App,列表畫面 中點擊某個聯絡人跳出 編輯畫面
編輯畫面需要預先填入該聯絡人的基本資料在每個欄位中。


class A_Activity : AppCompatActivity() {
companion object {
val LOG_TAG = A_Activity::class.java.simpleName
// 之後存放訊息的Bundle_Key,B_Activity也能用它從Bundle取值
const val KEY_MESSAGE = "我是A的Key"
// 當需要啟動的Activity,必須有個識別用的REQUEST_CODE
const val WANT_JOKE_REQUEST_CODE = 1
}
...
fun sendMessageToB(){
val intent = Intent(this, B_Activity.kt::class.java).apply {
putExtra(KEY_MESSAGE, "傳給B_Activity的字串訊息")
}
// 啟動B_Activity,並傳送一個REQUEST_CODE方便B_Activity識別。
startActivityForResult(intent, WANT_JOKE_REQUEST_CODE)
}
}
view raw A_Activity.kt hosted with ❤ by GitHub
class B_Activity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
...
// 先判斷傳來的intent是否有Key鍵為 A_Activity.KEY_MESSAGE
if (intent.hasExtra(A_Activity.KEY_MESSAGE)) {
// 推薦!簡短,避免多餘的空值判斷。
// 如果extras是空值回傳null,否則等同intent.extras.getString()!
val msgFromA = intent.getStringExtra(A_Activity.KEY_MESSAGE)
Log.d(LOG_TAG, msgFromA)
// 不推薦,如果A_Activity沒有putExtra,將會產生例外 java.lang.NullPointerException
// 如果對應的Key沒有KEY_MESSAGEㄉ回傳"預設值",否則回傳對應值。
// val msgFromA2 = intent.extras.getString(A_Activity.KEY_MESSAGE, "預設值")
// Log.d(LOG_TAG, msgFromA2)
}
...
}
}
view raw B_Activity.kt hosted with ❤ by GitHub

2. 當B Activity 處理完成A Activity給予的任務,要結束B本身並返回資料給A
Ex:當編輯成功時,編輯畫面關閉但同時將已更改聯絡人的id返回給列表畫面

class A_Activity : AppCompatActivity() {
companion object {
...
// 當需要啟動的Activity,必須有個識別用的REQUEST_CODE
const val WANT_JOKE_REQUEST_CODE = 1
}
// 因為之前使用startActvityForResult呼叫Activity,
// 所以會執行這個函數,必須覆寫它。
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
Log.d(LOG_TAG, "onActivityResult()呼叫")
super.onActivityResult(requestCode, resultCode, data)
// 第一步,是先判斷requestCode,因為你可以依據各種要求開啟別的Activity,
// 所以為了區別是什麼請求返回的的intent,只能用requestCode
when(requestCode) {
WANT_JOKE_REQUEST_CODE -> {
// 當resultCode是OK才執行。
if (resultCode == Activity.RESULT_OK) {
val msgFromSecond = data?.extras?.getString(KEY_MESSAGE, "沒東西")
Log.d(LOG_TAG, "msgFromSecond = $msgFromSecond")
} else {
Log.d(LOG_TAG, "Result不Ok")
}
}
}
}
}
view raw A_Activity.kt hosted with ❤ by GitHub
class B_Activity : AppCompatActivity() {
...
// 執行函數backToA(),將會將B_Activity終止並攜帶資料回到上一個Activity(此例為A_Activity)
fun backToA() {
// 建立一個新的intent
val intent = Intent().apply {
// 與第一種情況相同,都是putExtra自己想傳遞的資料。
// 要注意的是Key都是字串型態,Value則不一定是字串也可能是整數、布林值。
putExtra(MainActivity.KEY_MESSAGE, "我是從B_Activty的字串,哈哈哈!")
}
// 設定ResultCode為Result.OK 和 intent
setResult(Activity.RESULT_OK, intent)
// 結束B_Activity
finish()
}
}
view raw B_Activity.kt hosted with ❤ by GitHub

檢討
雖然putExtra和getExtra用起來很簡單,
但還是錯用,因此特別書寫一下!

有一點我犯的錯,紀錄一下。
當你使用intent時,不用另外指定給它新Bundle()。

不過底下這行還沒編譯就會直接報錯了。
intent.extras = Bundle()

延用舊intent塞值:
intent.putExtraString(KEY, 你要存的字串值)
或重新產生一個Intent再塞值:
Intent().apply{
   // put 你的資料在apply{ }中
}

最後putExtra能存的型態很多,
不只基本的Int、String、Float還有Array,
甚至連Serializable的物件都行。

留言

這個網誌中的熱門文章

Kotlin玩Android第03篇 Listview(01 ArrayAdapter)

golang本地測試如何繞過防火牆詢問允許