一、Activity
(一)、Activity与Activity通信
1. Intent 和 Bundle(单向传递)
- startActivity(Intent intent, Bundle bundle)
- startActivityForResult(Intent intent, int requestCode, Bundle bundle) + setResult(int resultCode, Intent data)
其中的Intent包含:
(1)、隐式Intent
隐含 Intent 不声明要启动的组件的类名称,而是声明要执行的操作。
//发起电话呼叫
Uri number = Uri.parse("tel:5551234");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);
(2)、显式Intent
2. BroadcastReceiver(可双向通信)
Broadcast分类:
- Normal Broadcast(普通广播)
是完全异步接收,逻辑上是同一时刻被所有接收者收到,消息传递效率高。缺点:接收者不能将处理结果传递到下一个接收者,并且无法终止Broadcast Intent的传播
- Ordered Broadcase(有序广播)
接收者按预先声明的优先级依次接收Broadcast。可通过在BroadcastReceiver中setResultExtras(Bundle)保存结果继续传播;也可调用abortBroadcast();终止Broadcast继续传播。其中优先级设置:
- 通过
(二)、Activity与Fragment通信
1. Fragment构造函数传递(单向传递)
getSupportFragmentManager().beginTransaction()
.add(CustFragment.newInstance(自定义参数列表))
2. 获取Fragment实例对象(双向通信)
- 通过Fragment的Id获取实例
getSupportFragmentManager().findFragmentById(R.id.headlines_fragment);
- 通过Fragment的Tag获取实例
getSupportFragmentManager().findFragmentByTag("HeadLines");
(三)、Activity与Service通信
1. startService()(单向传递)
因为此函数的原型为Context.startService(Intent service);
,所以依靠Intent,可以在创建Service的时候传递一些小数据,且是单向传递数据。在Service的onStartCommand()
方法中可以拿到作为参数传进去的Intent数据。
2. bindService() (双向通信)
如果Activity与Service需要进行方法调用或交换数据,则应该使用bindService()和unbindService()方法启动、关闭Service。
- 在Service中创建IBinder对象,并在onBind()方法中返回
public class BindService extends Service
{
private int count;
private boolean quit;
// 定义onBinder方法所返回的对象
private MyBinder binder = new MyBinder();
// 通过继承Binder来实现IBinder类
public class MyBinder extends Binder
{
public int getCount()
{
// 获取Service的运行状态:count
return count;
}
}
// 必须实现的方法,绑定该Service时回调该方法
@Override
public IBinder onBind(Intent intent)
{
System.out.println("Service is Binded");
// 返回IBinder对象
return binder;
}
// Service被创建时回调该方法
@Override
public void onCreate()
{
super.onCreate();
System.out.println("Service is Created");
// 启动一条线程,动态地修改count状态值
new Thread()
{
@Override
public void run()
{
while (!quit)
{
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
}
count++;
}
}
}.start();
}
// Service被断开连接时回调该方法
@Override
public boolean onUnbind(Intent intent)
{
System.out.println("Service is Unbinded");
return true;
}
// Service被关闭之前回调该方法
@Override
public void onDestroy()
{
super.onDestroy();
this.quit = true;
System.out.println("Service is Destroyed");
}
}
Activity在bindService时传入创建的ServiceConnection对象,并重写
onServiceConnected()
和onServiceDisconnected()
方法,在onServiceConnected()
方法中能从参数中获取IBinder对象,此对象可访问Service内部数据,从而实现Activity与Service之间的通信。public class MainActivity extends Activity { Button bind, unbind, getServiceStatus; // 保持所启动的Service的IBinder对象 BindService.MyBinder binder; // 定义一个ServiceConnection对象 private ServiceConnection conn = new ServiceConnection() { // 当该Activity与Service连接成功时回调该方法 @Override public void onServiceConnected(ComponentName name , IBinder service) { System.out.println("--Service Connected--"); // 获取Service的onBind方法所返回的MyBinder对象 binder = (BindService.MyBinder) service; // ① } // 当该Activity与Service断开连接时回调该方法 @Override public void onServiceDisconnected(ComponentName name) { System.out.println("--Service Disconnected--"); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 获取程序界面中的start、stop、getServiceStatus按钮 bind = (Button) findViewById(R.id.bind); unbind = (Button) findViewById(R.id.unbind); getServiceStatus = (Button) findViewById(R.id.getServiceStatus); // 创建启动Service的Intent final Intent intent = new Intent(this, BindService.class); bind.setOnClickListener(new OnClickListener() { @Override public void onClick(View source) { // 绑定指定Service bindService(intent, conn, Service.BIND_AUTO_CREATE); } }); unbind.setOnClickListener(new OnClickListener() { @Override public void onClick(View source) { // 解除绑定Service unbindService(conn); } }); getServiceStatus.setOnClickListener(new OnClickListener() { @Override public void onClick(View source) { // 获取、并显示Service的count值 Toast.makeText(MainActivity.this, "Service的count值为:" + binder.getCount(), Toast.LENGTH_SHORT).show(); // ② } }); } }
(四)、Activity与BroadcastReceiver通信
1. startService()
中Intent传递,onReceive()
接收
二、Fragment
(一)、Fragment之间的通信
此处引用Google Developers的文档内容,取自链接
通常,您会希望一个Fragment与另一个Fragment进行通信,例如根据用户事件更改内容。所有Fragment到Fragment的通信都是通过共享 ViewModel或通过关联的Activity完成的。两个Fragment不应该直接通信。
如果您无法使用共享ViewModel在Fragments之间进行通信,则可以使用接口手动实现通信流。然而,这最终需要更多的工作来实现,并且在其他Fragment中不容易重复使用。
由此得出Fragment之间可以通过两种方式实现通信:
1. 共享ViewModel
2. 关联Activity
此处引用例子
用户在一个Fragment中选择列表中的一个item,另一个Fragment显示所选item的内容,两个Fragment都需要定义一些接口描述并且Activity必须将两者绑定在一起。且两Fragment都需要处理未创建或可见其他Fragment的情况
以下根据这个例子,用两种方式解决此问题
1. 共享ViewModel
。使用ViewModel就解决了这些痛点。
public class SharedViewModel extends ViewModel {
private final MutableLiveData<Item> selected = new MutableLiveData<Item>();
public void select(Item item) {
selected.setValue(item);
}
public LiveData<Item> getSelected() {
return selected;
}
}
public class MasterFragment extends Fragment {
private SharedViewModel model;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item); //向ViewModel传递选择item的信息
});
}
}
public class DetailFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, item -> { //ViewModel观察数据的变化,以传递到此Fragment
// Update the UI.
});
}
}
优点:
- 活动不需要做任何事情,也不需要了解这种通信的内容。
- Fragment无需了解SharedViewModel内部通信细节。如果其中一个Fragment消失,另一个Fragment继续照常工作。
- 每个Fragment都有自己的生命周期,不受另一个Fragment的生命周期的影响。如果一个Fragment替换另一个Fragment,则UI继续工作而没有任何问题。
2. 关联Activity
1. 定义一个接口
Fragment在其onAttach()生命周期方法中捕获接口实现,然后调用接口方法与Activity通信
public class HeadlinesFragment extends ListFragment {
OnHeadlineSelectedListener mCallback;
// Container Activity must implement this interface
public interface OnHeadlineSelectedListener {
public void onArticleSelected(int position);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// 在这里确认容器Activity是否实现了该回调接口,如果没实现,此处抛出异常
try {
mCallback = (OnHeadlineSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnHeadlineSelectedListener");
}
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
// 此时发送点击事件到所关联的Activity中
mCallback.onArticleSelected(position);
}
}
2. 实现接口
为了接收Fragment的事件回调,该关联的Activity必须实现Fragment中定义的接口
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener{
...
public void onArticleSelected(int position) {
// 接收到Fragment传来的点击事件
// 把数据显示出来
}
}
3. 把数据传到另一个Fragment中
关联的Activity可以通过使用findFragmentById()获取到Fragment实例来将消息传递到Fragment中,然后调用Fragment的public方法
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener{
...
public void onArticleSelected(int position) {
// 接收到Fragment传来的点击事件
// 把数据显示出来
ArticleFragment articleFrag = (ArticleFragment)
getSupportFragmentManager().findFragmentById(R.id.article_fragment); //获取显示文章的Fragment实例
if (articleFrag != null) {
// 如果用于显示文章内容的Fragment存在,则直接显示即可
// 调用显示文章的Fragment公共方法传递信息
articleFrag.updateArticleView(position);
} else {
// 另外,如果我们的页面是单页面(用于显示文章内容的Fragment暂时没创建),则此处创建一个实例显示
// 创建一个Fragment并给予选择item信息作为参数
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// 如果当前容器中存在另一个Fragment,使用替换原有的Fragment来显示,
// 把当前替换的事务加入到返回栈中,然后用户可以通过返回键恢复原来显示的Fragment
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// 提交事务
transaction.commit();
}
}
}
(二)、Fragment与Activity通信
1. 通过getActivity()
获取实例传递
2. 通过接口回调进行通信
详细步骤如以上Fragment之间的通信的“2.关联Activity”部分定义接口进行
三、Service
1. bindService()
与Activity双向通信
2. sendBroadcast()
发送广播
四、参考资料
- Google Developers
- 《疯狂Android讲义》 —— 李刚