android fragment 面試

總結

參考:https://www.jianshu.com/p/28ca4cbe190c

參考:https://www.jianshu.com/p/11c8ced79193

1.生命週期

參考:https://blog.csdn.net/gyh790005156/article/details/79487576

2.Fragment實現原理和Back Stack

參考:https://www.jianshu.com/p/28ca4cbe190c

參考:https://www.jianshu.com/p/11c8ced79193

面試題

1. Fragment爲什麼被稱爲第五大組件

Fragment比Activity更節省內存,其切換模式也更加舒適,使用頻率不低於四大組件,且有自己的生命週期,並且必須依付於Activity

2. Activity創建Fragment的方式

  • 靜態創建具體步驟

首先我們同樣需要註冊一個xml文件,然後創建與之對應的java文件,通過onCreatView()的返回方法進行關聯,最後我們需要在Activity中進行配置相關參數即在Activity的xml文件中放上fragment的位置。

  • 動態創建具體步驟

(1)創建待添加的碎片實例

(2)獲取FragmentManager,在活動中可以直接通過調用 getSupportFragmentManager()方法得到。

(3)開啓一個事務,通過調用beginTransaction()方法開啓。

(4)向容器內添加或替換碎片,一般使用repalce()方法實現,需要傳入容器的id和待添加的碎片實例。

(5)提交事務,調用commit()方法來完成。

3. FragmentPageAdapter和FragmentPageStateAdapter的區別

  • FragmentPagerAdapter:

適用於頁面較少的情況,後者適用於頁面較多的情況,通過源碼瞭解,主要查看destroyItem方法中的最後一行,mcurtransaction.remove(fragment),通過這行代碼瞭解到,FragmentStatePagerAdapter是真正釋放fragment內存,

  • FragmentStatePagerAdapter

在FragmentPagerAdapter的destroyItem方法中所調用的是mcurtransaction.detach(fragment),他僅僅是將fragment的頁面與activity的頁面抽離開來,並沒有真正的銷燬fragment釋放內存.

4. Fragment的生命週期

5. Fragment通信

  • Fragment與Activity通信方式

1.在fragment中調用activity中的方法getActivity

2.在Activity中條用Fragment中的方法,一般常用的是接口回調,在fragment中創建接口,在activity中實現接口,這樣就能完成activity中調用fragment中的方法

3.在Fragment中調用Fragment中的方法,首先先通過getactivity方法,獲取activity的方法,然後通過fingFragmentById獲取到另外一個fragment的方法,然後進行調用

6. ViewPager與Fragment結合使用時的懶加載問題

  • 所謂的 “懶加載” 就是數據只有在Fragment對於用戶可見的時才進行加載。因爲ViewPager會幫我們預先初始化Fragment。由於這個特性,我們不能把數據的加載放到onCreateView方法或者onCreate方法中。

因此,我們需要判定Fragment在什麼時候是處於可見的狀態。一般我們通常是通過Fragment中的生命週期方法onResume來判斷Fragment是否可見,但是由於ViewPager預加載的特性,Fragment即便不可見也會執行onResume方法,因此使用這個方法進行可見性的判斷就行不通了。這個時候我們需要用到下面的這個方法來進行Fragment可見性的判斷:

setUserVisibleHint()方法:

什麼時候被調用?

  • 當fragment被創建的時,setUserVisibleHint(boolean isVisibleToUser)方法會被調用,且傳入參數值爲false。
  • 當fragment可見時,setUserVisibleHint(boolean isVisibleToUser)方法會被調用,且傳入參數值爲true。
  • 當fragment由 可見 -> 不可見 時,setUserVisibleHint(boolean isVisibleToUser)方法會被調用,且傳入參數值爲false。

只需要當setUserVisibleHint(boolean isVisibleToUser)方法中的 isVisibleToUser 參數的值爲true的時候我們纔開始進行數據的加載

注意事項:
setUserVisibleHint(boolean isVisibleToUser)方法在Fragment的生命週期方法onCreate 之前調用的,也就是說他並不在Fragment的生命週期中。既然是在 onCreate 方法之前被調用,這樣就存在許多不確定因素,如果Fragmnet的View還沒有完成初始化之前,就在setUserVisibleHint()方法中進行UI的操作,這樣顯然會導致空指針的出現

解決方法:

我們需要對Fragment創建的View進行緩存,確保緩存的View不爲空的情況下我們纔可以在setUserVisibleHint方法中進行UI操作。

/**
 * Fragment的基類(懶加載)
 * Created by wangke on 17-8-15.
 */

public abstract class BaseLazyFragment extends RxFragment {

    private String TAG;
    //標記當前Fragment的可見狀態
    private boolean isFragmentVisible;
    private boolean isFirstVisible;
    //對Fragment中加載的View進行緩存
    private View mRootView;
    private Unbinder mUnbinder;


    public BaseLazyFragment(String TAG) {
        this.TAG = TAG;
    }


    /**
     * 當Fragment添加到Activity的時候最先調用此方法
     *
     * @param context 上下文對象
     */
    @Override
    public void onAttach(Context context) {

        super.onAttach(context);
        //獲取Fragment之間傳遞過來的參數
        initArgs(getArguments());

    }

    /**
     * 獲取Fragment中傳遞過來的參數,選擇重寫
     *
     * @param arguments
     */
    protected void initArgs(Bundle arguments) {


    }


    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {

        LogHelper.i("wwk", TAG + " ===>onCreate");
        super.onCreate(savedInstanceState);
        initVariable();
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        View view = inflater.inflate(getContentLayoutId(), container, false);
        mUnbinder = ButterKnife.bind(this, view);
        initWidget(mRootView);
        initEvent();

        return view;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        LogHelper.i("wwk", TAG + " ===>onViewCreated");

        if (mRootView == null) {
            mRootView = view;
            if (getUserVisibleHint()) {
                if (isFirstVisible) {
                    //處於可見狀態並且Fragment是第一次開啓
                    onFragmentFirstVisible();
                    isFirstVisible = false;
                }

                onFragmentVisibleChange(true);
                isFragmentVisible = true;
            }
        }

        //直接使用緩存的mRootView
        super.onViewCreated(mRootView, savedInstanceState);
    }

    /**
     * 初始化控件事件,選擇重寫
     */
    private void initEvent() {

    }

    /**
     * 初始化組件
     *
     * @param view
     */
    protected abstract void initWidget(View view);


    /**
     * 當Fragment第一次創建的時候調用,如果不可見則isVisible的參數值爲false
     * 當Fragment對於用戶可見時調用,此時的isVisibleToUser參數值爲true
     * 當Fragment當前的狀態由可見變爲不可見時調用,此時的isVisibleToUser參數爲false
     *
     * @param isVisibleToUser true : 可見
     *                        false : 不可見
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        LogHelper.i("tag", TAG + " ==> setUserVisibleHint ");
        super.setUserVisibleHint(isVisibleToUser);
        //setUserVisibleHint()的調用在Fragment的聲明週期外調用,需要保證rootView不爲空的時候調用 onFragmentVisibleChange方法
        if (mRootView == null) {
            return;
        }

        //第一次被開啓,並且對用戶可見(這個if語句中的判斷一般不會被執行到,setUserVisibleHint方法的調用時mRootView還沒有被緩存)
        if (isFirstVisible && isVisibleToUser) {
            //當Fragment第一次可見的時候調用
            onFragmentFirstVisible();
            isFirstVisible = false;
        }

        //Fragment對於用戶可見(已經不是第一次開啓)
        if (isVisibleToUser) {
            onFragmentVisibleChange(true);
            isFragmentVisible = true;
            return;
        }

        //能執行到這裏表明 Fragment對於用戶已經處於不可見的狀態
        if (isFragmentVisible) {
            //由 可見 -> 不可見
            isFragmentVisible = false;
            onFragmentVisibleChange(false);
        }
    }


    /**
     * 獲取填充Fragment的View的id
     *
     * @return
     */
    protected abstract int getContentLayoutId();


    /**
     * 當Fragment的狀態發生變化的時候調用,用於進行數據的刷新
     *
     * @param isVisible true  不可見 -> 可見
     *                  false 可見  -> 不可見
     */
    protected abstract void onFragmentVisibleChange(boolean isVisible);

    /**
     * 當Fragment第一次被開啓的時候調用,用於請求數據
     */
    protected abstract void onFragmentFirstVisible();

    /**
     * 獲取當前Fragment的可見狀態
     *
     * @return
     */
    protected boolean isFragmentVisible() {
        return isFragmentVisible;
    }

    /**
     * 給變量賦初始值
     */
    private void initVariable() {
        //標記是否是第一次開啓當前Fragment
        isFirstVisible = true;
        //標記Fragment對於用戶是否可見
        isFragmentVisible = false;
        //緩存Fragment創建出來的View
        mRootView = null;
    }

    @Override
    public void onDestroy() {
        initVariable();
        mUnbinder.unbind();
        super.onDestroy();
    }


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