Android中的组件通信

本文详细探讨了Android中Activity、Fragment、Service之间的通信方式。包括Activity间的Intent与BroadcastReceiver通信,Activity与Fragment通过构造函数、获取实例及接口回调的交互,Activity与Service的startService()与bindService()用法,Fragment之间的共享ViewModel和通过Activity中转的通信策略,以及Service的双向通信与广播发送。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、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()发送广播

四、参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值