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键都会执行出栈操作。

运行结果如下:


猜你喜欢

转载自blog.csdn.net/L_Scag/article/details/80353739