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(); } }
以上!