Fragment 详解二

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

猜你喜欢

转载自blog.csdn.net/weixin_39158738/article/details/77946427