相關文章:
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 plaincopy
<LinearLayout?xmlns:android="http://schemas.android.com/apk/res/android"??????android:id="@+id/main_layout"??????android:layout_width="match_parent"??????android:layout_height="match_parent"??????android:orientation="horizontal"??????android:baselineAligned="false"?>????????<fragment??????????android:id="@+id/fragment1"??????????android:name="com.harvic.com.harvicblog5_1.Fragment1"??????????android:layout_width="0dip"??????????android:layout_height="match_parent"??????????android:layout_weight="1"?/>????????<fragment??????????android:id="@+id/fragment2"??????????android:name="com.harvic.com.harvicblog5_1.Fragment2"??????????android:layout_width="0dip"??????????android:layout_height="match_parent"??????????android:layout_weight="1"?/>??</LinearLayout>??
在這個布局中,橫向放兩個fragment,由于這里的fragment是靜態添加的,所以每個fragment都是有id值的,所以這時候如果我們要獲取某個fragment的實例,就可以通過FragmentManager::findFragmentById()來找到了。
然后是這兩個fragment的布局。
fragment1.xml:
[html] view plaincopy
<LinearLayout?xmlns:android="http://schemas.android.com/apk/res/android"??????android:layout_width="match_parent"??????android:layout_height="match_parent"??????android:background="#ff00ff"??????android:orientation="vertical"?>????????????<TextView??????????android:layout_width="wrap_content"??????????android:layout_height="wrap_content"??????????android:text="This?is?fragment?1"??????????android:textColor="#000000"??????????android:textSize="25sp"?/>????????<ListView??????????android:id="@+id/list"??????????android:layout_width="match_parent"??????????android:layout_height="match_parent"></ListView>??</LinearLayout>??
可以看到fragment1的布局中,除了一個標識當前Fragment的TextView,就是一個listview;
fragment2.xml:
[html] view plaincopy
<LinearLayout?xmlns:android="http://schemas.android.com/apk/res/android"??????android:layout_width="match_parent"??????android:layout_height="match_parent"??????android:background="#ffff00"??????android:orientation="vertical"?>????????????<TextView??????????android:id="@+id/fragment2_tv"??????????android:layout_width="wrap_content"??????????android:layout_height="wrap_content"??????????android:text="This?is?fragment?2"??????????android:textColor="#000000"??????????android:textSize="25sp"?/>????????</LinearLayout>??
可以看到在fragment2中非常干凈,只有一個TextView來顯示當前用戶在fragment1中的點擊結果。
下面看看在MainActivity中是如何實現的吧
[java] view plaincopy
protected?void?onCreate(Bundle?savedInstanceState)?{??????super.onCreate(savedInstanceState);??????setContentView(R.layout.activity_main);????????ArrayAdapter?arrayAdapter?=?new?ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,mStrings);??????ListView?listView?=?(ListView)findViewById(R.id.list);??????listView.setAdapter(arrayAdapter);????????mFragment2_tv?=?(TextView)findViewById(R.id.fragment2_tv);????????listView.setOnItemClickListener(new?AdapterView.OnItemClickListener()?{??????????@Override??????????public?void?onItemClick(AdapterView<?>?parent,?View?view,?int?position,?long?id)?{??????????????mFragment2_tv.setText(mStrings[position]);??????????}??????});??}??
其中:
[java] view plaincopy
private?String[]?mStrings?=?{"Abbaye?de?Belloc",?"Abbaye?du?Mont?des?Cats",?"Abertam",?"Abondance",?"Ackawi",??????????"Acorn",?"Adelost",?"Affidelice?au?Chablis",?"Afuega'l?Pitu",?"Airag",?"Airedale",?"Aisy?Cendre",??????????"Allgauer?Emmentaler",?"Abbaye?de?Belloc",?"Abbaye?du?Mont?des?Cats",?"Abertam",?"Abondance",?"Ackawi",??????????"Acorn",?"Adelost",?"Affidelice?au?Chablis",?"Afuega'l?Pitu",?"Airag",?"Airedale",?"Aisy?Cendre",??????????"Allgauer?Emmentaler"};??
難度不大,通過(ListView)findViewById(R.id.list);找到fragment1中的listview,通過(TextView)findViewById(R.id.fragment2_tv);找到fragment2中的textView,然后直接對他們進行操作。即下面的代碼:
[java] view plaincopy
listView.setOnItemClickListener(new?AdapterView.OnItemClickListener()?{??????@Override??????public?void?onItemClick(AdapterView<?>?parent,?View?view,?int?position,?long?id)?{??????????mFragment2_tv.setText(mStrings[position]);??????}??});??
當用戶點擊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 plaincopy
public?View?onCreateView(LayoutInflater?inflater,?ViewGroup?container,??????????Bundle?savedInstanceState)?{??????View?rootView?=?inflater.inflate(R.layout.fragment1,?container,?false);??????listView?=?(ListView)rootView.findViewById(R.id.list);??????return?rootView;??}??
由于在onCreateView()中,還沒有創建視圖,所以在這里如果使用getView()方法將返回空。所以如果要獲取其實圖中指定控件的引用,只用用inflater.inflate()返回的rootView;在這個rootView()中用findViewById來查找。
方法二:在onActivityCreated()函數中獲取。
從
《Fragment詳解之一——概述》的流程圖中可以看到,onActivityCreated()回調會在Activity的OnCreate()執行完成后再執行,也就是說,onActivityCreated()會在Activity的OnCreate()工作完成以后才會執行。所以當執行到onActivityCreated()的時候Activity已經創建完成,它其中的各個fragment也視圖等等的也都已經創建完成。所在可以在這里獲取跟Activity相關的各種資源。第二個問題中的獲取其它Fragment頁面中控件的引用也是在onActivityCreated()中來做的。先看看在onActivityCreated()中如何獲得自己視圖中控件的引用吧
[java] view plaincopy
public?void?onActivityCreated(Bundle?savedInstanceState)?{??????super.onActivityCreated(savedInstanceState);????????listView?=?(ListView)?getView().findViewById(R.id.list);??}???
然后,獲得其它Fragment頁面中控件的引用的方法
在上面已經說了,要獲取Activity中的資源,就必須等Acitivity創建完成以后,所以必須放在onActivityCreated()回調函數中。
其獲取方法為:
[java] view plaincopy
public?void?onActivityCreated(Bundle?savedInstanceState)?{??????super.onActivityCreated(savedInstanceState);????????mFragment2_tv?=?(TextView)?getActivity().findViewById(R.id.fragment2_tv);????}??
上面講了一堆之后,下面就看看在Fragment1中如何實現的吧。
由上面的講述可知,無論是獲取自己視圖中控件的引用還是獲取其它fragment中控件的引用都可以放在onActivityCreated()函數中,所以我們就把它們全部放在onActivityCreated()中來實現了。
[java] view plaincopy
public?void?onActivityCreated(Bundle?savedInstanceState)?{??????super.onActivityCreated(savedInstanceState);????????mFragment2_tv?=?(TextView)?getActivity().findViewById(R.id.fragment2_tv);??????listView?=?(ListView)?getView().findViewById(R.id.list);????????ArrayAdapter?arrayAdapter?=?new?ArrayAdapter<String>(getActivity(),?android.R.layout.simple_list_item_1,?mStrings);??????listView.setAdapter(arrayAdapter);??????listView.setOnItemClickListener(new?AdapterView.OnItemClickListener()?{??????????@Override??????????public?void?onItemClick(AdapterView<?>?parent,?View?view,?int?position,?long?id)?{??????????????String?str?=?mStrings[position];??????????????mFragment2_tv.setText(str);??????????}??????});??}??
難度不大,也是獲取到了每個控件以后,直接對他們進行操作。
源碼在文章底部給出
我們這里直接在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 plaincopy
public?class?Fragment2?extends?Fragment?{??????private?TextView?mTv;??????…………??????public?void?setText(String?text)?{??????????mTv.setText(text);??????}??}??
2、Fragment1中的處理方式:
(1)、定義接口及變量
由于是用回調,所以要先定義一個接口及對應的變量:
[java] view plaincopy
private?titleSelectInterface?mSelectInterface;?????public?interface?titleSelectInterface{??????public?void?onTitleSelect(String?title);??}??
(2)、接口變量賦值
接口是給activity用的,所以要在activity中給這里的接口變量賦值,可以有很多方法,當然可以選擇寫一個setXXX()函數來賦值,但如果用戶忘了怎么辦?所以我們要強制用戶賦值。所以采用強轉的方式,在fragment與activity相關聯時,進行強轉賦值:
[java] view plaincopy
public?void?onAttach(Activity?activity)?{??????super.onAttach(activity);????????try?{??????????mSelectInterface?=?(titleSelectInterface)?activity;??????}?catch?(Exception?e)?{??????????throw?new?ClassCastException(activity.toString()?+?"must?implement?OnArticleSelectedListener");??????}??}??
采用強轉的方式的問題在于,如果用戶的activity沒有implements titleSelectInterface,就會拋出錯誤,所以在調試過程中就會發現。
(3)、調用接口變量
下一步就是在fragment1中在用戶點擊listView的item的時候,將結果回傳給Activity了,代碼如下:
[java] view plaincopy
public?void?onActivityCreated(Bundle?savedInstanceState)?{??????super.onActivityCreated(savedInstanceState);????????listView?=?(ListView)?getView().findViewById(R.id.list);??????ArrayAdapter?arrayAdapter?=?new?ArrayAdapter<String>(getActivity(),?android.R.layout.simple_list_item_1,?mStrings);??????listView.setAdapter(arrayAdapter);??????listView.setOnItemClickListener(new?AdapterView.OnItemClickListener()?{??????????@Override??????????public?void?onItemClick(AdapterView<?>?parent,?View?view,?int?position,?long?id)?{??????????????String?str?=?mStrings[position];??????????????mSelectInterface.onTitleSelect(str);??????????}??????});??}??
(4)、在Activity中實現titleSelectInterface接口
首先是MainActivity必須實現titleSelectInterface接口,然后結果會在onTitleSelect(String title)中返回,在結果返回后利用fragment2.setText()操作textView;代碼如下:
[java] view plaincopy
public?class?MainActivity?extends?FragmentActivity?implements?Fragment1.titleSelectInterface?{????????……????????????@Override??????public?void?onTitleSelect(String?title)?{??????????FragmentManager?manager?=?getSupportFragmentManager();??????????Fragment2?fragment2?=?(Fragment2)manager.findFragmentById(R.id.fragment2);??????????fragment2.setText(title);??????}??}??
在上面代碼中可以看出,在結果返回后,通過findFragmentById()來獲得fragment2的實例,這里首次出現了findFragmentById()函數的用法,這個函數主要用來靜態添加的fragment中,通過fragment的ID值來獲取它的實例。在獲得fragment2的實例以后,通過調用我們寫好了setText()方法來將結果顯示在textView中。
[java] view plaincopy
Fragment2?fragment2?=?(Fragment2)manager.findFragmentById(R.id.fragment2);??
OK啦,到這里這篇文章就結束啦,源碼過來啦。
參考文章:
1、《android Fragments詳解五:與activity通訊》?
2、《Inter-Fragment Communication》
總結
以上是生活随笔為你收集整理的Fragment详解之五——Fragment间参数传递的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。