概述
Activity和Fragment是Android开发中经常需要用到的,但是在使用的过程中有些细节性的问题很多人没有在意,今天我们就去带大家看看几个比较值得研究的地方。
实现
1.replace进行Fragment的切换,这样会重新实例化当前fragment。重新加载一遍数据,非常消耗性能和用户的数据流量,如果不是项目需求的话,不建议采用这种方式。
public void switchFragment(Fragment targetFragment){
if(targetFragment == null) return;
getSupportFragmentManager().beginTransaction()
.replace(R.id.fl_content, targetFragment).commit();
}
2.add,hide,show切换fragment,不会重新实例化当前fragment
从图中我们可以看出,每个Fragment确实只是初始化了一次,代码如下
public class MainActivity extends FragmentActivity implements RadioGroup.OnCheckedChangeListener{
private Fragment currentFragment;//当前fragment
private FragmentOne fragmentOne;
private FragmentTwo fragmentTwo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RadioGroup radioGroup = (RadioGroup) findViewById(R.id.rg_bottom);
radioGroup.setOnCheckedChangeListener(this);
currentFragment = new FragmentOne();
//默认选中第一个Fragment
((RadioButton)radioGroup.getChildAt(0)).setChecked(true);
}
public void start(View view){
startActivity(new Intent(this,SecondActivity.class));
}
@Override
public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {
switch (checkedId){
case R.id.rb_first:
if(fragmentOne == null) {
fragmentOne = new FragmentOne();
}
switchFragment(fragmentOne);
break;
case R.id.rb_second:
if(fragmentTwo == null) {
fragmentTwo = new FragmentTwo();
}
switchFragment(fragmentTwo);
break;
}
}
public void switchFragment(Fragment targetFragment){
if(targetFragment!=null){
if(targetFragment == currentFragment){
return;
}
}
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
if (!targetFragment.isAdded()) {
transaction
.hide(currentFragment)
.add(R.id.fl_content, targetFragment)
.commit();
System.out.println("还没添加呢");
} else {
transaction
.hide(currentFragment)
.show(targetFragment)
.commit();
System.out.println("添加了( ⊙o⊙ )哇");
}
currentFragment = targetFragment;
}
}
3.加入有这样的需求,每次切换fragment时都需要做一些操作,那么这时候我们就需要监听fragment的切换了。这时候可以利用onHiddenChanged,两个fragment进行切换的时候,会同时触发这两个fragment的onHiddenChanged方法。
4.Fragment重叠问题
前提:使用hide,show方法切换fragment
原因:当前Activity销毁的时候,系统会保存Fragment的状态,下次新的Activity重建的时候,无法控制当前fragment,导致fragment无法隐藏,重叠在一起
解决办法:重新当前Activity的onSaveInstanceState方法,注释掉保存状态的代码
@Override
protected void onSaveInstanceState(Bundle outState) {
//super.onSaveInstanceState(outState);
}
这时候再去切换就没有问题了。
5.底部Tab状态显示错误
当我们切换到非第一个按钮时,重新销毁当前Activity,此时按钮又会回到第一个选中。
解决办法,在onSaveInstanceState保存当前按钮选中的位置,在Activity重建是从参数中取书这个值,重新为对应位置的按钮设置选中
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RadioGroup radioGroup = (RadioGroup) findViewById(R.id.rg_bottom);
radioGroup.setOnCheckedChangeListener(this);
currentFragment = new FragmentOne();
//默认选中第一个Fragment
((RadioButton)radioGroup.getChildAt(0)).setChecked(true);
//恢复按钮状态
if(savedInstanceState!=null){
index = Integer.parseInt(savedInstanceState.getString("index"));
((RadioButton)radioGroup.getChildAt(index)).setChecked(true);
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
//保存按钮索引位置
outState.putString("index",String.valueOf(index));
}
6.setArgument方法的使用
众所周知,我们用setArgument来传递参数,如果使用不当,很可能发生下面的问题
原因:java.lang.IllegalStateException: Fragment already active异常主要是使用setArguments()传递参数导致的。
在 Fragment 没有被添加到 FragmentManager 之前,我们可以通过 Fragment.setArguments() 来设置参数,并在 Fragment 中,使用 getArguments() 来取得参数。在 Fragment 被添加到 FragmentManager 后,一旦被使用,我们再次调用 setArguments() 将会导致 java.lang.IllegalStateException: Fragment already active 异常。
正确使用方法
public class FragmentOne extends Fragment{
private TextView textView;
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_one, null);
textView = (TextView) view.findViewById(R.id.textview);
if(getArguments()!=null){
//取出保存的值
textView.setText(getArguments().getString("name"));
}
return view;
}
public static FragmentOne newInstance(String text){
FragmentOne fragmentOne = new FragmentOne();
Bundle bundle = new Bundle();
bundle.putString("name", text);
//fragment保存参数,传入一个Bundle对象
fragmentOne.setArguments(bundle);
return fragmentOne;
}
}