Fragment 详解二

来源:互联网 发布:php实现pdf在线阅读 编辑:程序博客网 时间:2024/06/01 08:00

本篇讲的是Fragment数据的传递、onBackPress()的拦截、replace的坑

一. setArguments 传递

特点,第一次初始化的时候使用。 google官方推荐,值得拥有。
先看下如何使用的, 下面为创建的FragmentTwo
package com.example.stormxz.fragmenttwo;import android.os.Bundle;import android.support.annotation.Nullable;import android.support.v4.app.Fragment;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;/** * Created by stormxz on 2017/9/5. */public class FragmentTwo extends Fragment {    private TextView textView = null;    @Nullable    @Override    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {        View view = inflater.inflate(R.layout.fragment_second, container, false);        textView = view.findViewById(R.id.second_text);        String text = getArguments().getString("stormxz");     //通过key,将数据取出,并使用        textView.setText(text);        return view;    }    public static FragmentTwo newInstance(String text){        FragmentTwo fragmentTwo = new FragmentTwo();           Bundle bundle = new Bundle();     //通过bundle进行数据的存储        bundle.putString("stormxz", text);        fragmentTwo.setArguments(bundle);        return fragmentTwo;    }}

MainActivity.java    FragmentManager fragmentManager = getSupportFragmentManager();    FragmentTwo fragmentTwo = FragmentTwo.newInstance(text);    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();    fragmentTransaction.add(R.id.frame, fragmentTwo);    fragmentTransaction.commit();

疑问?为什么不直接使用FragmentTwo的构造方法进行数据传递呢?

正解:
当FragmentTwo 在旋转屏时,构造方法传递过来的数据不能保持,而setArguments的数据可以保持
跟着源码走:
1. FragmentActivity.java  onCreate()中  会对fragment进行重新创建
mFragments.restoreAllState(p, nc != null ? nc.fragments : null);   

2. FragmentController.java    restoreAllState过度一下
public void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) {
    mHost.mFragmentManager.restoreAllState(state, nonConfig);
}

3. FragmentManager.java   restoreAllState    Fragment的创建

Fragment f = fs.instantiate(mHost, mContainer, mParent, childNonConfig);

4. FragmentState.java
FragmentState 的构造方法获得之前的bundle
mArguments = in.readBundle();

instantiate
mInstance = Fragment.instantiate(context, mClassName, mArguments);

5. Fragment.java 
public static Fragment instantiate(Context context, String fname, @Nullable Bundle args) {        try {            Class<?> clazz = sClassMap.get(fname);            if (clazz == null) {                // Class not found in the cache, see if it's real, and try to add it                clazz = context.getClassLoader().loadClass(fname);                sClassMap.put(fname, clazz);            }            Fragment f = (Fragment)clazz.newInstance();            if (args != null) {                args.setClassLoader(f.getClass().getClassLoader());                f.setArguments(args);                                  //将对应的bundle设置到fragment中,待getArguments            }            return f;        }     }

二、 同一个Activity,不同容器

1. 在Activity中,通过findViewById,获得控件实例,再操作

2. 在Fragment中onActivityCreated中,通过getActivity().findViewById() 获得控件实例,再进行操作

3. 在各自fragment中使用,通过回调实现
思路: 在FragmentFirst中创建回调接口以及方法, 在fragmentFirst中调用; Activity 实现该接口,和方法,并进行其他操作即可
比如下面FragmentFirst:
package com.example.stormxz.fragmenttwo;import android.app.Activity;import android.os.Bundle;import android.support.annotation.Nullable;import android.support.v4.app.Fragment;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.Button;import android.widget.EditText;/** * Created by stormxz on 2017/9/5. */public class FragmentFirst extends Fragment {    private TextCallBack textCallBack = null;    private Button button = null;    private EditText editText = null;    public interface TextCallBack{                   //创建的接口,和方法        public void textCallBack(String text);    }    @Override    public void onAttach(Activity activity) {        super.onAttach(activity);        textCallBack = (TextCallBack) activity;     //初始化textCallBack实例    }    @Nullable    @Override    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {        View view = inflater.inflate(R.layout.fragment_first, container, false);        button = view.findViewById(R.id.button);        editText = view.findViewById(R.id.first_text);        button.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                textCallBack.textCallBack(editText.getText().toString());   //调用该方法,此时会在实现该接口的地方调用            }        });        return view;    }    @Override    public void onActivityCreated(@Nullable Bundle savedInstanceState) {        super.onActivityCreated(savedInstanceState);    }}

MainActivity.java
package com.example.stormxz.fragmenttwo;import android.support.v4.app.Fragment;import android.support.v4.app.FragmentManager;import android.support.v4.app.FragmentTransaction;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;/** * Created by stormxz on 2017/9/5. */                                                     //实现FragmentFirst中的接口public class MainActivity extends AppCompatActivity implements FragmentFirst.TextCallBack{    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        FragmentManager fragmentManager = getSupportFragmentManager();        FragmentFirst fragmentFirst = new FragmentFirst();        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();        fragmentTransaction.add(R.id.frame, fragmentFirst, "first");        fragmentTransaction.commit();    }//重写该方法,并处理相关事件。当FragmentFirst中调用textCallBack时,触发该方法。    对应的FragmentTwo和第一个一样,此时不写了。    @Override    public void textCallBack(String text) {        if (text != null) {            FragmentManager fragmentManager = getSupportFragmentManager();            FragmentTwo fragmentTwo = FragmentTwo.newInstance(text);            Fragment fragmentFirst = fragmentManager.findFragmentByTag("first");    //通过tag,取出栈中的FragmentFirst            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();            if (fragmentFirst != null){                fragmentTransaction.hide(fragmentFirst);         //隐藏了FragmentFirst            }            fragmentTransaction.add(R.id.frame1, fragmentTwo);            fragmentTransaction.commit();        }    }}

三、 如何拦截fragment的回退事件

fragment 本身就是一个控件,没有拦截onBackPress事件的功能。可以通过Activity的onBackPress事件进行调用fragment的自己写的onBackPress().
这里需将fragment的实例传递出去,或者在外部创建fragment实例都行。


FragmentThird.java中的操作
package com.example.stormxz.fragmenttwo;import android.app.Activity;import android.os.Bundle;import android.support.annotation.Nullable;import android.support.v4.app.Fragment;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;/** * Created by stormxz on 2017/9/12. */public class FragmentThrid extends Fragment {    private TextView textView = null;    private MyInstance myInstance = null;    public interface MyInstance{                //自定义接口和方法        public void setFragmentThird(FragmentThrid fragmentThird);    }    @Override    public void onAttach(Activity activity) {        super.onAttach(activity);        myInstance = (MyInstance) activity;    }    @Nullable    @Override    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {        View view = inflater.inflate(R.layout.fragment_third, container, false);        return view;    }    @Override    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {        super.onViewCreated(view, savedInstanceState);        textView = view.findViewById(R.id.thrid_text);        textView.setText("i am third fragment");    }    @Override    public void onActivityCreated(@Nullable Bundle savedInstanceState) {        super.onActivityCreated(savedInstanceState);        myInstance.setFragmentThird(this);         //将对象传递出去    }    public boolean onBackPress(){        textView.setText("就不给你退");        return false;    }}

MainActivity.java 中的操作
package com.example.stormxz.fragmenttwo;import android.os.Bundle;import android.support.v4.app.FragmentManager;import android.support.v4.app.FragmentTransaction;import android.support.v7.app.AppCompatActivity;/** * Created by stormxz  on 2017/9/12. */public class MainThridFragment extends AppCompatActivity implements FragmentThrid.MyInstance{    private FragmentThrid fragmentThridd = null;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        FragmentManager fragmentManager = getSupportFragmentManager();        FragmentThrid  fragmentThrid = new FragmentThrid();        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();        fragmentTransaction.add(R.id.frame, fragmentThrid, "third");        fragmentTransaction.commit();    }    //获得Fragmen对象    @Override    public void setFragmentThird(FragmentThrid fragmentThird) {        if (fragmentThird != null) {            fragmentThridd = fragmentThird;        }    }    //进行事件的拦截    @Override    public void onBackPressed() {        if (fragmentThridd == null || fragmentThridd.onBackPress()) {            super.onBackPressed();        }    }}

四、repalce的一个问题

在使用replace之后,会将栈中前面的fragment的视图销毁,那么如何对之前的视图数据进行保存呢?
1. 通过变量,将数据保存,比如string
2. 给控件添加id即可

3. 将视图保留 

   public View getPersistentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState, int layout) {      if (rootView == null) {          // Inflate the layout for this fragment          rootView = inflater.inflate(layout, container,false);      } else {          ((ViewGroup) rootView.getParent()).removeView(rootView);      }      return rootView;  } 

原创粉丝点击