Android应用开发中Fragment间通信的实现教程
为了重用FragmentUI组件,在设计中你应该通过定义每一个fragemnt自己的layout和行为,让fragment的自包含和模块化。一旦你定义了这些可重用的Fragment,你可以通过Activity将它们关联起来并通过程序的逻辑代码将他们连接起来以实现整体组合的UI。
你会经常想要一个fragment与另一个fragment通信,例如基于用户事件改变fragment中的内容。所有fragment质检单额通信都是通过Activity关联起来的。两个fragment之间不应该直接进行通信。
定义接口
为了允许fragment和它的Activity通信,你应该fragment类中定义一个接口并在Activity中实现它。Fragment在onAttach()回调函数中获取接口的具体实现的对象。后面,fragment就可以调用接口中的方法实现与Activity的通信。
下面是一个Fragment一Activity通信的例子:
//用来存放fragment的Activtiy必须实现这个接口 publicinterfaceOnHeadlineSelectedListener{ publicvoidonArticleSelected(intposition); } @Override publicvoidonAttach(Activityactivity){ super.onAttach(activity); //这是为了保证Activity容器实现了用以回调的接口。如果没有,它会抛出一个异常。 try{ mCallback=(OnHeadlineSelectedListener)activity; }catch(ClassCastExceptione){ thrownewClassCastException(activity.toString() +"mustimplementOnHeadlineSelectedListener"); } }
现在fragment可以通过使用实现了OnHeadlineSelectedListener接口的mCallback实例调用onArticleSelected()方法(或其他在接口中的方法)将消息传递给Activity。
例如下面在fragment中的方法将会在用户点击一个Listitem的时候被调用。这个fragment使用回调接口将时间传递给父Activtity。
@Override publicvoidonListItemClick(ListViewl,Viewv,intposition,longid){ //发送时间给Activity宿主 mCallback.onArticleSelected(position); }
实现接口
为了接收从fragment传递过来的事件回调,宿主Activity必须实现定义在fragment类中的接口。
例如,下面的activity实现了上个例子中的接口。
publicstaticclassMainActivityextendsActivity implementsHeadlinesFragment.OnHeadlineSelectedListener{ ... publicvoidonArticleSelected(intposition){ //用户选择了HeadlinesFragment中的头标题后 //做一些业务操作 } }
将消息传递给fragment
宿主Activity可以通过调用findFragmentById()方法获取Fragment实例,然后直接调用Fragment的公有方法,将消息传递给Fragment。
例如,想象一下,之前讲过的Activity可能包含有其他的fragment,而这些fragment通过上面的回调函数返回的接口动态地显示一些内容。这种情况下,Activity可以将回调函数中接收到信息传递给需要的fragment。
publicstaticclassMainActivityextendsActivity implementsHeadlinesFragment.OnHeadlineSelectedListener{ ... publicvoidonArticleSelected(intposition){ //用户选中HeadlinesFragment中的头标题后 //做一些必要的业务操作 ArticleFragmentarticleFrag=(ArticleFragment) getSupportFragmentManager().findFragmentById(R.id.article_fragment); if(articleFrag!=null){ //如果articlefrag不为空,那么我们在同时显示两个fragmnet的布局中... //调用ArticleFragment中的方法去更新它的内容 articleFrag.updateArticleView(position); }else{ //否则,我们就是在仅包含一个fragment的布局中并需要交换fragment... //创建fragment并给他一个跟选中的文章有关的参数 ArticleFragmentnewFragment=newArticleFragment(); Bundleargs=newBundle(); args.putInt(ArticleFragment.ARG_POSITION,position); newFragment.setArguments(args); FragmentTransactiontransaction=getSupportFragmentManager().beginTransaction(); //用这个fragment替换任何在fragment_container中的东西 //并添加事务到backstack中以便用户可以回退到之前的状态 transaction.replace(R.id.fragment_container,newFragment); transaction.addToBackStack(null); //提交事务 transaction.commit(); } } }
动态加载的Fragment通信
fragment之间永远不能通信都是通过他们所依附的Activity来通信的,通过接口回调的方式来通信
Activity--->Fragment:在activity中创建Bundle数据包,并调用fragment的setArguments(Bundlebundle)方法
fragment--->Activity:在fragment类中定义一个接口,并在他所属的activity中实现该接口,fragment在他的onAttach()方法执行期间捕获该接口的实现,然后就可以调用该接口方法,以便跟activity通信。
下面的代码实现了在一个Activity下有两个Fragment,在一个Fragment中输入值在另一个Fragment显示
publicclassMainActivityextendsActivityimplementsMyListener{ @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); FragmentManagermanager=getFragmentManager(); FragmentTransactionfragmentTransaction=manager.beginTransaction(); Fragment1fragment1=newFragment1(); fragmentTransaction.add(R.id.layout1,fragment1); fragmentTransaction.commit(); } //在mainActivity中实现MyListener接口并实现它未实现的方法,在该方法中传递数据 @Override publicvoidsend(Stringinfo){ Toast.makeText(this,"Activity成功接收"+info,0).show(); Fragment2fragment2=newFragment2(); Bundlebundle=newBundle(); bundle.putString("name",info); fragment2.setArguments(bundle); FragmentManagermanager=getFragmentManager(); FragmentTransactionfragmentTransaction=manager.beginTransaction(); //替换该Fragment fragmentTransaction.replace(R.id.layout2,fragment2,"fragment2"); fragmentTransaction.commit(); } }
上面的MainActivity布局就是添加两个Linearlayout,下面是创建两个Fragment,Fragment1的布局就是一个EditText一个Button,Fragment2的布局就是一个TextView。
publicclassFragment1extendsFragment{ EditTextet; Buttonenter; privateStringinfo; @Override publicvoidonAttach(Activityactivity){ listener=(MyListener)activity; super.onAttach(activity); } @Override publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer, BundlesavedInstanceState){ Viewview=inflater.inflate(R.layout.fragment1_lay,container,false); et=(EditText)view.findViewById(R.id.et); enter=(Button)view.findViewById(R.id.enter); enter.setOnClickListener(newOnClickListener(){ @Override publicvoidonClick(Viewv){ info=et.getText().toString(); listener.send(info); } }); returnview; } publicMyListenerlistener; //定义一个接口 publicinterfaceMyListener{ publicvoidsend(Stringinfo); } } publicclassFragment2extendsFragment{ @Override publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer, BundlesavedInstanceState){ Viewview=inflater.inflate(R.layout.fragment2_lay,container,false); TextViewtv=(TextView)view.findViewById(R.id.tv); tv.setText(getArguments().get("name")+"");//获取传递的值 Toast.makeText(getActivity(),"fragment"+getArguments().get("name")+"",0).show(); returnview; } }
静态加载的fragment通信
fragment可以调用getActivity()方法获取他所在的Activity
Activity可以调用FragmentManager的findFragmentById()或findFragmentByTag()方法获取Fragment
如果是静态加载的Fragmentn那么向Activity传递数据就很简单了,在MainActivity的onCreate方法中:
FragmentManagerfragmentManager=getFragmentManager(); Fragmentfragment=fragmentManager.findFragmentById(R.id.frag);//静态加载在Activity布局中设置的Fragment的ID MyFragmentfrag=(MyFragment)fragment; frag.setText1("fragment静态传值");
在Fragment类中设置它的get、set方法,
privateStringtext1; publicStringgetText1(){ returntext1; } publicvoidsetText1(Stringtext1){ this.text1=text1; }
下面直接调用就可以了:
Stringvalue=getText1();