fragment的两种切换方式(add,replace),fragment重叠问题

fragment的两种切换方式:

1.通过add方法添加fragment,再通过hide,show决定显示哪一个fragment,此方式是将fragment隐藏而非重建

2.replace:每次都是重新创建fragment

用一个demo展示如下:

首页activity的布局如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:background="#ffffff">

    <FrameLayout
        android:id="@+id/fragment_container"
        android:background="#dddddd"
        android:layout_weight="1"
        android:layout_width="match_parent"
        android:layout_height="0dp">
    </FrameLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:orientation="horizontal">
        
        <Button
            android:id="@+id/bt_msg"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:background="#ffffff"
            android:text="消息"/>

        <Button
            android:id="@+id/bt_contacts"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:background="#ffffff"
            android:text="联系人"/>
        <Button
            android:id="@+id/bt_news"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:background="#ffffff"
            android:text="动态"/>
    </LinearLayout>

</LinearLayout>

布局上方是一个帧布局用来存放fragment,屏幕下方是三个按钮,用来切换fragment

fragment的布局如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
>

    <TextView
        android:id="@+id/fragment_text"
        android:layout_centerInParent="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="text"/>
</RelativeLayout>

Fragment的代码如下:

通过静态方法newIntance初始化fragment并设置参数

public class TestFragment extends Fragment{

    private String mText;
    private TextView mTextview;

    public static TestFragment  newInstance(String text){
        TestFragment fg = new TestFragment();
        Bundle agrs = new Bundle();
        agrs.putString("text",text);
        fg.setArguments(agrs);
        return fg;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(getArguments() != null){
            mText = getArguments().getString("text");
        }
    }

    //    @SuppressLint("ValidFragment")
//    public TestFragment(String fName){
//        this.mText = fName;
//    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //return super.onCreateView(inflater, container, savedInstanceState);
        View view = LayoutInflater.from(getActivity()).inflate(R.layout.layout_frag,container,false);
        mTextview = (TextView)view.findViewById(R.id.fragment_text);
        mTextview.setText(mText);
        mTextview.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mTextview.setText("changed_"+mText);
            }
        });
        return view;
    }
}

fragment中的textview点击后文字内容会作出改变

首页MainActivity的代码如下:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    public static final  String TAG = "MainActivity";
    public static final String KEY_MSG_FRAGMENT = "msg_fragment";
    public static final String KEY_CONTACTS_FRAGMENT = "contacts_fragment";
    public static final String KEY_NEWS_FRAGMENT = "news_fragment";



    private Button bt_msg,bt_contacts,bt_news;
    private TestFragment fg_msg,fg_contacts,fg_news;
    //FragmentTransaction transaction;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bt_msg = (Button) findViewById(R.id.bt_msg);
        bt_contacts = (Button) findViewById(R.id.bt_contacts);
        bt_news = (Button) findViewById(R.id.bt_news);
        bt_msg.setOnClickListener(this);
        bt_contacts.setOnClickListener(this);
        bt_news.setOnClickListener(this);
       ShowMsgFragment();
    }


    private void ShowMsgFragment(){
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
         if(fg_msg == null){
             fg_msg = TestFragment.newInstance("msg");
             transaction.add(R.id.fragment_container,fg_msg);
         }
         
         hideAllFragement();
         transaction.show(fg_msg);

//        Log.d(TAG,"ShowMsgFragment ,fg_contacts is null");
//        if(fg_msg == null){
//            fg_msg = TestFragment.newInstance("msg");
//
//         }
//        transaction.replace(R.id.fragment_container,fg_msg);
//        Log.d(TAG,"ShowMsgFragment ,fg_contacts is null");
        transaction.commit();

    }

    private void ShowContactsFragment(){
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        if(fg_contacts == null){
            fg_contacts = TestFragment.newInstance("Contacts");
            transaction.add(R.id.fragment_container,fg_contacts);
        }


        hideAllFragement();
        transaction.show(fg_contacts);

//        if(fg_contacts == null){
//            Log.d(TAG,"ShowContactsFragment ,fg_contacts is null");
//            fg_contacts = TestFragment.newInstance("Contacts");
//
//        }
//
//        transaction.replace(R.id.fragment_container,fg_contacts);
        Log.d(TAG,"ShowContactsFragment ,fg_contacts is not null");

        transaction.commit();

    }

    private void ShowNewsFragment(){
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        if(fg_news == null){
            fg_news = TestFragment.newInstance("news");
            transaction.add(R.id.fragment_container,fg_news);
        }

        
        hideAllFragement();
        transaction.show(fg_news);

//        if(fg_news == null){
//            Log.d(TAG,"ShowNewsFragment ,fg_contacts is null");
//            fg_news = TestFragment.newInstance("news");
//
//        }
//        transaction.replace(R.id.fragment_container,fg_news);
//        Log.d(TAG,"ShowNewsFragment ,fg_contacts is  not null");
        transaction.commit();

    }

    public void hideAllFragement(){
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        if(fg_msg != null){
            transaction.hide(fg_msg);
        }
        if(fg_contacts != null){
            transaction.hide(fg_contacts);
        }
        if(fg_news != null){
            transaction.hide(fg_news);
        }

        transaction.commit();

    }


   

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.bt_msg:
                Log.d(TAG,"try call ShowMsgFragment");
                ShowMsgFragment();
                break;
            case R.id.bt_contacts:
                Log.d(TAG,"try call ShowContactsFragment");
                ShowContactsFragment();
                break;
            case R.id.bt_news:
                Log.d(TAG,"try call ShowNewsFragment");
                ShowNewsFragment();
                break;
            default:
                break;
        }
    }
}

以上例子,如果使用add方式,点击fragment里面的文字改变后,我们切换到其他fragment再切换回来时,发现他的文字是保持点击后改变的文字,而不是初始化的文字,说明我们切换回来的时候fragment没有被重新创建,而是保持之前的那个fragment。

如果我们用replace方式,点击fragment里面的文字改变后,切换到其他fragment后再切换回来,显示的文字为初始化的文字而不是改变后的文字,说明fragment进行了重建。

所以用add方式实现fragment的效果就是:切换fragment时不会重新创建,是什么样子切换回来还是什么样子;用replace的效果就是:切换fragment时每次都会重新创建初始化。

以上代码有个问题,横竖屏切换时会发生fragment重叠问题

原因如下:

出现这种问题的原因是:当我们旋转屏幕的时候,activity会被销毁并重新创建,并且在销毁之前执行了onSaveInstanceState(Bundle outState)这个方法。这个方法会保存activity的一些信息,其中就包括添加过的fragment,当activity被重新创建时,会初始化其中的变量,如fragment,也就导致了重叠的问题。

解决方法:

重写activity的onSaveInstanceState

@Override
protected void onSaveInstanceState(Bundle outState) {
    if(fg_msg != null){
        getSupportFragmentManager().putFragment(outState,KEY_MSG_FRAGMENT,fg_msg);
    }
    if(fg_contacts != null){
        getSupportFragmentManager().putFragment(outState,KEY_CONTACTS_FRAGMENT,fg_contacts);
    }
    if(fg_news != null){
        getSupportFragmentManager().putFragment(outState,KEY_NEWS_FRAGMENT,fg_news);
    }


    super.onSaveInstanceState(outState);
}

activity中onCreate中若savedInstanceState不为null则重建fragment:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    bt_msg = (Button) findViewById(R.id.bt_msg);
    bt_contacts = (Button) findViewById(R.id.bt_contacts);
    bt_news = (Button) findViewById(R.id.bt_news);
    bt_msg.setOnClickListener(this);
    bt_contacts.setOnClickListener(this);
    bt_news.setOnClickListener(this);

    //transaction = getSupportFragmentManager().beginTransaction();

    if(savedInstanceState != null){
        fg_msg = (TestFragment)getSupportFragmentManager().getFragment(savedInstanceState,KEY_MSG_FRAGMENT);
        fg_contacts = (TestFragment)getSupportFragmentManager().getFragment(savedInstanceState,KEY_CONTACTS_FRAGMENT);
        fg_news = (TestFragment)getSupportFragmentManager().getFragment(savedInstanceState,KEY_NEWS_FRAGMENT);
    }else{
        ShowMsgFragment();
    }




}

以上!

猜你喜欢

转载自blog.csdn.net/gz2012zb/article/details/81516700
今日推荐