Android實現Fragment與Activity之間的資料互動
1概念
1 為什麼
因為Fragment和Activity一樣是具有生命週期,不是一般的bean通過建構函式傳值,會造成異常。
2 參考連結
【Fragment精深系列4】Fragment與Activity之間的資料互動
2 Activity把值傳遞給Fragment
2.1 第一種方式,也是最常用的方式,就是使用Bundle來傳遞引數
(1)宿主Activity/FragmentAdapter中:
Bundle bundle = new Bundle();
bundle.putString(Constant.INTENT_ID, productId);
Fragment fragment = null ;
switch (position) {
case 0:
fragment = new ProductImageDetailFragment();
break;
case 1:
fragment = new ProductParamFragment();
break;
case 2:
fragment = new ProductCommentFragment();
break;
default:
break;
}
fragment.setArguments(bundle);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
(2)Activity/FragmentAdapter中:
Fragment中的onCreatView/onStart()方法中,通過getArgments()方法,獲取到bundle物件,然後通過getString的key值拿到我們傳遞過來的值。
@Override
public void onStart() {
super.onStart();
if (isAdded()) {//判斷Fragment已經依附Activity
productId = getArguments().getString(Constant.INTENT_ID);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
2.2 第二種方式,是在宿主Activity中定義方法,將要傳遞的值傳遞到Fragment中,在Fragment中的onAttach方法中,獲取到這個值。
(1)宿主activity中的getTitles()方法
public String getTitles(){
return "hello";
}
- 1
- 2
- 3
(2)Fragment中的onAttach方法
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
titles = ((MainActivity) activity).getTitles();//通過強轉成宿主activity,就可以獲取到傳遞過來的資料
}
- 1
- 2
- 3
- 4
- 5
2.3 第三種方式,是擴充套件一下建立Fragment和傳遞數值
(1)在宿主activity中,建立Fragment
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.setCustomAnimations(android.R.anim.fade_in,android.R.anim.fade_out);
fragment1 = MyFragment.newInstance("這是第一個fragment");//這裡只需要直接呼叫這個方法,就建立了一個fragment
fragment2 = MyFragment.newInstance("這是第二個fragment");
- 1
- 2
- 3
- 4
- 5
(2)Fragment中
//定義newInstance()例項
static MyFragment newInstance(String s){
MyFragment myFragment = new MyFragment();
Bundle bundle = new Bundle();
bundle.putString("DATA",s);
myFragment.setArguments(bundle);
return myFragment;
}
//同樣,在onCreatView中直接獲取這個值
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//......
Bundle bundle = getArguments();
String data = bundle.getString("DATA");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
3 Fragment把值傳遞給Activity
3.1 步驟
(1)在fragment中定義一個內部回撥介面,再讓包含該fragment的activity實現該回調介面,這樣fragment即可呼叫該回調方法將資料傳給activity。其實介面回撥的原理都一樣,以前的部落格有講到,介面回撥是java不同物件之間資料互動的通用方法。
(2)activity實現完了介面怎麼傳給剛才的fragment呢?當fragment新增到activity中時,會呼叫fragment的方法onAttach(),這個方法中適合檢查activity是否實現了OnArticleSelectedListener介面,檢查方法就是對傳入的activity的例項進行型別轉換,然後賦值給我們在fragment中定義的介面。
(3)在一個fragment從activity中剝離的時候,就會呼叫onDetach方法,這個時候要把傳遞進來的activity物件釋放掉,不然會影響activity的銷燬,產生不必要的錯誤。注意看onAttach方法中的程式碼,在賦值之前要做一個判斷,看看Activity中有沒有實現了這個介面,用到了instanceof。如果沒有實現介面,我們就丟擲異常。
3.2 例子
(1)在宿主activity中,建立Fragment
public class MainActivity extends Activity implements MenuFragment.FragmentInteraction{
private TextView textView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textView = (TextView) findViewById(R.id.content_text);
}
// 3.2 +實現介面,實現回撥
@Override
public void process(String str) {
if (str != null) {
textView.setText(str);
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
(2)Fragment中
public class MenuFragment extends Fragment implements View.OnClickListener {
// 2.1 定義用來與外部activity互動,獲取到宿主activity
private FragmentInteraction listterner;
// 1 定義了所有activity必須實現的介面方法
public interface FragmentInteraction {
void process(String str);
}
// 當FRagmen被載入到activity的時候會被回撥
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if(activity instanceof FragmentInteraction) {
listterner = (FragmentInteraction)activity; // 2.2 獲取到宿主activity並賦值
} else{
throw new IllegalArgumentException("activity must implements FragmentInteraction");
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_menu, container, false);
View btn = view.findViewById(R.id.tv_button);
View btn_m = view.findViewById(R.id.movie_button);
if (btn != null||btn_m!=null) {
btn.setOnClickListener(this);
btn_m.setOnClickListener(this);
}
return view;
}
@Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.tv_button:
listterner.process("我是電視劇"); // 3.1 執行回撥
break;
case R.id.movie_button:
listterner.process("我是電影");
break;
}
}
//把傳遞進來的activity物件釋放掉
@Override
public void onDetach() {
super.onDetach();
listterner = null;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
4 Fragment與Fragment之間的傳值
在Activity中載入Fragment的時候、有時候要使用多個Fragment切換、並傳值到另外一個Fragment、也就是說兩個Fragment之間進行引數的傳遞,有兩個方法。
4.1 通過共同的Activity傳遞(主要方法)
在Activity裡面新增一個欄位、來臨時儲存要一些值。在Activity中定義一個欄位、然後新增set和get方法。
(1)在宿主activity中
public class DemoActivity {
private String mTitle;
public String getmTitle() {
return mTitle;
}
public void setmTitle(String title) {
this.mTitle = title;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
(2)Fragment中
// 呼叫方法、需要注意的是在設值的時候要進行強轉一下
((DemoActivity)getActivity()).getmTitle();
- 1
- 2
4.1 通過Bundle來傳遞(本質還是Activity–>Fragment)
(1)在宿主activity中
ft.hide(getActivity().getSupportFragmentManager().findFragmentByTag(""));
DemoFragment demoFragment = new DemoFragment();
Bundle bundle = new Bundle();
bundle.putString("key", "這是方法二");
demoFragment.setArguments(bundle);
ft.add(R.id.fragmentRoot, demoFragment, SEARCHPROJECT);
ft.commit();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
(2)Fragment中
String string = getArguments().getString("key");
- 1
1概念
1 為什麼
因為Fragment和Activity一樣是具有生命週期,不是一般的bean通過建構函式傳值,會造成異常。
2 參考連結
【Fragment精深系列4】Fragment與Activity之間的資料互動
2 Activity把值傳遞給Fragment
2.1 第一種方式,也是最常用的方式,就是使用Bundle來傳遞引數
(1)宿主Activity/FragmentAdapter中:
Bundle bundle = new Bundle();
bundle.putString(Constant.INTENT_ID, productId);
Fragment fragment = null;
switch (position) {
case 0:
fragment = new ProductImageDetailFragment();
break;
case 1:
fragment = new ProductParamFragment();
break;
case 2:
fragment = new ProductCommentFragment();
break;
default:
break;
}
fragment.setArguments(bundle);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
(2)Activity/FragmentAdapter中:
Fragment中的onCreatView/onStart()方法中,通過getArgments()方法,獲取到bundle物件,然後通過getString的key值拿到我們傳遞過來的值。
@Override
public void onStart() {
super.onStart();
if (isAdded()) {//判斷Fragment已經依附Activity
productId = getArguments().getString(Constant.INTENT_ID);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
2.2 第二種方式,是在宿主Activity中定義方法,將要傳遞的值傳遞到Fragment中,在Fragment中的onAttach方法中,獲取到這個值。
(1)宿主activity中的getTitles()方法
public String getTitles(){
return "hello";
}
- 1
- 2
- 3
(2)Fragment中的onAttach方法
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
titles = ((MainActivity) activity).getTitles();//通過強轉成宿主activity,就可以獲取到傳遞過來的資料
}
- 1
- 2
- 3
- 4
- 5
2.3 第三種方式,是擴充套件一下建立Fragment和傳遞數值
(1)在宿主activity中,建立Fragment
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.setCustomAnimations(android.R.anim.fade_in,android.R.anim.fade_out);
fragment1 = MyFragment.newInstance("這是第一個fragment");//這裡只需要直接呼叫這個方法,就建立了一個fragment
fragment2 = MyFragment.newInstance("這是第二個fragment");
- 1
- 2
- 3
- 4
- 5
(2)Fragment中
//定義newInstance()例項
static MyFragment newInstance(String s){
MyFragment myFragment = new MyFragment();
Bundle bundle = new Bundle();
bundle.putString("DATA",s);
myFragment.setArguments(bundle);
return myFragment;
}
//同樣,在onCreatView中直接獲取這個值
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//......
Bundle bundle = getArguments();
String data = bundle.getString("DATA");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
3 Fragment把值傳遞給Activity
3.1 步驟
(1)在fragment中定義一個內部回撥介面,再讓包含該fragment的activity實現該回調介面,這樣fragment即可呼叫該回調方法將資料傳給activity。其實介面回撥的原理都一樣,以前的部落格有講到,介面回撥是java不同物件之間資料互動的通用方法。
(2)activity實現完了介面怎麼傳給剛才的fragment呢?當fragment新增到activity中時,會呼叫fragment的方法onAttach(),這個方法中適合檢查activity是否實現了OnArticleSelectedListener介面,檢查方法就是對傳入的activity的例項進行型別轉換,然後賦值給我們在fragment中定義的介面。
(3)在一個fragment從activity中剝離的時候,就會呼叫onDetach方法,這個時候要把傳遞進來的activity物件釋放掉,不然會影響activity的銷燬,產生不必要的錯誤。注意看onAttach方法中的程式碼,在賦值之前要做一個判斷,看看Activity中有沒有實現了這個介面,用到了instanceof。如果沒有實現介面,我們就丟擲異常。
3.2 例子
(1)在宿主activity中,建立Fragment
public class MainActivity extends Activity implements MenuFragment.FragmentInteraction{
private TextView textView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textView = (TextView) findViewById(R.id.content_text);
}
// 3.2 +實現介面,實現回撥
@Override
public void process(String str) {
if (str != null) {
textView.setText(str);
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
(2)Fragment中
public class MenuFragment extends Fragment implements View.OnClickListener {
// 2.1 定義用來與外部activity互動,獲取到宿主activity
private FragmentInteraction listterner;
// 1 定義了所有activity必須實現的介面方法
public interface FragmentInteraction {
void process(String str);
}
// 當FRagmen被載入到activity的時候會被回撥
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if(activity instanceof FragmentInteraction) {
listterner = (FragmentInteraction)activity; // 2.2 獲取到宿主activity並賦值
} else{
throw new IllegalArgumentException("activity must implements FragmentInteraction");
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_menu, container, false);
View btn = view.findViewById(R.id.tv_button);
View btn_m = view.findViewById(R.id.movie_button);
if (btn != null||btn_m!=null) {
btn.setOnClickListener(this);
btn_m.setOnClickListener(this);
}
return view;
}
@Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.tv_button:
listterner.process("我是電視劇"); // 3.1 執行回撥
break;
case R.id.movie_button:
listterner.process("我是電影");
break;
}
}
//把傳遞進來的activity物件釋放掉
@Override
public void onDetach() {
super.onDetach();
listterner = null;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
4 Fragment與Fragment之間的傳值
在Activity中載入Fragment的時候、有時候要使用多個Fragment切換、並傳值到另外一個Fragment、也就是說兩個Fragment之間進行引數的傳遞,有兩個方法。
4.1 通過共同的Activity傳遞(主要方法)
在Activity裡面新增一個欄位、來臨時儲存要一些值。在Activity中定義一個欄位、然後新增set和get方法。
(1)在宿主activity中
public class DemoActivity {
private String mTitle;
public String getmTitle() {
return mTitle;
}
public void setmTitle(String title) {
this.mTitle = title;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
(2)Fragment中
// 呼叫方法、需要注意的是在設值的時候要進行強轉一下
((DemoActivity)getActivity()).getmTitle();
- 1
- 2
4.1 通過Bundle來傳遞(本質還是Activity–>Fragment)
(1)在宿主activity中
ft.hide(getActivity().getSupportFragmentManager().findFragmentByTag(""));
DemoFragment demoFragment = new DemoFragment();
Bundle bundle = new Bundle();
bundle.putString("key", "這是方法二");
demoFragment.setArguments(bundle);
ft.add(R.id.fragmentRoot, demoFragment, SEARCHPROJECT);
ft.commit();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
(2)Fragment中
String string = getArguments().getString("key");
- 1