回調的方式使用startActivityForResult

問題

最近遇到了一個很有趣的問題,爲什麼不能夠用回調的方式使用startActivityForResult呢?如果我們想要用回調的方式使用,有什麼問題?
首先我們看一下目前官方的使用方式,如下圖所示
在這裏插入圖片描述
其實這個流程很複雜,很不符合高內聚的原則,特別是如果頁面的請求很多就會變成如下的情況

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode){
            case 1:
                break;
            case 2:
                break;
            case 3:
                break;
            .....          
        }
    }

如果我們想要實現成回調的方式呢?

回調實現

參考這篇博客,https://juejin.im/entry/5b9a6e3cf265da0adc18b6f7
有幾種實現方式:

  1. 使用一個代理類,幫忙處理startActivityForResult和onActivityResult,本質上和原生使用方式沒有區別,還是必須要在Activity裏的onActivityResult
    裏面手動的調用;
  2. 使用反射或者AOP,修改onActivityResult的流程,但穩定性和兼容性較差,而且可能會和其他的框架產生衝突;
  3. 比較推薦的就是這個方法,在Activity裏面增加一個空的fragment,通過這個fragment發起請求和接收結果,然後將收到的結果用回調函數傳遞給Activity。

回調的問題

那麼爲什麼官方不設計成回調的方式呢?像下面這樣子,回調的方式有啥問題

 startActivityForResult(intent, new CallBack() {
      @Override
      public void onActivityResult(int resultCode, Intent data) {
      }
  });

匿名內部類的構造函數
在上述的例子當中,callback是一個匿名內部類,我們都知道匿名內部類會持有外部類的引用,那這個引用是何時傳入的呢?
我們通過反射來查看以下匿名內部類的構造函數

private void reflect(Object callback){
    Class cl = callback.getClass();
     //構造函數
     Constructor[] declaredConstructors = cl.getDeclaredConstructors();
     for (Constructor constructor:declaredConstructors){
         Log.i("構造函數",constructor.toString());
     }
}

通過打印可以看到構造函數如下
在這裏插入圖片描述
也就是編譯器在編譯的時候替我們生成了一個構造函數,並且將對應的activity當作參數傳入。

Activity被銷燬的場景
若我們考慮下面這種情況,當A使用回調的方式跳轉到B,此時由於某種原因A被銷燬了,然後當B執行完成返回結果,系統會重新創建A1,而callback裏面持有的是A引用,並不會對A1產生作用,這顯然不是我們想要的結果。

在這裏插入圖片描述
當activity被重建,我們可以通過反射,將新的activity重新set進去,這樣callback引用的就是重建後的新的activity了。

Class cl = callback.getClass();
 Field[] fields = cl.getDeclaredFields();
 for(Field f : fields) {
     try {
         f.setAccessible(true); // 設置些屬性是可以訪問的
         String type = f.getType().toString(); // 得到此屬性的類型
         String name = f.getName();// 得到屬性的名稱
         if(type.equals(FirstActivity.class.toString())) {
             f.set(callback, this.getActivity());
         }
         Log.i("字段信息", type + ", " + name);
     } catch (Exception e) {
         e.printStackTrace();
     }
 }

結論

在Activity當中增加一個空的fragment可以解決此問題,但對於Activity銷燬和重建的場景則需額外處理,由於反射會損耗性能,
初步想法是增加Activity生命週期的感知能力,當感知到Activity有銷燬重建的動作,則使用反射重新設置一下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章