在上一篇主要讲解了fragment的一些基础用法,有兴趣的同学可以看看http://blog.csdn.net/qq_27970997/article/details/70036940。那么这一篇主要讲解在使用fragment中的一些注意事项。
注意一:fragment回退栈的问题。
如何实现回退栈,回退栈有什么作用呢?首先实现回退栈很简单,只需要在进行commit()之前添加addToBackStack(String)
,一般情况下String设置为null就可以。在上一篇我们讲到,当使用replace来进行fragment的切换的时候,前一个fragment的实例就会被销毁,那么如果我不想销毁实例的话有什么解决方法吗?当然有,你可以使用hide()和show()方法,他可以保证你的fragment的实例和视图不会被销毁。但是,如果我不想销毁实例但是我想重新加载视图的话怎么办呢?那就要用到我们的回退栈了。回退栈就是保留fragment的实例,但是会重新绘制fragment的视图。和detach()的作用是一样的。
因为所有的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使用过程中的一些注意事项,欢迎大家留言。
