fragment

Posted csdn用户R

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了fragment相关的知识,希望对你有一定的参考价值。

1、概述

首先我们简单回顾一下,相信大家对Fragment的都不陌生,对于Fragment的使用,一方面Activity需要在布局中为Fragment安排位置,另一方面需要管理好Fragment的生命周期。Activity中有个FragmentManager,其内部维护fragment队列,以及fragment事务的回退栈。

一般情况下,我们在Activity里面会这么添加Fragment:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public  class  MainActivity  extends  FragmentActivity         private  ContentFragment mContentFragment  ;         @Override       protected  void  onCreate(Bundle savedInstanceState)                   super .onCreate(savedInstanceState);             setContentView(R.layout.activity_main);               FragmentManager fm = getSupportFragmentManager();             mContentFragment = (ContentFragment) fm.findFragmentById(R.id.id_fragment_container);               if (mContentFragment ==  null  )                               mContentFragment =  new  ContentFragment();                   fm.beginTransaction().add(R.id.id_fragment_container,mContentFragment).commit();                      

针对上面代码,问两个问题:

1、为什么需要判null呢?

主要是因为,当Activity因为配置发生改变(屏幕旋转)或者内存不足被系统杀死,造成重新创建时,我们的fragment会被保存下来,但是会创建新的FragmentManager,新的FragmentManager会首先会去获取保存下来的fragment队列,重建fragment队列,从而恢复之前的状态。

2、add(R.id.id_fragment_container,mContentFragment)中的布局的id有何作用?

一方面呢,是告知FragmentManager,此fragment的位置;另一方面是此fragment的唯一标识;就像我们上面通过fm.findFragmentById(R.id.id_fragment_container)查找~~

好了,简单回顾了一下基本用法,具体的还请参考上面的博客或者其他资料,接下来,介绍一些使用的意见~~

2、Fragment Arguments

下面描述一个简单的场景,比如我们某个按钮触发Activity跳转,需要通过Intent传递参数到目标Activity的Fragment中,那么此Fragment如何获取当前的Intent的值呢?

有哥们会说,这个简单?看我的代码(问题代码):

1 2 3 4 5 6 7 8 9 10 11 12 13 14 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);         

我们直接在Fragment的onCreate中,拿到宿主Activty,宿主Activity中肯定能通过getIntent拿到Intent,然后通过get方法,随意拿参数~~

这么写,功能上是实现了,但是呢?存在一个大问题:我们用Fragment的一个很大的原因,就是为了复用。你这么写,相当于这个Fragment已经完全和当前这个宿主Activity绑定了,复用直接废了~~~所以呢?我们换种方式,推荐使用arguments来创建Fragment。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 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间的解耦。当然了这里需要注意:

setArguments方法必须在fragment创建以后,添加给Activity前完成。千万不要,首先调用了add,然后设置arguments。

3、Fragment的startActivityForResult

依旧是一个简单的场景:两个Fragment,一个展示文章列表的Fragment(叫做ListTitleFragment),一个显示详细信息的Fragment(叫做:ContentFragment),当然了,这两个Fragment都有其宿主Activity。

现在,我们点击列表Fragment中的列表项,传入相应的参数,去详细信息的Fragment展示详细的信息,在详细信息页面,用户可以进行点评,当用户点击back以后,我们以往点评结果显示在列表的Fragment对于的列表项中;

也就是说,我们点击跳转到对应Activity的Fragment中,并且希望它能够返回参数,那么我们肯定是使用Fragment.startActivityForResult ;

在Fragment中存在startActivityForResult()以及onActivityResult()方法,但是呢,没有setResult()方法,用于设置返回的intent,这样我们就需要通过调用getActivity().setResult(ListTitleFragment.REQUEST_DETAIL, intent);。

详细代码:

ListTitleFragment

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public  class  ListTitleFragment  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  void  onActivityCreated(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)                     mCurrentPos = position ;              Intent intent =  new  Intent(getActivity(),ContentActivity. class );              intent.putExtra(ContentFragment.ARGUMENT, mTitles.get(position));              startActivityForResult(intent, REQUEST_DETAIL);                 @Override        public  void  onActivityResult( int  requestCode,  int  resultCode, Intent data)                     Log.e( "TAG" "onActivityResult" );              super .onActivityResult(requestCode, resultCode, data);              if (requestCode == REQUEST_DETAIL)                                  mTitles.set(mCurrentPos, mTitles.get(mCurrentPos)+ " -- " +data.getStringExtra(ContentFragment.RESPONSE));                     mAdapter.notifyDataSetChanged();                    

ContentFragment

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public  class  ContentFragment  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(ListTitleFragment.REQUEST_DETAIL, intent);                               public  static  ContentFragment newInstance(String argument)                     Bundle bundle =  new  Bundle();              bundle.putString(ARGUMENT, argument);              ContentFragment contentFragment =  new  ContentFragment();              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;       

贴出了两个Fragment的代码,可以看到我们在ListTitleFragment.onListItemClick,使用startActivityForResult()跳转到目标Activity,在目标Activity的Fragment(ContentFragment)中获取参数,然后调用getActivity().setResult(ListTitleFragment.REQUEST_DETAIL, intent);进行设置返回的数据;最后在ListTitleFragment.onActivityResult()拿到返回的数据进行回显;

为大家以后在遇到类似问题时,提供了解决方案;也说明了一个问题:fragment能够从Activity中接收返回结果,但是其自设无法产生返回结果,只有Activity拥有返回结果。

接下来我要贴一下,这两个Fragment的宿主Activity:

ListTitleActivity

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public  class  ListTitleActivity  extends  FragmentActivity          private  ListTitleFragment mListFragment;          @Override        protected  void  onCreate(Bundle savedInstanceState)                     super .onCreate(savedInstanceState);              setContentView(R.layout.activity_single_fragment);                FragmentManager fm = getSupportFragmentManager();              mListFragment = (ListTitleFragment) fm.findFragmentById(R.id.id_fragment_container);                if (mListFragment ==  null  )                                  mListFragment =  new  ListTitleFragment();                     fm.beginTransaction().add(R.id.id_fragment_container,mListFragment).commit();                      

ContentActivity:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public  class  ContentActivity  extends  FragmentActivity          private  ContentFragment mContentFragment;          @Override        protected  void  onCreate(Bundle savedInstanceState)                      super .onCreate(savedInstanceState);               setContentView(R.layout.activity_single_fragment);                 FragmentManager fm = getSupportFragmentManager();               mContentFragment = (ContentFragment) fm.findFragmentById(R.id.id_fragment_container);                 if (mContentFragment ==  null  )                                    String title = getIntent().getStringExtra(ContentFragment.ARGUMENT);                      mContentFragment = ContentFragment.newInstance(title);                      fm.beginTransaction().add(R.id.id_fragment_container,mContentFragment).commit();                        

有没有发现两个Activity中的代码极其的类似,且使用了同一个布局文件:

activity_single_fragment.xml

1 2 3 4 5 6 7 8 < RelativeLayout  xmlns:android = "http://schemas.android.com/apk/res/android"        xmlns:tools = "http://schemas.android.com/tools"        android:layout_width = "match_parent"        android:layout_height = "match_parent"        android:id = "@+id/id_fragment_container" >   </ RelativeLayout >

为什么要贴这Acticity的代码呢?因为我们项目中,如果原则上使用Fragment,会发现大量类似的代码,那么我们就可以抽象一个Activity出来,托管我们的Single Fragment。

详细见下一节。

4、SingleFragmentActivity

于是抽象出来的Activity的代码为:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package  com.example.demo_zhy_23_fragments;   import  android.os.Bundle; import  android.support.v4.app.Fragment; import  android.support.v4.app.FragmentActivity; import  android.support.v4.app.FragmentManager;   public  abstract  class  SingleFragmentActivity  extends  FragmentActivity        protected  abstract  Fragment createFragment();          @Override        protected  void  onCreate(Bundle savedInstanceState)                       super .onCreate(savedInstanceState);              setContentView(R.layout.activity_single_fragment);                FragmentManager fm = getSupportFragmentManager();              Fragment fragment =fm.findFragmentById(R.id.id_fragment_container);                if (fragment ==  null  )                                 fragment = createFragment() ;                      fm.beginTransaction().add(R.id.id_fragment_container,fragment).commit();                      

那么,有了这个SingleFragmentActivity,我们的ContentActivity和ListTitleActivity也能大变身了~

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package  com.example.demo_zhy_23_fragments;   import  android.support.v4.app.Fragment;   public  class  ContentActivity  extends  SingleFragmentActivity        private  ContentFragment mContentFragment;          @Override        protected  Fragment createFragment()                      String title = getIntent().getStringExtra(ContentFragment.ARGUMENT);                 mContentFragment = ContentFragment.newInstance(title);               return

以上是关于fragment的主要内容,如果未能解决你的问题,请参考以下文章

Fragment总结

Android:Fragment

Fragment 使用详解

创建Fragment和传递数值

Android Fragment使用 嵌套Fragments (Nested Fragments) 的使用及常见错误

Android Fragment使用 嵌套Fragments (Nested Fragments) 的使用及常见错误

(c)2006-2024 SYSTEM All Rights Reserved IT常识