本篇讲的是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;
}