Activity & Fragment & tips

相比於Activity來說,創建一個Fragment所需系統資源相比Activity來說更少,然而控制卻更爲靈活。Fragment一般分爲兩類,一類是有UI的Fragment,可以作爲頁面,作爲View來展示,另一類是用沒有UI的Fragment,一般用作保存數據。

封裝BaseFragment基類

例如爲了實例化View,抽象一個getLayoutId方法,子類無需關心具體的創建操作,父類來做View的創建處理。同時可以提供一個afterCreate抽象函數,在初始化完成之後調用,子類可以做一些初始化的操作,你也可以添加一些常用的方法在基類,例如ShowToast().

public abstract class BaseFragment extends Fragment {
    protected View mRootView;

@Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        if(null == mRootView){
           mRootView = inflater.inflate(getLayoutId(), container, false);
        }
        return mRootView;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        afterCreate(savedInstanceState);
    }

protected abstract int getLayoutId();

    protected abstract void afterCreate(Bundle savedInstanceState);
}

public View onCreateView 這個方法中返回之前判斷一下你的mRootView是null再inflate,這樣會比較好,在ViewPager中隨着頁面滑動這個方法會調用多次,inflate過了之後就直接用就好了。

使用靜態工廠方法newInstance(…)來獲取Fragment實例

可以在Google的代碼中發現這種寫法,好處是接收確切的參數,返回一個Fragment實例,避免了在創建Fragment的時候無法在類外部知道所需參數的問題,在合作開發的時候特別有用。
還有就是Fragment推薦使用setArguments來傳遞參數,避免在橫豎屏切換的時候Fragment自動調用自己的無參構造函數,導致數據丟失。

public static WeatherFragment newInstance(String cityName) {
    Bundle args = new Bundle();
    args.putString(cityName,"cityName");
    WeatherFragment fragment = new WeatherFragment();
    fragment.setArguments(args);
    return fragment;
}

Fragment狀態保存/現場恢復

不要在Fragment裏面保存ViewState!
爲了讓你的代碼更加清晰和穩定,最好區分清楚fragment狀態保存和view狀態保存,
如果某個屬性屬於View,則不要在Fragment中做它的狀態保存,除非屬性屬於Fragment。

每一個自定義View都有義務實現狀態的保存,可以像EditText一樣,設置一個開關來選擇是否保存
比如說:android:freezeText=”true/false”。

public class CustomView extends View {
    @Override
    public Parcelable onSaveInstanceState() {
        Bundle bundle = new Bundle();
        // 在這裏保存當前狀態
        return bundle;
    }
    @Override
    public void onRestoreInstanceState(Parcelable state) {
        super.onRestoreInstanceState(state);
        // 恢復保存的狀態
    }
}

處理fragment狀態保存,例如保存從服務器獲取的數據。

private String serverData;

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("data", serverData);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        serverData = savedInstanceState.getString("data");
    }

避免錯誤操作導致Fragment的視圖重疊

視圖重疊是因爲fragment已經發生了內存泄漏。
activity的創建、銷燬完全託管到systemserver(ams),而fragment一般是手動new一個對象再add到systemserver,所以這裏就有問題了。
fragment生命週期開始於add,結束於remove。不管app中間怎麼變化,崩潰、進程被回收,只要沒有remove,android框架都會自動創建、恢復fragment的狀態。
這個問題很簡單,在add或者replace的時候,調用含有TAG參數的那個方法,之後再add相同TAG的Fragment的話,之前的會被替換掉,也就不會同時出現多個相同的Fragment了。

public class WeatherFragment extends Fragment {
    //TAG
    public static final String TAG = WeatherFragment.class.getSimpleName();

不過爲了最大限度的重用,可以在Activity的onCreate(Bundle savedInstanceState)中判斷savedInstanceState是否不爲空;

不爲空的話,先用getSupportFragmentManager(). findFragmentByTag()找一下,找到實例就不用再次創建。

WeatherFragment fragment = null;

if(savedInstanceState!=null){
fragment = getSupportFragmentManager().findFragmentByTag(WeatherFragment.TAG);
}

if(fragment == null){
   fragment = WeatherFragment.newInstance(...);
}

Fragment裏監聽虛擬按鍵和實體按鍵的返回事件

mRootView.setFocusable(true);
mRootView.setFocusableInTouchMode(true);
mRootView.setOnKeyListener(new View.OnKeyListener() {
    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            //不一定是要觸發返回棧,可以做一些其他的事情,我只是舉個栗子。
            getActivity().onBackPressed();
            return true;
        }
        return false;
    }
});

注意事項:
* FragmentTransaction異步執行相關問題。FragmentTransaction#commit函數是異步執行的(其把本次transaction的所有操作添加到消息隊列裏),不注意這一點可能會出現一些奇怪的問題。比如閃屏問題:view的顯示隱藏是同步執行的,而fragment的hide、show是異步執行的,所以可能會碰到view隱藏了,而fragment的界面還沒顯示,導致閃屏。不過android也提供了FragmentManager#executePendingTransactions方法,強制同步執行。

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