安卓中本地服务Service和远程服务AIDL的使用

安卓本地服务Service和远程服务AIDL的使用

服务是安卓四大组件之一,是一个运行在后台的组件,完成某些特定的任务。
关于服务的概念,这里就不啰嗦了。

一.本地服务:一个应用程序内部的服务。

本地服务有两种调用的方式:

  • 一种是startService:开启服务
  • 一种是bindService:绑定服务
1.startService方式 使用步骤:

1.先声明一个类继承Service类:重写onCreate() onStartCommand()
onDestory()等生命周期方法。

 注:onStart()方法已经被onStartCommand()方法替代
     另外生命周期方法是根据业务需求,重写需要的方法,不是必须重写的。

     下面代码利用服务完成了在后台对电话状态的监听,当打电话时,
     会录音,并将录音文件存放在sd卡根目录。有兴趣,后面附有源
     码,可以下载运行。   注意:运行时加上相关权限
<!-- 读取电话状态的权限(示例代码中用到的权限) -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <!-- 写sd卡和录音的权限 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
public class MyService extends Service {

    private TelephonyManager telManager;
    private MediaRecorder recorder;
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        System.out.println("开始创建服务");
        //服务中要处理的业务
        telManager = (TelephonyManager) getApplicationContext().getSystemService(TELEPHONY_SERVICE);
        telManager.listen(new MyListener(), PhoneStateListener.LISTEN_CALL_STATE);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("接收到开启服务的命令");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        System.out.println("服务销毁");
        super.onDestroy();
    }

    //电话状态的监听器,进行电话录音
    class MyListener extends PhoneStateListener{
        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            switch (state) {
            case TelephonyManager.CALL_STATE_IDLE://电话空闲状态
                if(recorder!=null){
                    //8.结束录音
                    recorder.stop();
                    //9.释放资源
                    recorder.release();
                }
                break;
            case TelephonyManager.CALL_STATE_RINGING://响铃状态
                System.out.println("正在响铃");
                break;

            case TelephonyManager.CALL_STATE_OFFHOOK://通话中
                //录音

                try {
                    //1.创建录音对象实例
                    recorder = new MediaRecorder();
                    // 2.设置声音源
                    recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                    //3.设置输出文件的格式
                    recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
                    //4.设置输出文件的名称
                    File file = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis()+".3gp");
                    recorder.setOutputFile(file.getAbsolutePath());
                    //5.设置录音的编码方式
                    recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
                    //6.准备录音
                    recorder.prepare();
                    //7.开始录音
                    recorder.start();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }

}

2.在Activity中开启服务。开启方法很简单,和启动Activity类似.

// 开启服务代码
Intent intent = new Intent(MainActivity.this, MyService.class);
startService(intent);

// 停止服务代码
Intent intent2 = new Intent(MainActivity.this, MyService.class);
stopService(intent2);
2.bindService 使用步骤:

1.和上面一样,先声明一个类继承Service类,大家会发现,自动会实现一个方法 onBind()方法,很显然,google是推荐我们使用绑定服务的方式的。为什么?

  • 绑定服务后可以调用服务里面的方法,因为服务就是为我们的程序服务的
    如果不能产生关联,会失去服务的的作用。
public class MyBindService extends Service {

    /**
     * 1.绑定成功后,会返回绑定者一个Binder对象,利用这个对象,调用者就可以调用服务中的一些业务逻辑 2.例如
     * 本服务中有一个方法MehtodInService,由于这个方法是private私有的,其他类无法调用,
     * 如果在Binder中调用,当绑定服务者拿到Binder对象时,就可以间接调用服务里的方法。
     * 
     * 3.因此定义一个MyBinder继承IBinder的实现类,在里面调用MethodInService
     * 4.但是如果一旦将MyBinder对象返回给服务绑定者,selfMethod这个方法也会被调用到,而这是我们不希望的。
     * 因此我们抽取一个借口,让MyBinder实现,返回给服务绑定者一个借口类型。而接口中只定义我们想暴露的方法。
     *  然后在成功绑定的方法中
     */
    @Override
    public IBinder onBind(Intent intent) {
        System.out.println("onBind方法");
        return new MyBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        System.out.println("onUnbind方法");
        return super.onUnbind(intent);
    }

    @Override
    public void onCreate() {
        System.out.println("onCreate方法");
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("onStartCommand方法");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        System.out.println("onDestroy方法");
        super.onDestroy();
    }

    /**
     * 服务中的一个方法
     */
    private void MethodInService() {
        System.out.println("绑定服务中的方法");
    }

    // 1.利用继承IBinder的一个直接实现类,来处理要给调用者暴露方法让其调用
    class MyBinder extends Binder implements IMyBinder {

        // 调用服务中的方法
        @Override
        public void callMethodInService() {
            MethodInService();
        }

        // 另一个方法
        public void selfMethod() {
            System.out.println("一个核心的方法,是服务内部的一个方法,不希望让服务绑定者调用到");
        }

    }
}
面向接口编程,抽取接口类
public interface IMyBinder {
    public void callMethodInService();
}

2.在MainActivity中绑定服务

//绑定服务代码
Intent intent3 = new Intent(MainActivity.this, MyBindService.class);
conn = new MyConn();
bindService(intent3, conn, BIND_AUTO_CREATE);

//解除绑定服务代码
unbindService(conn);
 绑定回调接口:这个是上面绑定时必须的参数
// 成功绑定后处理的回单接口
    class MyConn implements ServiceConnection {

        // 服务成功绑定后回调
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 得到绑定后返回的Binder对象
            binder = (IMyBinder) service;
            System.out.println("成功绑定服务");
            binder.callMethodInService();
        }

        // 解除绑定后回调
        @Override
        public void onServiceDisconnected(ComponentName name) {

        }

    }

二.远程服务:调用其他应用程序提供的服务

1.先创建一个工程作为远程服务的提供者,和上面一样,先创建一个服务,并且创建一个接口类,不同于前面本地服务的是,这个接口需要把后缀改为 aidl, 然后该远程服务的写法如下 。

注:和写本地服务的不同点

   - 接口文件要改后缀为aidl,该aidl文件会自动在gen目录下自动生成接口
   - 该服务返回的Binder对象,是要继承刚才自动生成接口的的内部类Stub
   - 该服务需要配置一个意图过滤器,<intent-filter><intent-filter/>
//远程服务在配置时需配置意图过滤器,因为在其他程序中需要通过隐式意图访问
  <service android:name="com.demo.remoteservice.MyRomoteBindService">
            <intent-filter>
                <action android:name="com.demo.remoteservice.MyRomoteBindService"/>
            </intent-filter>
        </service>
//.aidl文件内容,需要去掉接口中的访问修饰符
interface IRemoteBinder {
     void callMethodInService();
}
远程服务代码
public class MyRomoteBindService extends Service {


    @Override
    public IBinder onBind(Intent intent) {
        System.out.println("远程服务被绑定");
        return new MyBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        System.out.println("远程服务被解除绑定");
        return super.onUnbind(intent);
    }

    @Override
    public void onCreate() {
        System.out.println("远程服务被创建");
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        System.out.println("远程服务被销毁");
        super.onDestroy();
    }


    /**
     * 远程服务中的一个方法
     */
    private void MethodInService() {
        System.out.println("远程服务中的方法");
    }

    // 此时需要实现自动生成的服务接口的内部类
    class MyBinder extends IRemoteBinder.Stub {

        // 调用服务中的方法
        @Override
        public void callMethodInService() {
            MethodInService();
        }

    }
}

2.在另一个工程中调用该远程服务:

  • 步骤:
  • 1.在该工程中新建一个和远程服务类所在工程一样结果的包
  • 2.将远程服务工程中的接口文件 (.aidl文件)拷贝到该新建的包下
  • 3.绑定远程服务

    注:绑定远程服务时,回调接口里的代码和绑定本地服务略有不同。需要调用
        IRemoteBinder.Stub.asInterface(service);获取Binder对象
    详情见代码
    
// 绑定远程服务
// 需要用隐式意图
Intent intent4 = new Intent();
intent4.setAction("com.demo.remoteservice.MyRomoteBindService");
remoteConn = new MyRemoteConn();
bindService(intent4, remoteConn, BIND_AUTO_CREATE);

// 解除绑定远程服务
unbindService(remoteConn);
回调类MyRemoteConn
//绑定远程服务的回调接口
    class MyRemoteConn implements ServiceConnection {
        // 服务成功绑定后回调
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            try {
                // 绑定远程服务,得到绑定后返回的Binder对象
                remoteBinder = IRemoteBinder.Stub.asInterface(service);
                remoteBinder.callMethodInService();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        // 解除绑定后回调
        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }
我博客资源下载部分可以下载该示例工程
附有两个工程,一个工程中示范了本地服务中start方式调用服务和绑定
服务,以及绑定远程服务的示例,另一个工程师远程服务的提供者
主界面如图

这里写图片描述

小结

  • start方式开启服务,开启之后,服务和开启者就没有关系。
    生命周期为: onCreate()——》OnStartCommand()——》OnDestroy()
    当多次开启时,服务只会被创建一次,下次会直接调用onStartCommand()方法

  • 通过bind绑定服务(包括绑定远程服务),绑定者可以通过接口调用服务里的方法。
    生命周期为 : onCreate()——》onBind()——》onUnbind()——》onDestroy()
    当多次开启时,服务只会被创建一次,下次会直接调用onBind()方法

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值