Android指东:组件通信

发布 : 2019-08-30 分类 : Android指南 浏览 :

这里我们会先略过一些通用的方法,比如广播、数据存储SharePreferences等,把注意力放在组件内部。

1. 向下一个Activity传递数据

Intent 是在相互独立的组件(如两个 Activity)之间提供运行时绑定功能的对象。Intent 表示某个应用“执行某项操作的意图”。新建一个Intent对象,传入希望启用的Activity作为参数,调用startActivity,即可向下一个Activity传递数据。

1
2
3
4
Intent intent = new Intent(this, TargetActivity.class);
// 其中value支持多种类型
intent.putExtra("key",value);
startActivity(intent);

2. 向上一个Activity返回数据

Activity中还有一个startActivityForResult()方法也是用于启动Activity的,但是这个方法期望在下一个Activity销毁的时候能够返回一个结果给上一个Activity

startActivityForResult方法接收两个参数,第一个参数还是Intent,第二个参数是请求码(requestCode),用于在之后的回调函数中判断数据的来源。

1
2
3
// 启动
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivityForResult(intent, 1);
1
2
3
4
5
// 下一个Activity销毁之前
Intent intent = new Intent();
intent.putExtra("data","123");
setResult(RESULT_OK, intent);
finish()

在下一个Activity被销毁之后会调用上一个ActivityonActivityResult()方法,因此我们需要在上一个Activity中重写这个方法来得到返回的数据结果。

1
2
3
4
5
6
7
8
9
10
11
12
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
switch(requestCode){
case 1:
if(resultCode == RESULT_OK) {
String string = data.getStringExtra("data");
}
break;
case 2:
....
}
}

3. Activity与内嵌Fragment通信

3.1 Activity向Fragment发送数据

常见的就是使用Bundle来传递参数。

3.1.1 基础用法

Activity中,创建Fragment对象的时候,通过setArguments放入数据。

1
2
3
4
5
6
7
8
9
10
11
// 通过Bundle和setArguments向MessageFragment传递初始化数据
MessageFragment messageFragment = new MessageFragment();
Bundle bundle = new Bundle();
bundle.putString("name", "My name is Jack");
messageFragment.setArguments(bundle);

DisplayFragment displayFragment = new DisplayFragment();
fragmentTransaction = getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragment_1, messageFragment, null);
fragmentTransaction.commit();

Fragment初始化时通过getArguments取出数据。

1
2
3
4
5
6
7
8
9
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_message, container, false);

// 通过getArguments获取数据
String initStr = (String) getArguments().get("name");
...
return view;
}

3.1.2 扩展用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Activity代码
public class MainActivity extends AppCompatActivity implements MessageFragment.Listener {
private FragmentTransaction fragmentTransaction;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

if (findViewById(R.id.fragment_1) != null) {
if (savedInstanceState != null) {
return;
}
fragmentTransaction = getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_1, MessageFragment.getInstance("test"), null);
fragmentTransaction.commit();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Fragment代码
public class MessageFragment extends Fragment {
// 定义getInstance()静态方法
public static MessageFragment getInstance(String s){
MessageFragment messageFragment = new MessageFragment();
Bundle bundle = new Bundle();
bundle.putString("data",s);
messageFragment.setArguments(bundle);
return messageFragment;
}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_message, container, false);
String initStr = (String) getArguments().get("data");
return view;
}
}

3.2 Fragment向Activity返回数据

3.2.1 接口回调

Fragment中定义一个内部回调接口,再让包含该FragmentActivity实现该回调接口,这样Fragment即可调用该回调方法将数据传给Activity

Fragment添加到Activity中时,会调用Fragment的方法onAttach(),这个方法中适合检查Activity是否实现了Listener接口,检查方法就是对传入的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
// Fragment代码
public class MessageFragment extends Fragment {
private Listener listener;
private EditText editText;
private Button bFragment;
private Button bActivity;
private FragmentManager manager;

public MessageFragment() {
// Required empty public constructor
}

public interface Listener {
void show(String string);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_message, container, false);

// 向Activity返回数据
bActivity = view.findViewById(R.id.button2);
bActivity.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
listener.show(editText.getText().toString());
}
});
return view;
}

@Override
public void onAttach(Context context) {
super.onAttach(context);
if(context instanceof Listener) {
listener = ((Listener) context);
} else {
throw new IllegalArgumentException("Activity must implements Listener");
}
}

@Override
public void onDetach() {
super.onDetach();
listener = null;
}
}

在一个FragmentActivity中剥离的时候,就会调用onDetach方法,这个时候要把传递进来的Activity对象释放掉,不然会影响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
// Activity代码
public class MainActivity extends AppCompatActivity implements MessageFragment.Listener {
private FragmentTransaction fragmentTransaction;
private TextView textView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.top);

if (findViewById(R.id.fragment_1) != null) {
if (savedInstanceState != null) {
return;
}

MessageFragment messageFragment = new MessageFragment();
fragmentTransaction = getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragment_1, messageFragment, null);

fragmentTransaction.commit();
}
}

@Override
public void show(String string) {
textView.setText(string);
}
}

3.2.2 Handler方案

这种方法会使得Fragment对具体的Activity存在耦合,不利于Fragment复用不利于维护,若想删除相应的ActivityFragment也得改动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class MainActivity extends AppCompatActivity{ 
//声明一个Handler
public Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// ...相应的处理代码
}
};
}

public class MainFragment extends Fragment{
// 保存Activity传递的handler
private Handler mHandler;

@Override
public void onAttach(Context context) {
super.onAttach(context);
// 这个地方已经产生了耦合,若还有其他的activity,这个地方就得修改
mHandler = ((MainActivity)context).mHandler;
}
}

4. 同宿主的Fragment间通信

由于 Activity 持有所有内嵌的 Fragment 对象实例。(创建实例时保存的 Fragment 对象,或者通过 FragmentManager 类提供的findFragmentById()findFragmentByTag() 方法也能获取到 Fragment 对象),所以可以直接操作FragmentFragment 通过 getActivity() 方法可以获取到宿主 Activity 对象(强制转换类型即可),进而可以操作宿主 Activity;那么很自然的,获取到宿主 Activity 对象的 Fragment 便可以操作其他 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
public class MessageFragment extends Fragment {
private Listener listener;
private Button bFragment;
private FragmentManager manager;

public MessageFragment() {
// Required empty public constructor
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// onCreate时获取宿主的FragmentManager
manager = getFragmentManager();
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_message, container, false);

// 向另一个Fragment传递数据
bFragment = view.findViewById(R.id.button);
bFragment.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 通过manager.findFragmentByTag
DisplayFragment displayFragment = (DisplayFragment) manager.findFragmentByTag("bottom");
TextView textView = displayFragment.getView().findViewById(R.id.display);
textView.setText(editText.getText());
}
});

return view;
}
}

虽然上述操作已经能够解决 ActivityFragment 的通信问题,但会造成代码逻辑紊乱的结果,极度不符合 “高内聚,低耦合” 这一编程思想。Fragment 做好自己的事情即可,所有涉及到 Fragment 之间的控制显示等操作,都应交由宿主 Activity 来统一管理。

5. EventBus

EventBus是用反射机制实现的,性能上会有问题。使用EventBus实现组件间的通信主要分为3个步骤:

(1)定义事件模型对象;

1
2
3
4
5
6
7
8
9
10
// 定义事件对象
public class MessageEvent {
public String key;
public String value;

public MessageEvent(String key, String value) {
this.key = key;
this.value = value;
}
}

(2)添加事件订阅者;

1
EventBus.getDefault().register(DisplayFragment.this);

(3)当事件触发时,进行事件发布。

1
EventBus.getDefault().post(new MessageEvent("data", editText.getText().toString()));

详细例子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 添加订阅者
public class DisplayFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// 订阅事件
EventBus.getDefault().register(DisplayFragment.this);
return inflater.inflate(R.layout.fragment_display, container, false);
}

// 定义事件的处理函数
@Subscribe(threadMode = ThreadMode.MAIN)
public void messageEventBus(MessageEvent messageEvent) {
TextView textView = getView().findViewById(R.id.display);
textView.setText(messageEvent.value);
}

}
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
// 添加事件发布者
public class MessageFragment extends Fragment {
private Button bBus;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_message, container, false);
bBus = view.findViewById(R.id.button3);
return view;
}

@Override
public void onStart() {
super.onStart();

// 使用Event Bus
bBus.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 发布事件
EventBus.getDefault().post(new MessageEvent("key", "value"));
}
});
}

}

6. 更多

本文demo地址:>>>点我进入

Activity与Fragment通信方式:>>>点我进入

Android框架之路—EventBus的使用:>>>点我进入

EventBus官方Github地址:>>>点我进入

本文作者 : 冰比冰水冰
原文链接 : http://iceiceice.top/2019/08/30/android-communication/
版权声明 : 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!
留下足迹