在上一篇主要讲解了fragment的一些基础用法,有兴趣的同学可以看看http://blog.youkuaiyun.com/qq_27970997/article/details/70036940。那么这一篇主要讲解在使用fragment中的一些注意事项。
注意一:fragment回退栈的问题。
如何实现回退栈,回退栈有什么作用呢?首先实现回退栈很简单,只需要在进行commit()之前添加addToBackStack(String)
,一般情况下String设置为null就可以。在上一篇我们讲到,当使用replace来进行fragment的切换的时候,前一个fragment的实例就会被销毁,那么如果我不想销毁实例的话有什么解决方法吗?当然有,你可以使用hide()和show()方法,他可以保证你的fragment的实例和视图不会被销毁。但是,如果我不想销毁实例但是我想重新加载视图的话怎么办呢?那就要用到我们的回退栈了。回退栈就是保留fragment的实例,但是会重新绘制fragment的视图。和detach()的作用是一样的。
注意二: Fragment与Activity通信
因为所有的Fragment都是依附于Activity的,所以通信起来并不复杂,大概归纳为:
a、如果你Activity中包含自己管理的Fragment的引用,可以通过引用直接访问所有的Fragment的public方法
b、如果Activity中未保存任何Fragment的引用,那么没关系,每个Fragment都有一个唯一的TAG或者ID,可以通过getFragmentManager.findFragmentByTag()或者findFragmentById()获得任何Fragment实例,然后进行操作。当然,你需要提前为fragment设置TAG或者ID;
c、在Fragment中可以通过getActivity得到当前绑定的Activity的实例,然后进行操作。
注:如果在Fragment中需要Context,可以通过调用getActivity(),如果该Context需要在Activity被销毁后还存在,则使用getActivity().getApplicationContext()。
注意三:Fragment Argument的使用
如何高效的实例化fragment
public class ContentFragment extends Fragment{
private String mArgument;
public static final String ARGUMENT = "argument";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// mArgument = getActivity().getIntent().getStringExtra(ARGUMENT);
Bundle bundle = getArguments();
if (bundle != null)
mArgument = bundle.getString(ARGUMENT);
}
/**
* 传入需要的参数,设置给arguments
* @param argument
* @return
*/
public static ContentFragment newInstance(String argument) {
Bundle bundle = new Bundle();
bundle.putString(ARGUMENT, argument);
ContentFragment contentFragment = new ContentFragment();
contentFragment.setArguments(bundle);
return contentFragment;
}
给Fragment添加newInstance方法,将需要的参数传入,设置到bundle中,然后setArguments(bundle),最后在onCreate中进行获取;这样就完成了Fragment和Activity间的解耦.
注意四:Fragment的startActivityForResult(MainActivity包含TestFragment,SecondActivity包含BlankFragment)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager fm = getSupportFragmentManager();
TestFragment mListFragment = (TestFragment) fm.findFragmentById(R.id.id_fragment_container);
if(mListFragment == null ) {
mListFragment = new TestFragment();
fm.beginTransaction().add(R.id.id_fragment_container,mListFragment).commit();
}
}
首先在MainActivity里面加载TestFragment,需要注意的是必须对TestFragment进行非空验证,以确保唯一性。
public class TestFragment extends ListFragment {
public static final int REQUEST_DETAIL = 0x110;
private List<String> mTitles = Arrays.asList("hello","World","android");
private int mCurrentPos;
private ArrayAdapter<String> mAdapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_test, container, false);
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setListAdapter(mAdapter = new ArrayAdapter<String>(getActivity(),android.R.layout.simple_list_item_1,mTitles));
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
mCurrentPos = position;
Intent intent = new Intent(getActivity(), SecondActivity.class);
intent.putExtra(BlankFragment.ARGUMENT, mTitles.get(position));
startActivityForResult(intent,REQUEST_DETAIL);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_DETAIL){
mTitles.set(mCurrentPos, mTitles.get(mCurrentPos)+" -- "+data.getStringExtra(BlankFragment.RESPONSE));
mAdapter.notifyDataSetChanged();
}
}
}
在TestFragment里面需要注意:在进行跳转的时候是跳转到目标所属的Activity,而不是直接跳转到对应的Fragment
。其他的写法和Activity的一样
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
FragmentManager fm = getSupportFragmentManager();
BlankFragment mContentFragment = (BlankFragment) fm.findFragmentById(R.id.id_fragment_container);
if(mContentFragment == null ) {
String title = getIntent().getStringExtra(BlankFragment.ARGUMENT);
mContentFragment = BlankFragment.newInstance(title);
fm.beginTransaction().add(R.id.id_fragment_container,mContentFragment).commit();
}
}
}
在SecondActivity里面加载BlankFragment,需要注意的是必须对BlankFragment进行非空验证,以确保唯一性。
public class BlankFragment extends Fragment {
private String mArgument;
public static final String ARGUMENT = "argument";
public static final String RESPONSE = "response";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getArguments();
if (bundle != null) {
mArgument = bundle.getString(ARGUMENT);
Intent intent = new Intent();
intent.putExtra(RESPONSE, "good");
getActivity().setResult(TestFragment.REQUEST_DETAIL, intent);
}
}
public static BlankFragment newInstance(String argument) {
Bundle bundle = new Bundle();
bundle.putString(ARGUMENT, argument);
BlankFragment contentFragment = new BlankFragment();
contentFragment.setArguments(bundle);
return contentFragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Random random = new Random();
TextView tv = new TextView(getActivity());
tv.setText(mArgument);
tv.setGravity(Gravity.CENTER);
tv.setBackgroundColor(Color.argb(random.nextInt(100),
random.nextInt(255), random.nextInt(255), random.nextInt(255)));
return tv;
}
}
注意onCreate()方法的写法
注意五:同一个Activity里面的fragment的数据传递(FragmentA弹出FragmentB(FragmentB为DialogFragment),FragmentB弹框消失时传递数据给FragmentA)
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Random random = new Random();
TextView tv = new TextView(getActivity());
tv.setText(mArgument);
tv.setGravity(Gravity.CENTER);
tv.setBackgroundColor(Color.argb(random.nextInt(100),
random.nextInt(255), random.nextInt(255), random.nextInt(255)));
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EvaluateDialog dialog = new EvaluateDialog();
//注意setTargetFragment
dialog.setTargetFragment(BlankFragment.this, REQUEST_EVALUATE);
dialog.show(getFragmentManager(), EVALUATE_DIALOG);
}
});
return tv;
}
//接收返回回来的数据
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_EVALUATE) {
String evaluate = data
.getStringExtra(EvaluateDialog.RESPONSE_EVALUATE);
Toast.makeText(getActivity(), evaluate, Toast.LENGTH_SHORT).show();
}
}
注意dialog.setTargetFragment(Fragment fragment,in
t requestCode);这个方法,一般就是用于当前fragment由别的fragment启动,在完成操作后返回数据的
// 设置返回数据
protected void setResult(int which) {
// 判断是否设置了targetFragment
if (getTargetFragment() == null)
return;
Intent intent = new Intent();
intent.putExtra(RESPONSE_EVALUATE, mEvaluteVals[which]);
getTargetFragment().onActivityResult(BlankFragment.REQUEST_EVALUATE,
Activity.RESULT_OK, intent);
}
注意六:FragmentPagerAdapter和FragmentStatePagerAdapter
那么这两个类有何区别呢?
主要区别就在与对于fragment是否销毁,下面细说:
FragmentPagerAdapter:对于不再需要的fragment,选择调用detach方法,仅销毁视图,并不会销毁fragment实例。
FragmentStatePagerAdapter:会销毁不再需要的fragment,当当前事务提交以后,会彻底的将fragmeng从当前Activity的FragmentManager中移除,state标明,销毁时,会将其onSaveInstanceState(Bundle outState)中的bundle信息保存下来,当用户切换回来,可以通过该bundle恢复生成新的fragment,也就是说,你可以在onSaveInstanceState(Bundle outState)方法中保存一些数据,在onCreate中进行恢复创建。
如上所说,使用FragmentStatePagerAdapter当然更省内存,但是销毁新建也是需要时间的。一般情况下,如果你是制作主页面,就3、4个Tab,那么可以选择使用FragmentPagerAdapter,如果你是用于ViewPager展示数量特别多的条目时,那么建议使用FragmentStatePagerAdapter。
以上就是fragment使用过程中的一些注意事项,欢迎大家留言。