Fragment详解之五——Fragment间参数传递

来源:互联网 发布:网络探案小说排行榜 编辑:程序博客网 时间:2024/05/01 02:16

相关文章:

1、《Fragment详解之一——概述》
2、《Fragment详解之二——基本使用方法》
3、《Fragment详解之三——管理Fragment(1)》
4、《Fragment详解之四——管理Fragment(2)》
5、《Fragment详解之五——Fragment间参数传递》
6、《Fragment详解之六——如何监听fragment中的回退事件与怎样保存fragment状态》


在关Fragment间参数的传递,有两种情况:

  • 第一种情况:同一个container中不同fragment间的参数传递。这种情况一般发生在fragment跳转时,上一个Fragment将参数传递给下一个Fragment。
  • 第二种情况:是同一个Activity中,不个container间Fragment的参数传递。
有关第一种情况,以前写过一篇文章,详细说明了上一个Fragment将参数传递给下一个Fragment,及数据回传的方法。详细参见:《Fragment跳转时传递参数及结果回传的方法》

下面详细看看这两种参数传递方法。

一、同一个container间的参数传递。

有关这个问题,请大家移步以前写的一篇文章:《Fragment跳转时传递参数及结果回传的方法》,在这篇文章中有关Fragment跳转时的参数传递和结果回传已经讲的很清楚了,这里就没必要重新再写一遍,下面是这篇文章的效果图:

  • 1、在界面开始时,点击“加载第二个Fragment”按钮
  • 2、调起Fragment2,并向其传递一个参数“从Fragment1传来的参数”,显示在Fragment2中
  • 3、点击Fragment2中的四个小动物中的一个,会向Fragment1回传用户点击的是哪个动物,在Fragment1中显示出来。
看起来挺有意思?那就移步到这篇文章里看看吧

二、同一个Activity,不同container间的参数传递

这里到了这篇文章的重点内容了哦,这可并不是说上一部分不重要哈,其实上一部分要比这部分重要!同一个container中不同Fragment间的参数传递一般的工程都会用到的,所以大家一定要看。而我这里不讲,是因为以前有讲过,这里就没必要再重复一遍了,好了,废话说了好多……开整吧。
先看看效果图:
1、在这个Actiivty中有两个Fragment;
2、Fragment1中有一个listView,当我们点击ListView的Item的时候,把Item上的内容更新到Fragment2上


这里有多种实现方法,最可取的是方法三。我们由简到易慢慢讲。
我们想使两个fragment实例要能通信,那如果我们都能通过findViewById()找到所有的控件,直接操控的话,岂不就实现了。而通过findViewById()能找到所有控件实例的地方就是在Activity中了,所以这就有了方法一。

方法一:直接在Activity中操作

在Activity中找到对应的控件实例,然后直接操控即可。
先看看MainActivity的布局:activity_main.xml

[html] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:id="@+id/main_layout"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:orientation="horizontal"  
  6.     android:baselineAligned="false" >  
  7.   
  8.     <fragment  
  9.         android:id="@+id/fragment1"  
  10.         android:name="com.harvic.com.harvicblog5_1.Fragment1"  
  11.         android:layout_width="0dip"  
  12.         android:layout_height="match_parent"  
  13.         android:layout_weight="1" />  
  14.   
  15.     <fragment  
  16.         android:id="@+id/fragment2"  
  17.         android:name="com.harvic.com.harvicblog5_1.Fragment2"  
  18.         android:layout_width="0dip"  
  19.         android:layout_height="match_parent"  
  20.         android:layout_weight="1" />  
  21. </LinearLayout>  
在这个布局中,横向放两个fragment,由于这里的fragment是静态添加的,所以每个fragment都是有id值的,所以这时候如果我们要获取某个fragment的实例,就可以通过FragmentManager::findFragmentById()来找到了。
然后是这两个fragment的布局。
fragment1.xml:

[html] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:layout_width="match_parent"  
  3.     android:layout_height="match_parent"  
  4.     android:background="#ff00ff"  
  5.     android:orientation="vertical" >  
  6.       
  7.     <TextView  
  8.         android:layout_width="wrap_content"  
  9.         android:layout_height="wrap_content"  
  10.         android:text="This is fragment 1"  
  11.         android:textColor="#000000"  
  12.         android:textSize="25sp" />  
  13.   
  14.     <ListView  
  15.         android:id="@+id/list"  
  16.         android:layout_width="match_parent"  
  17.         android:layout_height="match_parent"></ListView>  
  18. </LinearLayout>  
可以看到fragment1的布局中,除了一个标识当前Fragment的TextView,就是一个listview;
fragment2.xml:
[html] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:layout_width="match_parent"  
  3.     android:layout_height="match_parent"  
  4.     android:background="#ffff00"  
  5.     android:orientation="vertical" >  
  6.       
  7.     <TextView  
  8.         android:id="@+id/fragment2_tv"  
  9.         android:layout_width="wrap_content"  
  10.         android:layout_height="wrap_content"  
  11.         android:text="This is fragment 2"  
  12.         android:textColor="#000000"  
  13.         android:textSize="25sp" />  
  14.       
  15. </LinearLayout>  
可以看到在fragment2中非常干净,只有一个TextView来显示当前用户在fragment1中的点击结果。
下面看看在MainActivity中是如何实现的吧
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. protected void onCreate(Bundle savedInstanceState) {  
  2.     super.onCreate(savedInstanceState);  
  3.     setContentView(R.layout.activity_main);  
  4.   
  5.     ArrayAdapter arrayAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,mStrings);  
  6.     ListView listView = (ListView)findViewById(R.id.list);  
  7.     listView.setAdapter(arrayAdapter);  
  8.   
  9.     mFragment2_tv = (TextView)findViewById(R.id.fragment2_tv);  
  10.   
  11.     listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {  
  12.         @Override  
  13.         public void onItemClick(AdapterView<?> parent, View view, int position, long id) {  
  14.             mFragment2_tv.setText(mStrings[position]);  
  15.         }  
  16.     });  
  17. }  
其中:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. private String[] mStrings = {"Abbaye de Belloc""Abbaye du Mont des Cats""Abertam""Abondance""Ackawi",  
  2.         "Acorn""Adelost""Affidelice au Chablis""Afuega'l Pitu""Airag""Airedale""Aisy Cendre",  
  3.         "Allgauer Emmentaler""Abbaye de Belloc""Abbaye du Mont des Cats""Abertam""Abondance""Ackawi",  
  4.         "Acorn""Adelost""Affidelice au Chablis""Afuega'l Pitu""Airag""Airedale""Aisy Cendre",  
  5.         "Allgauer Emmentaler"};  
难度不大,通过(ListView)findViewById(R.id.list);找到fragment1中的listview,通过(TextView)findViewById(R.id.fragment2_tv);找到fragment2中的textView,然后直接对他们进行操作。即下面的代码:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {  
  2.     @Override  
  3.     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {  
  4.         mFragment2_tv.setText(mStrings[position]);  
  5.     }  
  6. });  
当用户点击listView的一个item时,将值setText到fragment2的textView中。
源码在文章底部给出

可见,直接在activity中操作各个fragment的控件就可以实现消息互传。但,这样真的好吗?如果每个fragment中的控件都在Activity中操作,那还要fragment干嘛!最最起码,应该每个fragment负责自己的控件操作才对嘛!
所以,我们对这种方法进行改进,将点击Item的赋值操作放到fragment1中去。所以,这就有方法二;

方法二:直接在fragment中操作

在这里我们会把所有方法写在Fragment1中,这里涉及到两方面的内容:
第一:在Fragment中如何获得自己控件的引用,比较这里Fragment1里的listview控件。
第二:在Fragment中如何获得其它Fragment页面中控件的引用,比如这里Fragment2里的TextView控件。 

首先,获取自己控件引用的方法: 
方法一:在onCreateView()中获取。 
就比如这里获取自己的listView控件的引用,代码如下:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public View onCreateView(LayoutInflater inflater, ViewGroup container,  
  2.         Bundle savedInstanceState) {  
  3.     View rootView = inflater.inflate(R.layout.fragment1, container, false);  
  4.     listView = (ListView)rootView.findViewById(R.id.list);//获取自己视图里的控件引用,方法一  
  5.     return rootView;  
  6. }  
由于在onCreateView()中,还没有创建视图,所以在这里如果使用getView()方法将返回空。所以如果要获取其实图中指定控件的引用,只用用inflater.inflate()返回的rootView;在这个rootView()中用findViewById来查找。
方法二:在onActivityCreated()函数中获取。
《Fragment详解之一——概述》的流程图中可以看到,onActivityCreated()回调会在Activity的OnCreate()执行完成后再执行,也就是说,onActivityCreated()会在Activity的OnCreate()工作完成以后才会执行。所以当执行到onActivityCreated()的时候Activity已经创建完成,它其中的各个fragment也视图等等的也都已经创建完成。所在可以在这里获取跟Activity相关的各种资源。第二个问题中的获取其它Fragment页面中控件的引用也是在onActivityCreated()中来做的。先看看在onActivityCreated()中如何获得自己视图中控件的引用吧

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public void onActivityCreated(Bundle savedInstanceState) {  
  2.     super.onActivityCreated(savedInstanceState);  
  3.   
  4.     listView = (ListView) getView().findViewById(R.id.list);//获取自己视图里的控件引用,方法二  
  5. }   
然后,获得其它Fragment页面中控件的引用的方法
在上面已经说了,要获取Activity中的资源,就必须等Acitivity创建完成以后,所以必须放在onActivityCreated()回调函数中。
其获取方法为:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public void onActivityCreated(Bundle savedInstanceState) {  
  2.     super.onActivityCreated(savedInstanceState);  
  3.   
  4.     mFragment2_tv = (TextView) getActivity().findViewById(R.id.fragment2_tv);//获取其它fragment中的控件引用的唯一方法!!!  
  5.   
  6. }  
上面讲了一堆之后,下面就看看在Fragment1中如何实现的吧。
由上面的讲述可知,无论是获取自己视图中控件的引用还是获取其它fragment中控件的引用都可以放在onActivityCreated()函数中,所以我们就把它们全部放在onActivityCreated()中来实现了。
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public void onActivityCreated(Bundle savedInstanceState) {  
  2.     super.onActivityCreated(savedInstanceState);  
  3.   
  4.     mFragment2_tv = (TextView) getActivity().findViewById(R.id.fragment2_tv);//获取其它fragment中的控件引用的唯一方法!!!  
  5.     listView = (ListView) getView().findViewById(R.id.list);//获取自己视图里的控件引用,方法二  
  6.   
  7.     ArrayAdapter arrayAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, mStrings);  
  8.     listView.setAdapter(arrayAdapter);  
  9.     listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {  
  10.         @Override  
  11.         public void onItemClick(AdapterView<?> parent, View view, int position, long id) {  
  12.             String str = mStrings[position];  
  13.             mFragment2_tv.setText(str);  
  14.         }  
  15.     });  
  16. }  
难度不大,也是获取到了每个控件以后,直接对他们进行操作。
源码在文章底部给出

我们这里直接在fragment1中操作了fragment2的控件,这样就违背了模块分离的思想,我们应该让他们各自处理各自的代码才好。所以,考虑到将他们分离,我们这里就出现了方法三。

方法三:在各自的fragment中操作

好,我们先想想要怎么解决这个问题,首先,我们把各自的事件放在各自的fragment中处理,即在fragment1中能得到当前用户点击的ITEM的String字符串,在fragment2中可以设置textview的值。那问题来了,各自获得了各自的东东,那通过什么让他们交互呢?
答案显然是activity。
很显然,在activity中可以直接通过FragmentManager::findFragmentById()来获取fragment2的实例。进而调用fragment2中的任意方法,这就实现了与fragment2的通信。
那fragment1又怎么把结果回传给Activity呢?大家如果在看到这里之前先看了《Fragment跳转时传递参数及结果回传的方法》就很容易想到,用回调!请记住。在不同页面中回传结果,回调是万能的解决方案。
1、Fragment2设置textView函数:
先看个简单的,fragment2中的处理代码:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public class Fragment2 extends Fragment {  
  2.     private TextView mTv;  
  3.     …………  
  4.     public void setText(String text) {  
  5.         mTv.setText(text);  
  6.     }  
  7. }  
2、Fragment1中的处理方式:
(1)、定义接口及变量
由于是用回调,所以要先定义一个接口及对应的变量:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. private titleSelectInterface mSelectInterface;  
  2.    
  3. public interface titleSelectInterface{  
  4.     public void onTitleSelect(String title);  
  5. }  
(2)、接口变量赋值
接口是给activity用的,所以要在activity中给这里的接口变量赋值,可以有很多方法,当然可以选择写一个setXXX()函数来赋值,但如果用户忘了怎么办?所以我们要强制用户赋值。所以采用强转的方式,在fragment与activity相关联时,进行强转赋值:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public void onAttach(Activity activity) {  
  2.     super.onAttach(activity);  
  3.   
  4.     try {  
  5.         mSelectInterface = (titleSelectInterface) activity;  
  6.     } catch (Exception e) {  
  7.         throw new ClassCastException(activity.toString() + "must implement OnArticleSelectedListener");  
  8.     }  
  9. }  
采用强转的方式的问题在于,如果用户的activity没有implements titleSelectInterface,就会抛出错误,所以在调试过程中就会发现。
(3)、调用接口变量
下一步就是在fragment1中在用户点击listView的item的时候,将结果回传给Activity了,代码如下:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public void onActivityCreated(Bundle savedInstanceState) {  
  2.     super.onActivityCreated(savedInstanceState);  
  3.   
  4.     listView = (ListView) getView().findViewById(R.id.list);//获取自己视图里的控件引用,方法二  
  5.     ArrayAdapter arrayAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, mStrings);  
  6.     listView.setAdapter(arrayAdapter);  
  7.     listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {  
  8.         @Override  
  9.         public void onItemClick(AdapterView<?> parent, View view, int position, long id) {  
  10.             String str = mStrings[position];  
  11.             mSelectInterface.onTitleSelect(str);  
  12.         }  
  13.     });  
  14. }  
(4)、在Activity中实现titleSelectInterface接口
首先是MainActivity必须实现titleSelectInterface接口,然后结果会在onTitleSelect(String title)中返回,在结果返回后利用fragment2.setText()操作textView;代码如下:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public class MainActivity extends FragmentActivity implements Fragment1.titleSelectInterface {  
  2.   
  3.     ……  
  4.       
  5.     @Override  
  6.     public void onTitleSelect(String title) {  
  7.         FragmentManager manager = getSupportFragmentManager();  
  8.         Fragment2 fragment2 = (Fragment2)manager.findFragmentById(R.id.fragment2);  
  9.         fragment2.setText(title);  
  10.     }  
  11. }  
在上面代码中可以看出,在结果返回后,通过findFragmentById()来获得fragment2的实例,这里首次出现了findFragmentById()函数的用法,这个函数主要用来静态添加的fragment中,通过fragment的ID值来获取它的实例。在获得fragment2的实例以后,通过调用我们写好了setText()方法来将结果显示在textView中。
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. Fragment2 fragment2 = (Fragment2)manager.findFragmentById(R.id.fragment2);  
OK啦,到这里这篇文章就结束啦,源码过来啦。

参考文章:

1、《android Fragments详解五:与activity通讯》 

2、《Inter-Fragment Communication》


源码内容:

1、《harvicBlog5_1》:对应方法一
2、《harvicBlog5_2》:对应方法二

3、《harvicBlog5_3》:对应方法三


如果本文有帮到你,记得关注哦

源码下载地址:http://download.csdn.net/detail/harvic880925/8582921

请大家尊重原创者版权,转载请标明出处:http://blog.csdn.net/harvic880925/article/details/44966913 ,谢谢!

0 0