天天看點

Fragment生命周期那些事

提筆犯怵,好久沒總結幹貨了,知識普遍都是碎片化的,記錄在雲筆記裡的比較多和雜。

最近項目用了BottomBar這個開源控件,狂拽炫酷吊炸天,視覺效果很好,還支援behavior,與NestedScrollView結合可以下拉隐藏,上滑顯示,上個圖。

Fragment生命周期那些事
Fragment生命周期那些事

以上都不是重點————分割———埋個雷–使用fragmentmanager管理Fragment的生命周期方法——

項目要使用fragment,fragment切換不需要滑動切換,當然可以不用viewpager了,也就不需要fragmentPagerAdapter了(純手打,如果單詞錯了勿怪),使用fragmentmanager+frameLayout動态顯示隐藏fragment,Activity代碼在後面,先讓我啰嗦完:

上一個項目使用的TabHost+FrameLayout+Fragment,對于Fragment的生命周期方法的執行有了一定的認識,在BaseFragment中做了詳細記錄,如下:

public abstract class BaseFragment extends Fragment {
    protected View rootView;
    public Context mContext;
    private boolean isCacheView=true;//是否緩存view

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mContext = context;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        isCacheView = setISCacheView();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        if (null!=rootView && isCacheView) {
            ViewGroup parent = (ViewGroup) rootView.getParent();
            if (parent != null) {
                parent.removeView(rootView);
            }
        }else {
            rootView = loadView(inflater);
        }
        bindView(rootView);
        return rootView;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        LogUtils.w(this.getClass().getSimpleName()+"onViewCreated");
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        //每次切換fragment都會調用
        LogUtils.w(this.getClass().getSimpleName()+"onActivityCreated");
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        LogUtils.w(this.getClass().getSimpleName()+"onDestroyView");
    }

    /**
     * 子類必須實作,載入自己的布局檔案
     * 如果緩存view,則隻會執行一次
     * @param inflater
     * @return
     */
    protected abstract View loadView(LayoutInflater inflater);

    /**
     * 子類必須實作,每次顯示fragment時更新view
     * 不管緩存與否,每次都執行
     * @param rootView
     */
    protected abstract void bindView(View rootView);

    public boolean setISCacheView(){
        return true;
    }

    public View getView(){
        return rootView;
    }

    /**
     * 在該方法中才可以使用mContext
     */
    public void loadData(){};

    /**
     * 修改titleBar标題
     * @param s
     */
    public void setActivityTitle(String s){
        if (null!=mContext){
            BaseActivity activity = (BaseActivity) mContext;
            activity.setTitle(s);
        }
    }

    public void showProgressBar(){
        if (null!=mContext){
            MainActivity activity = (MainActivity) mContext;
            activity.showProgress();
        }
    }

    public void hideProgressBar(){
        if (null!=mContext){
            MainActivity activity = (MainActivity) mContext;
            activity.hideProgress();
        }
    }
    public void increaseProgress(){
        if (null!=mContext){
            MainActivity activity = (MainActivity) mContext;
            activity.increateProgress();
        }
    }
}
           

目前項目無腦的把上個項目的基類拷貝過來,想當然的以為使用FragmentManager自己管理fragment,其生命周期方法也一樣,然後我在bindView(View rootView)方法裡改變MainActivity内toolBar的标題,實作切換fragment時,标題也切換。但是并沒有,切換fragment時,周期方法沒有如期回調。

這裡講的比我清楚http://blog.csdn.net/a910626/article/details/46016887不同的是我fragment使用了tag标記,添加前判斷是否存在,存在則彈出,不會重複建立。

public class MainActivity extends BaseActivity implements OnTabSelectListener {

    private FragmentManager fragmentManager;
    private ArrayList<String> fragmentTags;
    private int currIndex;
    private static final String CURR_INDEX = "currIndex";
    private BottomBar bottomBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        fragmentManager = getSupportFragmentManager();
        initToolBar();
        initData(savedInstanceState);
        initView();
    }

    private void initView() {
        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
        bottomBar = (BottomBar) findViewById(R.id.bottomBar);
        bottomBar.setOnTabSelectListener(this);
        bottomBar.setTabSelectionInterceptor(new TabSelectionInterceptor() {
            @Override
            public boolean shouldInterceptTabSelection(@IdRes int oldTabId, @IdRes int newTabId) {
                if (oldTabId == R.id.tab_favorites&&newTabId==R.id.tab_friends)
                    return true;
                return false;
            }
        });
        showFragment();
    }

    private void initData(Bundle savedInstanceState) {
        fragmentTags = new ArrayList<>(Arrays.asList("HomeFragment", "ImFragment", "InterestFragment"));
        currIndex = ;
        if(savedInstanceState != null) {
            currIndex = savedInstanceState.getInt(CURR_INDEX);
            hideSavedFragment();
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt(CURR_INDEX, currIndex);
    }

    private void hideSavedFragment() {
        Fragment fragment = fragmentManager.findFragmentByTag(fragmentTags.get(currIndex));
        if(fragment != null) {
            fragmentManager.beginTransaction().hide(fragment).commit();
        }
    }

    private void showFragment() {
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        Fragment fragment = fragmentManager.findFragmentByTag(fragmentTags.get(currIndex));
        if(fragment == null) {
            fragment = FragmentFactory.createFragment(currIndex);
        }
        for (int i = ; i < fragmentTags.size(); i++) {
            Fragment f = fragmentManager.findFragmentByTag(fragmentTags.get(i));
            if(f != null && f.isAdded()) {
                fragmentTransaction.hide(f);
            }
        }
        if (fragment.isAdded()) {
            fragmentTransaction.show(fragment);
        } else {
            fragmentTransaction.add(R.id.fragment_container, fragment, fragmentTags.get(currIndex));
        }
        fragmentTransaction.commitAllowingStateLoss();
        fragmentManager.executePendingTransactions();
    }

    @Override
    public String returnToolBarTitle() {
        return "測試";
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onTabSelected(@IdRes int tabId) {
        switch (tabId){
            case R.id.tab_favorites:
                currIndex = ;
                BottomBarTab nearby = bottomBar.getTabWithId(R.id.tab_nearby);
                nearby.setBadgeCount();
                break;
            case R.id.tab_nearby:
                currIndex = ;
                break;
            case R.id.tab_friends:
                currIndex = ;
                break;
            default:
                break;
        }
        showFragment();
    }
}
           

好人做到底,布局檔案

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.vmove.ecg.activity.MainActivity">
    <include
        layout="@layout/include_toolbar"/>
    <FrameLayout
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        android:background="@color/gray_white"
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
    <com.roughike.bottombar.BottomBar
        android:id="@+id/bottomBar"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:layout_gravity="bottom"
        app:bb_behavior="shy|shifting"
        app:bb_tabXmlResource="@xml/bottombar_tabs" />

</android.support.design.widget.CoordinatorLayout>
           

toolbar的布局懶得貼了,BaseActivity相信大家都有,裡面有個ActivityManager,儲存Activity的List。

總結一下,不管使用那種結構來顯示fragment,其本質都是使用fragmentmanager管理fragment,隻是有些現成的工具,比如TabHost、FragmentPagerAdapter内部使用fragmentmanager幫你管理了,使生命周期方法與Activity的同步,如果要自己寫,也無可厚非。君子性非異也,善假于物也。

繼續閱讀