Fragment 与 Activity 通信

前言

  • 本来打算把 Fragment 的内容写完,结果写着写着发现这个篇幅已经够长了,所以就先写通信这一块了,其他的另起篇幅

正文

一、 Fragment 与 Activity 通信

  • 所有的 Fragment 都是依附于 Activity 存在的,而通信则是 Fragment 与 Activity 之间相互传递数据。

  • 一个 Activity 可以替换多个 Fragment ,Activity 就是这多个 Fragment 的管理者,考虑到 Fragment 的复用性,尽量降低 Fragment 与 Fragment 之间的耦合,不要用一个 Fragment 来操作另一个 Fragment,使用 Activity 来操作 Fragment

1. Activity 向 Fragment 传递数据
通过 bundle
  • 在动态添加 Fragment 的过程中,我们在 Activity 中通过 Fragment.setArguments() 的方法为 Fragment 提供数据,setArguments 方法需要传递一个 Bundle,把需要传递的数据放在 Bundle 中即可
1
2
3
Bundle bundle = new Bundle();
bundle.putString("name","zhangsan");
firstFragment.setArguments(bundle);
  • 在 Fragment 中,在 onAttach() 函数中通过调用 getArguments() 获得一个 Bundle 对象,从而获取我们提供的数据。
1
2
3
4
5
@Override
public void onAttach(Context context) {
super.onAttach(context);
name = (String) getArguments().get("name");
}
2. 在Fragment中可以通过 getActivity 得到当前绑定的 Activity 的实例,然后进行操作。
  • 假如 Fragment 依附的 Activity 中有这样一个方法:
1
2
3
4
public String getName(){
return "lisi";
}
  • 在 Fragment 中可以这样获取
1
2
HuiTuiZhanActivity activity = (HuiTuiZhanActivity) getActivity();
String name = activity.getName();
3. 实现Fragment 中改变 Activity 中的控件内容

通过设置回调接口来实现该效果

  • Fragment 中的代码如下所示:
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package com.example.administrator.fragment_text.huituizhan;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import com.example.administrator.fragment_text.R;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;
/**
* Created by Administrator on 2017/4/10.
*/
public class FirstFragment extends Fragment {
@BindView(R.id.editText)
EditText editText;
@BindView(R.id.btn)
Button btn;
Unbinder unbinder;
@BindView(R.id.bt2n)
Button bt2n;
private String name;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.i("FirstFragment", "onCreateView");
View inflate = inflater.inflate(R.layout.huituizhan_first_fragment, container, false);
unbinder = ButterKnife.bind(this, inflate);
return inflate;
}
/**
* 点击第一个按钮切换到 SecondFragment
*点击第二个按钮触发自定义接口中的方法,具体做什么就看宿主 Activity
*/
@OnClick({R.id.btn, R.id.bt2n})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.btn:
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
SecondFragment secondFragment = new SecondFragment();
fragmentTransaction.hide(this);
// fragmentTransaction.remove(this);
fragmentTransaction.add(R.id.framelayout, secondFragment, "second");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
break;
case R.id.bt2n:
//当需要切换 Activity 中的 TextView 的时候触发该接口中的方法
onBt2nClickListener.OnBt2nClick();
break;
}
}
private OnBt2nClickListener onBt2nClickListener;
public void setOnBt2nClickListener(OnBt2nClickListener onBt2nClickListener){
this.onBt2nClickListener = onBt2nClickListener;
}
/**
* 自定义回调接口
*/
public interface OnBt2nClickListener{
public void OnBt2nClick();
}
}
  • Activity 中的代码如下所示:
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
55
56
package com.example.administrator.fragment_text.huituizhan;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.TextView;
import com.example.administrator.fragment_text.R;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class HuiTuiZhanActivity extends AppCompatActivity {
@BindView(R.id.framelayout)
FrameLayout framelayout;
@BindView(R.id.textView)
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hui_tui_zhan);
ButterKnife.bind(this);
FragmentManager supportFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
FirstFragment firstFragment = new FirstFragment();
Bundle bundle = new Bundle();
bundle.putString("name", "zhangsan");
firstFragment.setArguments(bundle);
fragmentTransaction.add(R.id.framelayout, firstFragment, "first").commit();
}
@Override
protected void onResume() {
super.onResume();
FirstFragment first = (FirstFragment) getSupportFragmentManager().findFragmentByTag("first");
first.setOnBt2nClickListener(new FirstFragment.OnBt2nClickListener() {
@Override
public void OnBt2nClick() {
textView.setText("珞神");
}
});
}
}

这样就实现了,在点击 Fragment 中的按钮的时候,改变 Activity 中的 TextView 显示的内容,并且降低 Fragment 与 Activity 的耦合性,并增强了 Fragment 的复用性,哪个 Activity 都能用这个 Fragment

4. 实现 Fragment 来操作另一个 Fragment

Fragment1 操作另一个 Fragment2,不应在Fragment1 中直接来操作,应该交给他们共同的宿主 Activity 来操作,也是通过设置接口来实现。

测试逻辑概述: FirstFragment 中的按钮切换 Activity 中的 TextView ,SecondFragment 中的按钮切换 ThreeFragment

  • FirstFragment 中的代码:
    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
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    package com.example.administrator.fragment_text.huituizhan;
    import android.content.Context;
    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.support.v4.app.Fragment;
    import android.support.v4.app.FragmentManager;
    import android.support.v4.app.FragmentTransaction;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.Button;
    import android.widget.EditText;
    import com.example.administrator.fragment_text.R;
    import butterknife.BindView;
    import butterknife.ButterKnife;
    import butterknife.OnClick;
    import butterknife.Unbinder;
    /**
    * Created by Administrator on 2017/4/10.
    */
    public class FirstFragment extends Fragment {
    @BindView(R.id.editText)
    EditText editText;
    @BindView(R.id.btn)
    Button btn;
    Unbinder unbinder;
    @BindView(R.id.bt2n)
    Button bt2n;
    private String name;
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    Log.i("FirstFragment", "onCreateView");
    View inflate = inflater.inflate(R.layout.huituizhan_first_fragment, container, false);
    unbinder = ButterKnife.bind(this, inflate);
    editText.setText(name);
    return inflate;
    }
    /**
    * 点击按钮切换到 SecondFragment
    */
    @OnClick({R.id.btn, R.id.bt2n})
    public void onViewClicked(View view) {
    switch (view.getId()) {
    case R.id.btn:
    FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
    SecondFragment secondFragment = new SecondFragment();
    fragmentTransaction.hide(this);
    fragmentTransaction.add(R.id.framelayout, secondFragment, "second");
    fragmentTransaction.addToBackStack(null);
    fragmentTransaction.commit();
    break;
    case R.id.bt2n:
    //如果宿主 Activity 实现了此接口
    if (getActivity() instanceof OnBt2nClickListener) {
    //当需要切换 Activity 中的 TextView 的时候触发该接口中的方法
    ((OnBt2nClickListener) getActivity()).OnBt2nClick();
    }
    break;
    }
    }
    // private OnBt2nClickListener onBt2nClickListener;
    //
    //
    // public void setOnBt2nClickListener(OnBt2nClickListener onBt2nClickListener){
    // this.onBt2nClickListener = onBt2nClickListener;
    // }
    /**
    * 自定义回调接口
    */
    public interface OnBt2nClickListener {
    public void OnBt2nClick();
    }
    }

注意: 这里的回调采用了另一种方式:

1
2
3
4
5
6
//如果宿主 Activity 实现了此接口
if (getActivity() instanceof OnBt2nClickListener) {
//当需要切换 Activity 中的 TextView 的时候触发该接口中的方法
((OnBt2nClickListener) getActivity()).OnBt2nClick();
}
  • SecondFragment 中的代码:
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package com.example.administrator.fragment_text.huituizhan;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import com.example.administrator.fragment_text.R;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;
/**
* Created by Administrator on 2017/4/10.
*/
public class SecondFragment extends Fragment {
@BindView(R.id.editText)
EditText editText;
@BindView(R.id.btn)
Button btn;
Unbinder unbinder;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View inflate = inflater.inflate(R.layout.huituizhan_second_fragment, container, false);
unbinder = ButterKnife.bind(this, inflate);
Log.i("SecondFragment", "onCreateView");
return inflate;
}
@OnClick(R.id.btn)
public void onViewClicked() {
if (getActivity() instanceof OnBt22222nClickListener) {
//当需要切换 Activity 中的 TextView 的时候触发该接口中的方法
((OnBt22222nClickListener) getActivity()).OnBt22222nClick();
}
}
private OnBt22222nClickListener onBt22222nClickListener;-->
public void setOnBt22222nClickListener(OnBt22222nClickListener onBt22222nClickListener) {-->
this.onBt22222nClickListener = onBt22222nClickListener;-->
}
/**
* 自定义回调接口
*/
public interface OnBt22222nClickListener {
public void OnBt22222nClick();
}
}

注意: SecondFragment 中的回调设置与 FirstFragment 中的一样,我试过按照常规方式 ( setOnBt22222nClickListener 方式 ) 设置,切换 Fragment 的时候程序崩溃,而这种方式则没问题,不知道为嘛 - -!

  • Activity 中的代码:
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package com.example.administrator.fragment_text.huituizhan;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.TextView;
import com.example.administrator.fragment_text.R;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class HuiTuiZhanActivity extends AppCompatActivity implements FirstFragment.OnBt2nClickListener, SecondFragment.OnBt22222nClickListener {
@BindView(R.id.framelayout)
FrameLayout framelayout;
@BindView(R.id.textView)
TextView textView;
private SecondFragment second;
private FirstFragment firstFragment;
private ThreeFragment three;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hui_tui_zhan);
ButterKnife.bind(this);
FragmentManager supportFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
firstFragment = new FirstFragment();
Bundle bundle = new Bundle();
bundle.putString("name", "zhangsan");
firstFragment.setArguments(bundle);
fragmentTransaction.add(R.id.framelayout, firstFragment, "first").commit();
}
//FirstFragment 中回调的点击事件
@Override
public void OnBt2nClick() {
textView.setText("珞神");
if (second == null) {
second = new SecondFragment();
second.setOnBt22222nClickListener(this);
}
}
//SecondFragment 中回调的点击事件
@Override
public void OnBt22222nClick() {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (three == null) {
three = new ThreeFragment();
}
if (second == null) {
second = new SecondFragment();
}
// fragmentTransaction.hide(second);
// fragmentTransaction.add(R.id.framelayout,three,"three");
fragmentTransaction.replace(R.id.framelayout, three, "three");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
}
5. 通过 getFragmentManager.findFragmentByTag() 或者 findFragmentById() 获得任何 Fragment 实例,然后来操作 Fragment 中的方法。
  • 假如 Fragment 中有这样一个方法:
1
2
3
4
public String getName(){
return "珞神";
}
  • 在其宿主 Activity 中可以这样操作:
1
2
FirstFragment first = (FirstFragment) getSupportFragmentManager().findFragmentByTag("first");
String name = first.getName();

至此,完结!如有错误和遗漏,一经发现,必然改正!