国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android下Activity間通信序列化過程中的深淺拷貝淺析

2019-10-22 18:25:30
字體:
來源:轉載
供稿:網友

前言

問題的背景是,視頻互動業務需要增加彈幕功能,但是播放器的視圖是偽橫屏的,即,他是一種類似于使用 rotate(90.0)的方式,旋轉橫屏的,在 Activity 層面上還是一個豎屏的狀態。那么彈幕輸入的時候的鍵盤,也是豎屏的。這會帶來比較嚴重的用戶體驗問題。

由于屏幕旋轉狀態在 android/166153.html">android 下,是一個 Activity 層面上的事情,而且相當的底層,無從 hook,多方調研以后,決定采拉起一個橫屏的 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 WeakReference<DanmakuWriteCallback> danmakuWriteCallback = 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 WeakReference<DWDanmakuWriteController.DanmakuWriteCallback> callback; public Map<String, String> utExtraParams;}

那么現在問題來了,怎么把這個 Activity 獲取到的 String 帶回去?

最自然的想法是 onActivityResult,然而,播放器是一個 sdk,寫不了 Activity 里的代碼,也不可能通知許多業務方一一做改動。

那就只能拋開 android 原生的 Activity 間拉起結束中的通信機制了,思考其他可以通信的方法。很自然地,我們想到了 Callback 。結構如下圖。但是 Callback 這樣的一個非基本數據類型的對象怎么在 Activity 間傳遞呢?

java,深淺拷貝,android,深拷貝,拷貝文件

嘗試通過存入 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。

背后的原因是因為,在常規的序列化過程中,淺拷貝其實是沒什么意義的。淺拷貝意味著復制一個引用的地址,是一個內存地址,但是常規序列化,要么跨進程,要么就是網絡傳輸,序列化為 JSON,在這些常規場景里內存地址沒有意義。因此 Java 序列化沒有淺拷貝的選項,也往往是針對一個 POJO 或者 Bean 進行序列化,而不會對一個一般的含有很多引用的類進行序列化。

然而 Android 中的 Activity 與 Activity 間的傳遞對象又有所不同,理論上,都在同一個 Dalvik VM 中運行,相互的類引用都是可以訪問到的。但是由于 Android Intent 設計為序列化傳遞,序列化過程中沒有設計淺拷貝的機制,因此就無法淺拷貝地傳遞引用過去。

那么為什么設為 static 以后就可以傳遞,不會導致 crash 了呢?是因為靜態成員屬于類級別的,雖然不能序列化,但是因為我是在同一個機器(而且是同一個進程),我的jvm已經把這個類連帶著他的靜態變量一起加載進來了,所以獲取到的是類層面上的靜態變量地址,故,功能正常。

那么就決定是使用public static WeakReference<DWDanmakuWriteController.DanmakuWriteCallback> callback;了。但是事實上遇到了另一個問題:

在第一次 startActivity 的時候,觀察到 Android 做了一次 GC,然后該 WeakReference 就被釋放了,因此 Callback 的業務功能也不能正常執行。引入 WeakReference,原本是為了避開 static cakllback 導致的可能的內存泄漏,然而在這種主動 GC 的情況下,WeakReference 失效了。如果改用 SoftReference,和強引用并沒有什么區別,都不能避免內存的泄漏。

最終,采用 AtomReference 來持有這個 static callback,在 Activity 退出的時機去將 AtomicReference 置空。之所以使用 AtomicReference,是因為考慮到視頻 sdk 有并發場景的可能性,避免一邊置 null 另一邊準備使用的可能。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。

 

注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 英吉沙县| 青冈县| 天台县| 兴国县| 鄱阳县| 萨迦县| 崇左市| 恩平市| 普格县| 太谷县| 清丰县| 石门县| 龙川县| 武安市| 读书| 治多县| 广汉市| 治县。| 宁陕县| 称多县| 伊金霍洛旗| 迁安市| 阿拉善右旗| 武山县| 凤台县| 河池市| 甘孜| 额尔古纳市| 遂川县| 綦江县| 岑巩县| 桂平市| 邓州市| 井冈山市| 瓦房店市| 宁明县| 永川市| 柞水县| 阿拉尔市| 建宁县| 虞城县|