为了可以复用一个fragment,所以在定义fragment的时候,要把它定义为一个完全独立和模块化,它有它自己的layout和行为。当你定义好了这些可复用的fragment,可以把他们和activity相关联,在应用的逻辑基础上把这些fragment相互关联,从而组成一个完整的UI。
很多时候,我们需要fragment直接进行通信,比方说,根据用户的动作交换内容。所有的fragment直接的通信,都是利用与之关联的activity.2个fragment永远不可能直接通信。
定义接口
要允许fragment和它所在的activity通信,你可以在Fragment类里面定义一个接口,然后在activity里面实现这个接口。Fragment会在它的生命周期函数:onAttach()期间捕获这个接口的实现。然后就可以调用这个接口的方法和activity通信了。
下面是一个通信的例子:
1 public class HeadlinesFragment extends ListFragment { 2 OnHeadlineSelectedListener mCallback; 3 4 // Container Activity must implement this interface 5 public interface OnHeadlineSelectedListener { 6 public void onArticleSelected(int position); 7 } 8 9 @Override 10 public void onAttach(Activity activity) { 11 super.onAttach(activity); 12 13 // This makes sure that the container activity has implemented 14 // the callback interface. If not, it throws an exception 15 try { 16 mCallback = (OnHeadlineSelectedListener) activity; 17 } catch (ClassCastException e) { 18 throw new ClassCastException(activity.toString() 19 + " must implement OnHeadlineSelectedListener"); 20 } 21 } 22 23 ... 24 }
然后,这个fragment就可以利用OnHeadlineSelectedListener这个接口的实例
mCallback,来调用
onArticleSelected()(或者是其他接口里面的方法)来给activity发送信息。
比方说,下面的例子就是,当用户点击一个list里面的一项的时候,fragment里面接口函数被调用,利用这个接口里面的函数,给父activity发送消息。
1 @Override 2 public void onListItemClick(ListView l, View v, int position, long id) { 3 // Send the event to the host activity 4 mCallback.onArticleSelected(position); 5 }
实现接口
为了处理从fragment来的回调函数传来的消息,那么要处理这个回调消息的activity,也就是这个fragment所在的主体activity,必须实现在fragment里面定义的接口。
比方说,下面就是activity对上面那个接口的实现:
1 public static class MainActivity extends Activity 2 implements HeadlinesFragment.OnHeadlineSelectedListener{ 3 ... 4 5 public void onArticleSelected(int position) { 6 // The user selected the headline of an article from the HeadlinesFragment 7 // Do something here to display that article 8 } 9 }
向Fragment发送消息
主体的activity可以通过使用findFragmentById()来获取
Fragment的实例,然后发送消息到这个fragment,可以直接调用fragment的公有方法。
想象一下,显示在最上面的activity可能还包括有另外一个fragment,用来显示从上面的回调函数里里面返回的信息。那这种情况下,activity可以把从上面的回调函数里面接口的信息,传递给要显示这个信息的fragment.
1 public static class MainActivity extends Activity 2 implements HeadlinesFragment.OnHeadlineSelectedListener{ 3 ... 4 5 public void onArticleSelected(int position) { 6 // The user selected the headline of an article from the HeadlinesFragment 7 // Do something here to display that article 8 9 ArticleFragment articleFrag = (ArticleFragment) 10 getSupportFragmentManager().findFragmentById(R.id.article_fragment); 11 12 if (articleFrag != null) { 13 // If article frag is available, we're in two-pane layout... 14 15 // Call a method in the ArticleFragment to update its content 16 articleFrag.updateArticleView(position); 17 } else { 18 // Otherwise, we're in the one-pane layout and must swap frags... 19 20 // Create fragment and give it an argument for the selected article 21 ArticleFragment newFragment = new ArticleFragment(); 22 Bundle args = new Bundle(); 23 args.putInt(ArticleFragment.ARG_POSITION, position); 24 newFragment.setArguments(args); 25 26 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 27 28 // Replace whatever is in the fragment_container view with this fragment, 29 // and add the transaction to the back stack so the user can navigate back 30 transaction.replace(R.id.fragment_container, newFragment); 31 transaction.addToBackStack(null); 32 33 // Commit the transaction 34 transaction.commit(); 35 } 36 } 37 }