Android:我爲什麼要封裝DialogFragment?

我爲什麼要封裝DialogFragment

最近在重構項目代碼,項目中建立對話框用的是Dialog,AlertDialog。可是官方推出了DialogFragment來代替Dialog。那我就去認真的瞭解下DialogFragment。git

DialogFragment

DialogFragment是在Android3.0的時候被引入的,從其名字能夠很直觀的看出它是一種基於Fragment的Dialog,能夠用來建立對話框,它是用來替代Dialog的。一個新事物的出現是爲了解決舊事物存在的問題,那不建議使用的Dialog存在什麼問題呢?下面簡單的說下。github

Dialog存在問題:

  • 在手機配置發生變化後(好比:旋屏後),變化以前顯示的Dialog,變化以後不會顯示,更別提Dialog狀態的恢復了。編程

  • 管理自定義的Dialog和系統原生的Dialog麻煩架構

DialogFragment怎麼解決Dialog存在的問題:

  • DialogFragment說到底仍是一個Fragment,所以它繼承了Fragment的全部特性。同理FragmentManager會管理DialogFragment。在手機配置發生變化的時候,FragmentManager能夠負責現場的恢復工做。調用DialogFragment的setArguments(bundle)方法進行數據的設置,能夠保證DialogFragment的數據也能恢復。app

  • DialogFragment裏的onCreateView和onCreateDIalog 2個方法,onCreateView能夠用來建立自定義Dialog,onCreateDIalog 能夠用Dialog來建立系統原生Dialog。能夠在一個類中管理2種不一樣的dialog。ide

用DialogFragment替代Dialog

既然DialogFragment有這些好處,那我就毅然決然的對項目中的Dialog用DialogFragment來進行替代。
重構的思路是這樣的:工具

  • 首先先建立一個ConfirmDialogFragment類(該類是用來建立確認對話框的),ConfirmDialogFragment類繼承了DialogFragment。學習

  • 其次在建立一個ProgressDialogFragment類(該類是用來建立進度對話框),同時它也繼承了DialogFragment。網站

  • 其餘類型的Dialog就不舉例了。this

  • 最後在BaseActivity(項目中全部Activity的基類)添加顯示Dialog的方法,供BaseActivity的子類、Fragment、還有非Activity和非Fragment的類來調用。

咱們先看下關鍵代碼片斷:代碼地址
ConfirmDialogFragment中的代碼片斷:代碼地址

 

 

 

 

 

 

Java

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

  /**

    *用來建立確認對話框

   * Created by niuxiaowei on 2015/10/16.

*/

public class ConfirmDialogFragment extends DialogFragment{

 

        private ConfirmDialogListener mListener;

 

        //對外開放的接口

        public static interface ConfirmDialogListener extends DialogInterface.OnClickListener{

        }

 

        /**

         * @param title

        * @param message

         * @param cancelable

         * @return

         */

        public static ConfirmDialogFragment newInstance(String title, String message,boolean cancelable){

              ConfirmDialogFragment instance = new ConfirmDialogFragment();

              Bundle args = new Bundle();

              args.putString("title",title);

              args.putString("message",message);

              args.putBoolean("cancelable",cancelable);

              instance.setArguments(args);

              return instance;

        }

 

        @NonNull

        @Override

        public Dialog onCreateDialog(Bundle savedInstanceState) {

            建立ConfirmDialog核心代碼,能夠下載源代碼查看.....

        }

 

        @Override

        public void onAttach(Activity activity) {

            super.onAttach(activity);

            if (getActivity() instanceof ConfirmDialogListener ) {

                  mListener= (ConfirmDialogListener ) getActivity();

            }

        }

        ......

  }

ConfirmDialogFragment很關鍵的一點,ConfirmDialogFragment中的mListener屬性的值是經過

 

 

 

 

 

Java

 

1

2

3

4

5

6

7

   @Override

        public void onAttach(Activity activity) {

            super.onAttach(activity);

            if (getActivity() instanceof ConfirmDialogListener ) {

                  mListener= (ConfirmDialogListener ) getActivity();

            }

        }

方式獲取的。

BaseActivity中代碼片斷:代碼地址

 

 

 

 

 

Java

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

public class BaseActivity extends FragmentActivity

{

           /*

            *顯示確認對話框方法

           */

          public void showConfirmDialog(...){

                 ......

           }

 

           /*

            *顯示進度條對話框方法

           */

          public void showProgressDialog(...){

                 ......

          }

}

那咱們就重構BaseActivity的子類顯示Dialog的代碼:
我拿MainActivity來舉例子:
MainActivity的關鍵重構代碼:

 

 

 

 

 

 

Java

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

    /*

    *實現確認對話框的ConfirmDialogListener 接口

     *created by niuxiaowei

   */

   public class MainActivity extends BaseActivity implements ConfirmDialogListener {

 

           @Override

          public void onClick(DialogInterface dialogInterface, int i) {

              Toast.makeText(this,"點擊了MainActivity 調起的確認對話框 i="+i,Toast.LENGTH_LONG).show();

          }

 

         //調用顯示ConfirmDialog代碼

         showConfirmDialog(...);

 

        //調用顯示ProgressDialog代碼

         showProgressDialog(...);

}

如今MainActivity裏的代碼運行起來徹底沒問題,由於MainActivity裏面包含了3個Fragment,每一個Fragment裏面都有顯示ConfirmDialog和ProgressDialog的代碼,因此開始重構這3個Fragment:
重構思路:

  • 每一個Fragment裏均可以獲取到相對應的Activity的實例,只要獲取到實例就能夠調用顯示對話框的方法來顯示對話框了。

  • 對話框中的事件怎麼傳遞給Fragment問題?Activity能夠獲取到Fragment的實例,對話框能夠把事件傳遞給Activity,所以Activity瓜熟蒂落的能夠把事件傳遞給對應的Fragment。

  • 一個Activity有多個Fragment調用顯示對話框的方法,在Activity的實現了對話框接口的方法裏怎樣區分不一樣的Fragment調用者?能夠在BaseActivity顯示對話框的方法里加個id參數,用id來區分不一樣的Fragment調用者。
    那就上關鍵代碼片斷:
    MainActivity中的AFragment代碼片斷:

     

     

     

     

     

     

    Java

     

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    public AFragment extends Fragment implements ConfirmDialogListener{

     

           @Override

            public void onClick(DialogInterface dialogInterface, int i) {

                Toast.makeText(this,"點擊了AFragment 調起的確認對話框 i="+i,Toast.LENGTH_LONG).show();

            }

     

           //調用顯示ConfirmDialog代碼

           getActivity().showConfirmDialog(...);

    }

同理MainActivity的BFragment,CFragment的重構與AFragment相似。
MainActivity的關鍵代碼片斷:

 

 

 

 

 

Java

 

1

2

3

4

5

6

7

8

9

10

11

  @Override

  public void onClick(DialogInterface dialogInterface, int i) {

             //僞代碼

             if(mId == aFragment傳遞Id){

                    aFragment.onClick(dialogInterface,i);

             }else if(mId == bFragment傳遞Id){

             }else if(mId == cFragment傳遞Id){

             }else if(mId == mainActiviy傳遞Id){

                   調用本身的方法

             }

  }

 

產生的問題

看了MainActivity的onClick方法裏面代碼我都對本身無語了,onClick方法裏面充斥着各類的if else 語句,而且當前的MainActivity裏,若再有別的顯示ConfirmDialog的調用者,onClick方法裏少不了要增長對應的else if語句。MainActivity只是項目中全部Activity的一個縮影。其餘的Activity也會遇到一樣的問題(這不是我意淫的,提前預估到問題,提前入手進行解決老是好的)

咱們拿MainActivity來表明全部的Activity總結下使用DialogFragment建立Dialog產生的問題:

  • MainActivity裏的onClick方法維護、擴展性很差,充斥着各類if else if語句,可讀性也很差。

  • MainActivity裏的onClick方法除了把Dialog的事件轉發給相對應的調用者以外,沒有多任何其餘操做,因此是多餘的

  • 顯示Dialog的方法不靈活

存在這些問題嚴重影響了我後面的重構工做,因而乎我就去國內國外網站上搜索對應的解決方法,可是也沒有找到好的方法,最後我就想辦法本身解決上面的問題,這也是我爲什麼要封裝DialogFragment的原因

封裝DialogFragment,讓DialogFragment使用很是簡單、靈活

咱們仔細的分析下上文的問題的主要緣由是顯示Dialog的方法沒有把Dialog裏面的開放的接口做爲參數致使的,假如能像下面的使用方式:

 

 

 

 

 

Java

 

1

2

3

4

5

6

    //某一個Activity中顯示ConfirmDialog

    showConfirmDialog(title,message,confirmDialogListener);

    //某一個Fragment中顯示ConfirmDialog

    getActivity().showConfirmDialog(this,message,confirmDialogListener);

    //非Activity和非Fragment的類中顯示ConfirmDialog

    mActivity.showConfirmDialog(this,message,confirmDialogListener);

上文中全部的問題均可以解決。

爲何不按下面的作法作

作法1:那咱們直接把ConfirmDialogListener 的實例賦值給ConfirmDialogFragment 的實例的mListener屬性,如下爲代碼:

 

 

 

 

 

 

Java

 

1

2

3

4

5

6

7

      //直接把listener傳遞

       public static ConfirmDialogFragment newInstance(...,ConfirmDialogListener listener){

              ConfirmDialogFragment instance = new ConfirmDialogFragment();

              ......

              instance.mListener = listener;

              ......

        }

那我就詳細的解釋下爲何不這樣作的具體緣由:

  • 在建立Fragment的時候,最好是把傳遞給Fragment的數據存放在Bundle中,而後在調用fragment的setArguments(bundle)方法進行數據的設置,這種作法好處是:系統會保存Fragment的數據,在手機配置發生變化後(好比旋屏),系統會把保存的Fragment數據進行恢復。

以上作法,ConfirmDialogFragment 中mListener屬性系統沒有爲之保存,因此手機配置發生變化後,ConfirmDialogFragment 中的mListener 是null。

作法2:那咱們是否能夠把ConfirmDialogListener實例(ConfirmDialogListener是ConfirmDialogFragment 對外開放的接口)存放在Bundle中?
答案是不能夠,首先 Bundle對存放的數據是有限制的,把ConfirmDialogListener的實例存入Bundle中是比較複雜的操做。其次即便經過艱辛萬苦把ConfirmDialogListener實例存入了Bundle中,保存ConfirmDialogListener實例是毫無心義的,只有保存數據對於Fragment來講纔有意義,保存行爲對Fragment是無心義的。

有思路

咱們在回顧下ConfirmDialogFragment中onAttach的方法的關鍵代碼:代碼地址

 

 

 

 

 

Java

 

1

2

3

4

5

6

7

   @Override

   public void onAttach(Activity activity) {

       if(getActivity() instanceof ConfirmDialogListener){

          //關鍵代碼

           mListener= (ConfirmDialogListener)getActivity();

      }

    }

以上代碼的關鍵之處在於mListener= (ConfirmDialogListener)getActivity()。同時痛點也在此處,這是一種相似於硬編碼的方式,硬編碼的一個很差的地方就是沒有擴展性。解決思路:

  • 那咱們就想辦法讓此處變的有彈性。咱們能夠把BaseActivity想象爲一個ConfirmDialogListener的存取工具,調用者能夠把本身實現的ConfirmDialogListener存入BaseActivity中, ConfirmDialogFragment能夠從BaseActivity中取出ConfirmDialogListener實例,那個人問題就迎刃而解了。

  • 既然能夠獲取到BaseActivity的實例,那也能夠獲取到BaseFragment的實例(getParentFragment()能夠獲取到)。既然BaseFragment實例能夠獲取到,那解決ConfirmDialogFragment同時服務於BaseActivity和BaseFragment就不是問題了

同時我還想解決在任何的類中(無論Fragment、Activity、或其餘類中)顯示Dialog不須要依賴BaseActivity。而是有一個類(假如叫DialogFactory)定義顯示各類Dialog的方法。像下面同樣:

 

 

 

 

 

 

Java

 

1

2

3

4

5

6

     //某一個Activity中顯示ConfirmDialog

    mDialogFactory.showConfirmDialog(title,message,confirmDialogListener);

    //某一個Fragment中顯示ConfirmDialog

    mDialogFactory.showConfirmDialog(this,message,confirmDialogListener);

    //非Activity和非Fragment的類中顯示ConfirmDialog

    mDialogFactory.showConfirmDialog(this,message,confirmDialogListener);

那我就說下思路:

  • 新建DialogFactory類,該類封裝了顯示各類Dialog的方法

  • 新建BaseDialogFragment類,該類是各類類型Dialog的基類,裏面封裝了一些公用的方法

  • 修改BaseActivity和BaseFragment類,在各自的類中分別定義DialogFactory屬性mDialogFactory,這樣顯示Dialog的任務就交給了mDialogFactory

DialogFactory 代碼:代碼地址

 

 

 

 

 

 

Java

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

  /** * Created by niuxiaowei on 2016/2/3. * 對話框工廠 */

  public class DialogFactory {

 

        private FragmentManager mFragmentManager;

        private BaseActivity mBaseActivity;

        private BaseFragment mBaseFragment;

 

        public DialogFactory(BaseActivity baseActivity,FragmentManager fragmentManager){  

               this.mFragmentManager = fragmentManager;  

               this.mBaseActivity = baseActivity;  

        }

 

        public DialogFactory(BaseFragment baseFragment,FragmentManager fragmentManager){  

               this.mFragmentManager = fragmentManager;  

               this.mBaseFragment= baseFragment;  

        }

 

        /** * 進度條對話框

        * @param message 進度條顯示的信息

        * @param cancelable 點擊空白處是否能夠取消 */

       public void showProgressDialog(String message, boolean cancelable){  

              省略此處代碼......

        }

 

        /**

        *  顯示確認對話框,dialogId是用來區分不一樣對話框的

       * @param title 對話框title

       * @param message

       * @param cancelable

       * @param listener

       */

       public void showConfirmDialog(String title,String message,boolean cancelable,ConfirmDialogListener listener){

               省略此處代碼......

               if(mBaseActivity != null){

                    mBaseActivity.setDialogListener(listener);

               }else if(mBaseFragment != null){

                    mBaseFragment.setDialogListener(listener);

                }

         }

 

        顯示其餘類型的dialog方法......

   }

DialogFactory關鍵代碼介紹:

  • DialogFactory能夠供任何的類來使用

  • mFragmentManager屬性在現實Dialog時起做用,若調用者(顯示Dialog)是Activity,則傳遞getFragmentManager();若調用者是Fragment,則傳遞getChildFragmentManager()。不過不須要擔憂這些,BaseActivity和BaseFragment都已經封裝了這些參數

  • DialogFactory把調用者傳遞過來的BaseDialogListener傳遞給Activity或Fragment

BaseDialogFragment代碼:代碼地址

 

 

 

 

 

 

Java

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

    /** * Created by niuxiaowei on 2015/10/15. * 自定義dialog,是全部自定義dialog的基類 */

    public class BaseDialogFragment extends DialogFragment {

 

        /** * 基礎的dialog listener,沒有提供任何的方法,擴展的dialog,若該dialog有listener則必須繼承本接口 */

        public static interface BaseDialogListener{}

 

        /** * 接收dialog listener對象,具體由子類進行實現 * @param listener */

        protected void onReceiveDialogListener(BaseDialogListener listener){}

 

         @Override

         public void onActivityCreated(Bundle savedInstanceState) {

 

              /*解析BaseDialogListener,fragment的級別要大於activity,若

              *  (getParentFragment() instanceof BaseFragment)爲true* ,

               * 代表是一個fragment調起的dialog,不然是一個activity調起的diaolog

              * */

              BaseDialogListener listener = null;

              if (getParentFragment() instanceof BaseFragment) {    

                    listener = ((BaseFragment) getParentFragment()).getDialogListener();

              }else if(getActivity() instanceof BaseActivity){

                   listener = ((BaseActivity)getActivity()).getDialogListener();

              }

              if(listener != null){

                  onReceiveDialogListener(listener);

              }

         }

    }

BaseDialogFragment關鍵代碼介紹:

  • BaseDialogListener定義一個空方法接口,新增的Dialog(若該Dialog包含對外接口),則新增的Dialog提供的對外接口必須繼承BaseDialogListener

  • onReceiveDialogListener方法是提供給子類來實現,讓子類來接收調用者傳遞進來的BaseDialogListener實例

  • onActivityCreated方法很重要,該方法是使BaseDialogFragment能夠兼容Activity和Fragment的關鍵代碼

     

     

     

     

     

     

    Java

     

    1

    2

    3

    4

    5

    if (getParentFragment() instanceof BaseFragment) {    

               listener = ((BaseFragment) getParentFragment()).getDialogListener();

      }else if(getActivity() instanceof BaseActivity){

              listener = ((BaseActivity)getActivity()).getDialogListener();

      }


    上面代碼的做用是假如當前調用者(顯示Dialog)是一個Fragment,則會把Fragment中持有的BaseDialogListener賦給對應的Dialog,若當前調用者是一個Activity,則會作一樣的事情

ConfirmDialogFragment 關鍵代碼片斷:代碼地址

 

 

 

 

 

 

Java

 

1

2

3

4

5

6

7

8

9

        //繼承BaseDialogListener

        public static interface ConfirmDialogListener extends BaseDialogListener,DialogInterface.OnClickListener{

        }

 

        public void onReceiveDialogListener(BaseDialogListener listener){

              if(listener instanceof ConfirmDialogListener ){

                       mListener = (ConfirmDialogListener )listener;

              }

       }

ProgressDialogFragment基本沒發生多大改變,咱們就不貼具體代碼了。

修改BaseActivity和BaseFragment類關鍵代碼:

 

 

 

 

 

 

Java

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

public class BaseActivity extends FragmentActivity{

 

        protected DialogFactory mDialogFactory ;

        private BaseDialogListener mListener;

 

        public void getDialogListener(){

               return mListener;

        }

 

        public void setDialogListener(BaseDialogListener listener){

                mListener = listener;

        }

 

        public void onCreate(Bundle savedInstanceState){

               super.onCreate(savedInstanceState);

               mDialogFactory = new DialogFactory(this,getFragmentManager();

        }

}

 

  public class BaseFragment extends Fragment{

 

        protected DialogFactory mDialogFactory ;

        private BaseDialogListener mListener;

 

        public void getDialogListener(){

               return mListener;

        }

 

        public void setDialogListener(BaseDialogListener listener){

                mListener = listener;

        }

        public void onCreate(Bundle savedInstanceState){

               super.onCreate(savedInstanceState);

               mDialogFactory = new DialogFactory(this,getChildFragmentManager();

        }

}

介紹下BaseActivity修改的代碼:

  • mDialogFactory 是供Activity來顯示各類Dialog的

  • mListener是Activity持有調用者傳遞的BaseDialogListener的實例,BaseDialogFragment會從getDialogListener()方法獲取該實例

BaseFragment的修改和BaseActivity同樣,就不介紹了。

那咱們在理一下上面代碼的思路:

  • DialogFactory封裝了顯示各類Dialog的方法,使用者使用它來顯示Dialog。它會把使用者傳遞的BaseDialogListener傳遞給BaseActivity或BaseFragment

  • BaseActivity和BaseFragment在傳遞BaseDialogListener起了一個橋樑的做用。當Dialog即將被顯示時,BaseDialogFragment會從BaseActivity或BaseFragment獲取BaseDialogListener

解決最棘手的問題

當我還沉浸在happy中時,忽然一個問題出現了,旋屏後從新彈出的ConfirmDialog的點擊事件卻沒傳遞給調用者,我就細細的想原來是旋屏後BaseActivity或BaseFragment裏的mListener爲空了。那我就繼續解決這棘手問題,爲何棘手呢?由於咱們一直都是在圍繞着怎樣解決旋屏後Dialog中的mListener屬性的值(BaseDialogListener的實例)怎麼從新獲取的問題,可是通過一番努力仍是沒成功,不行我還得繼續想辦法。

上文中也提到過對於Fragment存放行爲是毫無心義的,那咱們就換個角度考慮問題,咱們先用BaseFragment來舉例子(BaseActivity相似):

  • 在BaseFragment用一個屬性mDialogListenerKey去存mListener(類型是BaseDialogListener)屬性的類名,當手機配置發生變化的時候在BaseFragment的onSaveInstance(bundle)方法中把mDialogListenerKey存入Bundle中(前提條件Dialog沒消失)

  • 當BaseFragment從新被建立的時候,在onCreate(savedInstanceState)方法中從Bundle中把mDialogListenerKey值讀出來

  • 根據mDialogListenerKey去找到對應的BaseDialogListener子類的實例

  • 把上步中找到的實例經過調用BaseFragment的setDialogListener()方法進行設置

那咱們就開始寫代碼:
新建DialogListenerHolder,該類用來持有調用者傳遞的BaseDialogListener實例,即把原來BaseActivity或BaseFragment裏的mListener屬性放到該類中
DialogListenerHolder修改的代碼片斷:代碼地址

 

 

 

 

 

 

Java

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

public class DialogListenerHolder{

 

      private BaseDialogListener mDialogListener;

      /** * 對話框的listener的key值,用類名做爲key值,

      *主要用來在手機配置發生變化時(橫屏換爲豎屏),

       *當現場恢復時,能正確的找到對話框的listener */

      private String mDialogListenerKey;

 

      public void setDialogListener(BaseDialogFragment.BaseDialogListener listener){        

          mDialogListener = listener;    

          mDialogListenerKey = listener == null ?null:listener.getClass().getName();

      }

 

      /** * 把listener的key值保存在bundle中,配置發生變化的狀況下(橫屏換爲豎屏),在從bundle中取listener的key值

     * @param outState */

    public void saveDialogListenerKey(Bundle outState){      

          if(outState != null){        

              outState.putString("key",mDialogListenerKey);

          }

    }

 

    /** * 從bundle中嘗試取出dialog listener key

   * @param savedInstanceState */

    public void getDialogListenerKey(Bundle savedInstanceState){    

          if(savedInstanceState != null){

               mDialogListenerKey = savedInstanceState.getString("key");

          }

    }

 

    /** * 這個方法很重要,是恢復dialog listener的一個關鍵點,

    *在初始化DialogFactory或把DialogFactory賦值後,調用該方法,把調用該方法所在

   * 的類的實例做爲參數。 該方法會把param中的屬性依次遍歷,嘗試找屬性是BaseDialogFragment.BaseDialogListener的實例,

   * 而且該屬性就是保存在bundle中的dialog listener key對應的dialog listener

  * @param o */

  public void restoreDialogListener(Object o){

        if(o == null){

              return;

         }

         if(!isNeedRestoreDialogListener()){

              return;

         }

       //先嚐試找傳進來的實例

        if(o instanceof BaseDialogFragment.BaseDialogListener & o.getClass().getName().equals(mDialogListenerKey))

        {        

       setDialogListener((BaseDialogFragment.BaseDialogListener)o);

           return;

       }

 

      Class c = o.getClass();

      Field[] fs = c.getDeclaredFields();

      for (int i = 0; i

代碼有點複雜我先簡單介紹下:
DialogListenerHolder中的mDialogListenerKey是存BaseDialogListener的子類的類名。

DialogListenerHolder中的saveDialogListenerKey(Bundle outState)方法是把mDialogListenerKey存到Bundle中,這樣系統就能夠存儲下該值。供BaseActivity或BaseFragment的onSaveInstanceState(Bundle outState)方法調用。

DialogListenerHolder中的getDialogListenerKey(Bundle savedInstanceState)方法是從Bundle中取出mDialogListenerKey,供BaseActivity或BaseFragment的onCreate(Bundle savedInstanceState)調用。

DialogListenerHolder中的restoreDialogListener(Object o)方法很重要,做用是從參數o中去查找mDialogListenerKey對應的BaseDialogListener(查找範圍是參數o和o中的屬性),若找到並調用setDialogListener()方法。
因此這裏對於調用者(調起Dialog)傳遞的BaseDialogListener有個要求:調用者實現了BaseDialogListener的子類或者調用者包含BaseDialogListener的子類的一個public屬性

DialogFactory修改代碼片斷:代碼地址

 

 

 

 

 

 

Java

 

1

2

3

4

5

6

7

8

9

10

private DialogListenerHolder mListenerHolder;

 

public DialogFactory(FragmentManager fragmentManager, Bundle savedInstanceState){

    this.mFragmentManager = fragmentManager;    

    mListenerHolder.getDialogListenerKey(savedInstanceState);

}

 

public void restoreDialogListener(Object o){    

    mListenerHolder.restoreDialogListener(o);

}

BaseActivity修改代碼片斷:代碼地址

 

 

 

 

 

 

Java

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

public BaseDialogFragment.BaseDialogListener getDialogListener()  {

    return mDialogFactory.mListenerHolder.getDialogListener();

}

 

@Override

public void onSaveInstanceState(Bundle outState) {            

   super.onSaveInstanceState(outState);    

mDialogFactory.mListenerHolder.saveDialogListenerKey(outState);

}

@Override

protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    mDialogFactory = new DialogFactory(getSupportFragmentManager(),savedInstanceState);  

    mDialogFactory.restoreDialogListener(this);

}

BaseFragment修改代碼片斷:代碼地址

 

 

 

 

 

 

Java

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

public BaseDialogFragment.BaseDialogListener getDialogListener()  {

    return mDialogFactory.mListenerHolder.getDialogListener();

}

@Override

public void onSaveInstanceState(Bundle outState) {    

    super.onSaveInstanceState(outState);    

   mDialogFactory.mListenerHolder.saveDialogListenerKey(outState);

}

 

@Override

public void onActivityCreated(Bundle savedInstanceState) {    

   super.onActivityCreated(savedInstanceState);

   mDialogFactory = new DialogFactory(getChildFragmentManager(),savedInstanceState);

   mDialogFactory.restoreDialogListener(this);

}

到此爲止咱們的封裝就一切ok了,高興下。

總結

通過一步步艱辛的路程,封裝DialogFragment的工做終於結束了,封裝好的Dialog架構能夠給您帶來如下好處:

  • 可讓DialogFragment的使用像Dialog同樣的簡單、靈活,同時也保持了DialogFragment的優勢,能夠在任何的類中使用。就像下面代碼:

     

     

     

     

     

     

    Java

     

    1

    2

    3

    4

    5

    6

      //某一個Activity中顯示ConfirmDialog

      mDialogFactory.showConfirmDialog(title,message,confirmDialogListener);

      //某一個Fragment中顯示ConfirmDialog

      mDialogFactory.showConfirmDialog(this,message,confirmDialogListener);

      //非Activity和非Fragment的類中顯示ConfirmDialog

      mDialogFactory.showConfirmDialog(this,message,confirmDialogListener);

  • 很簡單的新增新類型的Dialog

同時在使用的時候須要注意如下幾點:

1 . 在既不是Activity也不是Fragment的類(下面咱們簡稱該類)中調起Dialog要求:

  • 該類擁有DialogFactory 屬性(DialogFactory 的值是從繼承了BaseActivity的Activity或繼承了BaseFragment的Fragment傳遞進來的)

  • 在給DialogFactory 屬性賦值後,緊接着須要調用DialogFactory 的restoreDialogListener(Object)方法

  • 該類實現了XXDialogListener或者該類包含XXDialogListener這樣的一個屬性(該屬性權限必須是public)

2 .在繼承了BaseActivity的Activity(簡稱activity)中或者繼承了BaseFragment的Fragment(簡稱fragment)中調起Dialog的要求:

  • activity或fragment實現了XXDialogListener或者是activity或fragment包含XXDialogListener這樣的一個public類型的屬性。

3 .若須要建立新的類型的Dialog,須要注意的是:

  • 繼承BaseDialogFragment

  • 若該Dialog對外提供接口(接口須要繼承BaseDialogListener,須要實現onReceiveDialogListener()方法)

以上是我我的的總結,但願對給Android學習者提供幫助。代碼地址

問啊-定製化IT教育平臺,牛人一對一服務,有問必答,開發編程社交頭條 官方網站:www.wenaaa.com 下載問啊APP,參與官方懸賞,賺百元現金。

QQ羣290551701 彙集不少互聯網精英,技術總監,架構師,項目經理!開源技術研究,歡迎業內人士,大牛及新手有志於從事IT行業人員進入!

相關文章
相關標籤/搜索