這篇文章主要介紹了Android下Activity間通信序列化過程中深淺拷貝的示例分析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
創(chuàng)新互聯(lián)建站長期為近千家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊從業(yè)經(jīng)驗10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為沂南企業(yè)提供專業(yè)的成都網(wǎng)站設(shè)計、成都做網(wǎng)站,沂南網(wǎng)站改版等技術(shù)服務(wù)。擁有十多年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。
前言
問題的背景是,視頻互動業(yè)務(wù)需要增加彈幕功能,但是播放器的視圖是偽橫屏的,即,他是一種類似于使用 rotate(90.0)的方式,旋轉(zhuǎn)橫屏的,在 Activity 層面上還是一個豎屏的狀態(tài)。那么彈幕輸入的時候的鍵盤,也是豎屏的。這會帶來比較嚴(yán)重的用戶體驗問題。
由于屏幕旋轉(zhuǎn)狀態(tài)在 android 下,是一個 Activity 層面上的事情,而且相當(dāng)?shù)牡讓樱瑹o從 hook,多方調(diào)研以后,決定采拉起一個橫屏的 Activity 作為鍵盤輸入的專用 Activity。
這里的代碼很快就可以寫好,如下所示:
/** * Created by DesGemini on 12/09/2017. */ public class DialogActivity extends Activity { private RelativeLayout mContentView; private View vSendBtn; private EditText etDanmakuInput; private InputMethodManager mInputMethodManager; public static WeakReferencedanmakuWriteCallback = new WeakReference<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mInputMethodManager = (InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE); mContentView = (RelativeLayout) getLayoutInflater() .inflate(R.layout.hiv_danmaku_input_dialog, null); vSendBtn = mContentView.findViewById(R.id.tv_danmaku_send_btn); etDanmakuInput = (EditText) mContentView.findViewById(R.id.et_danmaku_input); vSendBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // 這里需要處理 Activity 間回傳邏輯 } }); setContentView(mContentView); showSoftKeyboard(); } private boolean showSoftKeyboard() { if (this.etDanmakuInput == null) { return false; } else { etDanmakuInput.postDelayed(new Runnable() { public void run() { etDanmakuInput.requestFocus(); mInputMethodManager.showSoftInput(etDanmakuInput, 0); } }, 100L); return true; } } @Override protected void onPause() { super.onDestroy(); danmakuWriteCallback.getAndSet(null); } @Override public void finish() { super.finish(); } }
DTO 的代碼定義如下所示:
public class DanmakuDialogDTO implements Serializable { public WeakReferencecallback; public Map utExtraParams; }
那么現(xiàn)在問題來了,怎么把這個 Activity 獲取到的 String 帶回去?
最自然的想法是 onActivityResult,然而,播放器是一個 sdk,寫不了 Activity 里的代碼,也不可能通知許多業(yè)務(wù)方一一做改動。
那就只能拋開 android 原生的 Activity 間拉起結(jié)束中的通信機(jī)制了,思考其他可以通信的方法。很自然地,我們想到了 Callback 。結(jié)構(gòu)如下圖。但是 Callback 這樣的一個非基本數(shù)據(jù)類型的對象怎么在 Activity 間傳遞呢?
嘗試通過存入 Intent 的 Extras的方式,然而 putExtra 方法并不能 put 一個 object,只能 put 一個 serializable。那就讓這個 DTO(Data Transfer Object)implements serializable 接口吧。沒有問題。
然而無法啟動 Activity,會有一個 crash 拋出:
java.lang.NullPointerException: Expected to unbox a 'int' primitive type but was returned null
報錯堆棧如下:
$Proxy1.startActivity(Unknown Source) android.app.Instrumentation.execStartActivity(Instrumentation.java:1520) android.taobao.atlas.runtime.InstrumentationHook$2$1.execStartActivity(InstrumentationHook.java:299)
如果把這個 DTO 的成員變量改為 static 類型,則可以啟動 Activity。
背后的原因是因為,在常規(guī)的序列化過程中,淺拷貝其實是沒什么意義的。淺拷貝意味著復(fù)制一個引用的地址,是一個內(nèi)存地址,但是常規(guī)序列化,要么跨進(jìn)程,要么就是網(wǎng)絡(luò)傳輸,序列化為 JSON,在這些常規(guī)場景里內(nèi)存地址沒有意義。因此 Java 序列化沒有淺拷貝的選項,也往往是針對一個 POJO 或者 Bean 進(jìn)行序列化,而不會對一個一般的含有很多引用的類進(jìn)行序列化。
然而 Android 中的 Activity 與 Activity 間的傳遞對象又有所不同,理論上,都在同一個 Dalvik VM 中運行,相互的類引用都是可以訪問到的。但是由于 Android Intent 設(shè)計為序列化傳遞,序列化過程中沒有設(shè)計淺拷貝的機(jī)制,因此就無法淺拷貝地傳遞引用過去。
那么為什么設(shè)為 static 以后就可以傳遞,不會導(dǎo)致 crash 了呢?是因為靜態(tài)成員屬于類級別的,雖然不能序列化,但是因為我是在同一個機(jī)器(而且是同一個進(jìn)程),我的jvm已經(jīng)把這個類連帶著他的靜態(tài)變量一起加載進(jìn)來了,所以獲取到的是類層面上的靜態(tài)變量地址,故,功能正常。
那么就決定是使用public static WeakReference
了。但是事實上遇到了另一個問題:
在第一次 startActivity 的時候,觀察到 Android 做了一次 GC,然后該 WeakReference 就被釋放了,因此 Callback 的業(yè)務(wù)功能也不能正常執(zhí)行。引入 WeakReference,原本是為了避開 static cakllback 導(dǎo)致的可能的內(nèi)存泄漏,然而在這種主動 GC 的情況下,WeakReference 失效了。如果改用 SoftReference,和強(qiáng)引用并沒有什么區(qū)別,都不能避免內(nèi)存的泄漏。
最終,采用 AtomReference 來持有這個 static callback,在 Activity 退出的時機(jī)去將 AtomicReference 置空。之所以使用 AtomicReference,是因為考慮到視頻 sdk 有并發(fā)場景的可能性,避免一邊置 null 另一邊準(zhǔn)備使用的可能。
感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“Android下Activity間通信序列化過程中深淺拷貝的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,更多相關(guān)知識等著你來學(xué)習(xí)!