最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時間:2017年10月18日 10:31:28   作者:DesGemini  
這篇文章主要給大家介紹了關于Android下Activity間通信序列化過程中深淺拷貝的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。

前言

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

由于屏幕旋轉狀態(tài)在 android 下,是一個 Activity 層面上的事情,而且相當?shù)牡讓?,無從 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;
}

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

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

那就只能拋開 android 原生的 Activity 間拉起結束中的通信機制了,思考其他可以通信的方法。很自然地,我們想到了 Callback 。結構如下圖。但是 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ī)的序列化過程中,淺拷貝其實是沒什么意義的。淺拷貝意味著復制一個引用的地址,是一個內存地址,但是常規(guī)序列化,要么跨進程,要么就是網(wǎng)絡傳輸,序列化為 JSON,在這些常規(guī)場景里內存地址沒有意義。因此 Java 序列化沒有淺拷貝的選項,也往往是針對一個 POJO 或者 Bean 進行序列化,而不會對一個一般的含有很多引用的類進行序列化。

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

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

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

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

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

總結

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

相關文章

最新評論

抚远县| 聂荣县| 松原市| 贵德县| 锦州市| 临西县| 深圳市| 绥滨县| 舟山市| 碌曲县| 绵阳市| 万载县| 溧阳市| 金坛市| 荥经县| 隆林| 阳泉市| 沧州市| 宾川县| 青河县| 平乐县| 铜陵市| 平阳县| 偃师市| 南开区| 内黄县| 全南县| 阳谷县| 汕头市| 中卫市| 宁波市| 常宁市| 巩留县| 巴林左旗| 雷波县| 亳州市| 宜阳县| 泸水县| 多伦县| 安仁县| 上犹县|