安卓中的四大组件_Service

本文深入解析Android服务的概念及其生命周期,探讨服务与线程的区别,并详细介绍如何使用及调用服务,包括本地服务与远程服务的实现方法。

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

  • 服务是一个没有界面的Activity.
  • 特点:长期在后台运行, 不关乎界面的一些操作.比如: 网易新闻服务, 每隔1分钟服务会去请求网络,是否有最新新闻.

  • 进程中运行着线程, Android应用程序刚启动都会开启一个进程给这个程序来使用.

  • 和Thread有点相似. 但是不适用线程的原因是,使用Thread不安全, 不严谨 在Android中,一个应用程序把所有的界面关闭时, 进程这时还没有被销毁, 现在处于的是空进程状态. 而安卓中空进程是很容易被结束掉的(详细见进程的回收机制)。

  • 进程的回收进制.

    • 五种进程, 从低到高

      1. Foreground process 前台进程

      2. Visible process 可视进程, 可以看见, 但不可以交互.

      3. Service process 服务进程

      4. Background process 后台进程

      5. Empty process 空进程 当程序退出时, 进程没有被销毁, 而是变成了空进程.

    • 回收的顺序: 从低到高

      • 当系统内存不够用时, 就会把空进程回收了( 一个一个回收掉空进程,直到系统内存够用).
      • 当系统回收完所有的空进程还是不够用时, 则会继续向上回收后台进程, 依次类推.
    • 当回收: 服务, 可视, 前台这三种进程时, 系统非必要情况下不会轻易回收, 如果需要回收掉这三种进程, 在系统内存够用时, 会重新启动进程.

    • 对于服务进程:如果用户手动的关闭服务, 这时服务不会再重启了.

  • 为什么用服务, 而不用Thread? Thread运行在空进程中, 很容易的被销毁了. 服务不容易被销毁, 如果非法状态下非销毁了, 系统会在内存够用时, 重新启动.

  • 电话窃听器(当接通电话时开始录音, 挂断电话时停止录音).

    @Override
    public void onCreate() {
        super.onCreate();
        System.out.println("电话窃听服务开启了。。。");
    
        // 监听手机的通话状态
        TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
        tm.listen(new PhoneStateListener() {
    
            @Override
            public void onCallStateChanged(int state, String incomingNumber) {
                super.onCallStateChanged(state, incomingNumber);
                if (state == TelephonyManager.CALL_STATE_IDLE && isRecording) {
                    // 如果电话处于空闲状态,并且正在录音中,说明是刚刚挂断电话
                    // 8.停止录音
                    mr.stop();
                    // 9.释放资源
                    mr.release();
                    isRecording = false;
                } else if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
                    // 如果电话接通了,开始录音
                    // 1. 创建一个录音器
                    mr = new MediaRecorder();
                    // 2. 设置音频源来自麦克风
                    mr.setAudioSource(MediaRecorder.AudioSource.MIC);
                    // 3. 设置输出文件的格式
                    mr.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
                    // 4. 设置输出文件的名字
                    mr.setOutputFile(PATH);
                    // 5. 设置音频编码
                    mr.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
                    // 6. 准备, 马上要录音了
                    try {
                        mr.prepare();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    // 7. 开始录音
                    mr.start();
                    isRecording = true;
                }
            }
    
        }, PhoneStateListener.LISTEN_CALL_STATE);
    
    }
    
  • 服务生命周期

    • 开启方式, 特点: 把服务启动起来后, 就不关服务的事了.. activity和服务没有关系.

      • startService方法执行的时候, 服务的生命周期执行的过程: onCreate -> onStart/onStartCommand 服务正在运行中
      • stopService方法执行的时候, 服务的生命周期执行的过程: onDestory 服务销毁了
      • 使用startService方式开启的服务, 只能用stopService关闭服务.
    • 绑定方式, 特点: 不求同年同日生, 但求同年同日死.

      • bindService方法执行的时候, 服务的生命周期执行的过程: onCreate(如果服务创建了,就不再重新创建了) -> onBind
      • unbindService, 生命周期执行的过程: onUnbind -> onDestory
    • onRebind 方法, 只有在onUnbind方法返回true的情况下, 才会被调用.

  • Activity调用Android中的服务中的方法.

    • 使用绑定服务方式, 调用服务中的方法. (因为上下文是由系统底层提供的,因此不能直接new服务对象,如果要调用服务内部的方法,只能通过在服务中 自定义一个内部类,然后在这个内部类中提供调用服务内的方法,并将这个内部类对象通过onBind方法返回给调用者activity)

      • 本地服务调用

        1. 调用bindService绑定服务, 并且传递过去一个连接桥对象

        2. 在服务的类中定义一个内部类MyBinder继承Binder, 并且声明一个forwardBuyTicket方法, 在此方法中转调服务中的buyTicket方法.

        3. 在服务中的onBind方法中, 返回第二步定义的内部类MyBinder对象.

        4. 在Activity中的连接桥中实现onServiceConnected方法, 把IBinder service对象强转成服务中内部类对象MyBinder.

        5. 得到服务中内部类实例, 调用这个实例中的方法forwardBuyTicket. 此方法会转调服务中买票的方法buyTicket.

      • 远程服务调用(一个程序调用另一个程序的服务中的方法)

      • IPC(intel-process communication)机制, 通信
      • 原理基于: aidl(application interface define language) 应用接口声明语言, 不支持修饰词

      • 过程

        • 写服务类

          1. 定义一个接口文件, 声明一个forwardPayMoney方法, 把文件的后缀名修改为.aidl, 并且把修饰词(public等)去掉.

          2. 在服务中定义一个内部类MyBinder, 继承Stub类, 并且把抽象方法forwardPayMoney实现了.

          3. 在onBind方法中把第二步定义的内部类对象MyBinder返回.

        • 另一个程序的Activity

          1. 使用隐式的方式绑定服务, 传递过去一个连接桥对象.

          2. 把服务程序中的aidl文件拷贝当前工程中, 包名要保留一致.

          3. 在连接桥对象中的onServiceConnected方法中, 把IBinder对象转换成aidl接口对象

            mAlipayRemoteService = Stub.asInterface(service);
            
          4. 使用aidl接口对象, 调用接口中的抽象方法, 实际上会调用到远程服务中内部类中的forwardPayMoney方法.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值