將 Intent 序列化,像 Uri 一樣傳遞 Intent!!!

承香墨影發表於2019-03-04

tips
tips

一、真的需要new一個Intent嗎?

在 Android 中,開啟一個 Activity ,有多少種方式?不過不管是使用什麼方式,最終都沒辦法逃避建立一個 Intent ,然後startActivity()

startActivity
startActivity

那麼,如果想根據資料來確定跳轉的頁面呢?

需要怎麼做比較好一點。DeepLink 好像是一個不錯的解決方案,在 AndroidManifest.xml 中,定義好 data 欄位,標記好 scheme 、 host 等等,然後按照規則進行傳遞,這樣也可以跳轉到某些頁面。

Deeplink
Deeplink

但是,這樣真的方便嗎?

我們需要在每個需要跳轉的 Activity 上,設定好data?當然,現在 Github 上也有一些成熟的 Deeplink 的解決方案,只需要在為某個 Activity 設定 data ,然後所有 deeplink 的連結都跳轉到這個 Activity 上,最後再由這個RouterActivity,去決定向那裡跳轉,並攜帶上引數。

那麼還有別的方案嗎?

二、Intent的toUri()

直到我發現 Intent 居然有個 toUri() 的方法,我就覺得有辦法對 Intent 進行簡單的序列化了。

method
method

從文件中可以看出,toUri() 方法可以將一個 Intent 轉換成一個 URI ,其中包含了 action、categories、flags 等一些必要的引數。

那麼文章開頭的地方,那麼 startActivity ,最終轉換成 URI ,是什麼呢?

uri_string
uri_string

仔細看,flag、compoent、putExtra 的資料,都被序列化成一個字串了。

得到的這個 Uri ,如何使用呢?可以藉助 Intent 的一個靜態方法,parseUri() 將一個 Intent 的 URI ,轉換成實際的 Intent 物件。

parseUri
parseUri

這樣的話,其實下面的方式,同樣也會調起TwoActivity,並且帶過去一個 balabala 的 ID 資料。

start_uri
start_uri

到這裡,基本上把本篇文章需要講解的內容都講明白了。但是有追求的程式設計師,我們還是要深挖一下,toUri() 到底幹了些什麼?

三、toUri()到底幹了什麼?

來看看 toUri() 的具體實現。

to_uri_shixian
to_uri_shixian

從原始碼的實現看,其實 toUri() 只是把每個欄位讀取出來,然後按照規則進行序列化,最後 parseUri() 只是按照這個規則進行了反序列化。熟練的話,基本上無需使用 toUri() 這個方法轉換,就可以盲寫 Intent 的 URI。

四、會有什麼隱患嗎?

我們使用的 API 都是官方對 Intent 提供的,用起來好像也確實沒有什麼問題。但是真的像看上去那麼美好嗎?

從傳遞引數的方向看,toUriInner() 方法是toUri() 方法中,對傳遞的資料進行序列化的方法。下面看看具體實現。

toUriInner
toUriInner

可以看到, toUriInner() 方法,它對基本的資料型別,都有對應的型別進行轉換,例如之前S.id=balabala 表示一個 key 為 id 的 String 型別的值 balabala 。

好像已經涵蓋了所有的型別傳參了,可是並不是這麼美好。發現沒有,沒有關於 Bundle 的引數傳遞,難道是看漏了嗎?

程式碼也不看了,做個試驗驗證一下。

start_bundler3
start_bundler3

看看 Log 輸出:

uri_string2
uri_string2

可以看到,toUri() 這個方法,確實對 Bundle 引數的序列化並沒有做特殊處理。

得到的結論,就是雖然 toUri()parseUri() 方法確實很好用,但是也是有缺陷的,Bundle 傳遞的資料沒法序列化成 Uri。

實際使用中,就需要我們對傳遞的引數有嚴格的要求,避免使用 Bundle 去傳遞資料,當然我們也可以自己去是實現序列化和反序列化 Bundle 的邏輯。

五、結語

這樣就可以簡單的對 Intent 進行傳遞,可以從後端伺服器拿到一個 IntentUri ,這樣就無需給每個點選設定好既定的開啟頁面了。當然,怎麼用還是要看實際的使用場景了。

今天在承香墨影公眾號的後臺,回覆『成長』。我會送你一些我整理的學習資料。

點贊或者分享吧~

相關文章