Android溫故知新之Fragment篇(二) Fragment數據傳遞及回退棧

通過上一章,我們對Fragment的生命週期有了詳細的瞭解,這一章我們來繼續看Fragment的其他內容。


本章主要內容如下:

1、動態創建Fragment與FragmentManager
2、Fragment與Activity的交互
3、Fragment回退棧


一、動態創建Fragment與FragmentManager

上一章最後,我們已經實現了一個通過FragmentManager、FragmentTransaction動態創建Fragment的例子,關鍵代碼如下:

myFragment = new MyFragment();  
android.support.v4.app.FragmentTransaction ft = getSupportFragmentManager().beginTransaction();  
ft.add(myFragment,"aaa");  
ft.commit();
首先創建了一個Fragment的實例,接着調用getSupportFragmentManager()(如果使用app包下的Fragment使用getFragmentManager())獲取到FragmentManager對象,該對象負責維護Fragment列表及回退棧管理,然後通過FragmentManager的beginTransaction()方法獲取FragmentTransaction對象,FragmentTransaction對象是對單個Fragment添加、隱藏、移除、替換以及將Fragment添加進回退棧等操作。

FragmentTransaction完成對Fragment的操作後需要通過commit()方法提交才能生效

並且一個FragmentTransaction對象無法執行兩次commit(),每次需要commit()都要調用FragmentManager的beginTransaction()方法獲取FragmentTransaction對象。


二、Fragment與Activity的交互

大家都知道Activity之間一般時通過Intent攜帶Bundle實現數據的交互,但Activity向Fragment發送數據無法使用Intent,並且不建議使用帶參數的構造方法,因爲Activity重啓後會重新調用Fragment無參數的構造方法,導致我們傳遞的數據丟失,這裏我們就需要使用Android SDK爲我們提供的setArguments(Bundle args)方法來解決這個問題。該方法原型如下:

    public void setArguments(Bundle args) {
        if (mIndex >= 0 && isStateSaved()) {
            throw new IllegalStateException("Fragment already active and state has been saved");
        }
        mArguments = args;
    }

如果在Activity中調用該方法,就可以將Activity的數據通過Bundle發送給Fragment了,但是有一點需要注意,該方法的註釋上有一句This method cannot be called if the fragment is added to a FragmentManager,就是說這個方法要在FragmentTransaction.commit()之前調用。這與方法回調時機有關,fragment的創建涉及子線程,FragmentTransaction.commit()之前調用該方法能保證在Fragment的生命週期回調中能獲取到傳遞的參數。

實例化Fragment常用的一種寫法:

  public static MyFragment getInstance(Bundle bundle){
        MyFragment fragment = new MyFragment();
        fragment.setArguments(bundle);
        return fragment;
    }

fragment.setArguments(bundle);這個方法中將bundle設爲Fragment的成員變量,並且對其數據進行了保存,在Activity重建後,也能獲取到該數據,避免了數據丟失的情況。

三、Fragment回退棧

Fragment回退棧由FragmentManager負責出棧及監聽,FragmentTransaction調用addToBackStack方法負責Fragment入棧,測試代碼如下:

activity.onCreate

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);

        next = findViewById(R.id.btn_next);
        previous = findViewById(R.id.btn_previous);
        mFrame = findViewById(R.id.frame);

        mManager = getSupportFragmentManager();

        if(savedInstanceState == null) {
            FragmentTransaction mTransaction = mManager.beginTransaction();
            Bundle b = new Bundle();
            b.putString("str", "fragment");
            MyFragment myFragment = MyFragment.getInstance(b);
            //替換
            mTransaction.replace(R.id.frame,myFragment);
            mTransaction.commit();
            Log.d("commit", "commit結束");
        }
        next.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                FragmentTransaction mTransaction = mManager.beginTransaction();
                i++;
                Bundle b = new Bundle();
                b.putString("str", "fragment" + i);
                MyFragment myFragment = MyFragment.getInstance(b);
                //替換
                mTransaction.replace(R.id.frame,myFragment);
                //入棧
                mTransaction.addToBackStack(null);
                mTransaction.commit();
            }
        });
        previous.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //回退棧中是否存在Fragment實例
                if(mManager.getBackStackEntryCount() > 0)
                    i--;
                //出棧
                mManager.popBackStack();
            }
        });
    }

fragment.java

public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Bundle b = getArguments();
        String str = "";
        if(b != null){
            str = b.getString("str");
        }
        View view = inflater.inflate(R.layout.fragment_my,container,false);
        TextView text = view.findViewById(R.id.tv);
        text.setText(str);
        return view;
    }
    public static MyFragment getInstance(Bundle bundle){
        MyFragment fragment = new MyFragment();
        fragment.setArguments(bundle);
        return fragment;
    }
每次點擊next按鈕,計數變量都會自增1,將"fragment" + i合併後的字符串傳遞給新建的Fragment用於顯示,並將該Fragment加入回退棧,每次點擊previous按鈕或back鍵都會執行出棧操作。

運行結果如下:


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