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