Android - 用Fragments实现动态UI - 和其他Fragments通信
为了重用Fragment UI组件,应该把每个都设计为它自有的模块组件并且有自己的布局和行为。一旦定义了这些可重用的Fragment,你可以把它们和一个activity关联然后和程序的逻辑一起实现上层的UI。
经常会用到一个Fragment需要和另一个通讯,比如根据用户事件来交换内容。所有的fragment和fragment只见的通讯是通过相关的activity实现的。两个fragment不能直接通讯。
定义一个接口
为了运行fragment和它的activity通讯,你可以在fragment类中定义一个接口然后在activity中实现它。fragment在onAttach()生命周期方法中捕获到接口然后调用接口方法来和activity通讯。
这里是一个fragment到activity通讯的例子:
1 public class HeadlinesFragment extends ListFragment { 2 OnHeadlineSelectedListener mCallback; 3 4 // Activity必需实现这个接口 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 // 这里确保了activity实现了回调接口方法,不然抛出异常 14 try { 15 mCallback = (OnHeadlineSelectedListener) activity; 16 } catch (ClassCastException e) { 17 throw new ClassCastException(activity.toString() 18 + " must implement OnHeadlineSelectedListener"); 19 } 20 } 21 22 ... 23 }
现在fragment可以通过调用onArticleSelected()方法向activity发送消息了(或者接口中的其他方法),使用onHeadlineSelectedListener接口中的mCallback实例。
例如,当用户点击list后,fragment的下面的方法会被调用。fragment用回调接口发送消息到父activity。
1 @Override 2 public void onListItemClick(ListView l, View v, int position, long id) { 3 // 发送消息到宿主activity 4 mCallback.onArticleSelected(position); 5 }
实现接口
为了接收fragment的回调事件,activity必需实现fragment类中定义的接口。
例如,下面的activity实现的上面例子中的接口。
1 public static class MainActivity extends Activity 2 implements HeadlinesFragment.OnHeadlineSelectedListener{ 3 ... 4 5 public void onArticleSelected(int position) { 6 // 用户点击了HeadlinesFragment中的文章标题 7 // 在这里实现一些方法来显示文章 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 // 用户点击了HeadlinesFragment中的文章标题 7 // 做点什么来显示文章 8 9 ArticleFragment articleFrag = (ArticleFragment) 10 getSupportFragmentManager().findFragmentById(R.id.article_fragment); 11 12 if (articleFrag != null) { 13 // 如果articleFrag可用,说明我们是在一个两栏的布局中... 14 15 // 调用ArticleFragment中的方法来更新内容 16 articleFrag.updateArticleView(position); 17 } else { 18 // 否则,我们是在一个单栏的布局中,所以需要切换fragment... 19 20 // 创建一个fragment然后把选中的文章作为参数传给它 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 // 用fragment替换fragment_container view中的内容 29 // 把transaction添加到返回堆栈这样用户可以切换回来 30 transaction.replace(R.id.fragment_container, newFragment); 31 transaction.addToBackStack(null); 32 33 // 提交transaction 34 transaction.commit(); 35 } 36 } 37 }