服务是安卓四大组件之一,是一个运行在后台的组件,完成某些特定的任务。
关于服务的概念,这里就不啰嗦了。
本地服务有两种调用的方式:
1.先声明一个类继承Service类:重写onCreate() onStartCommand()
onDestory()等生命周期方法。
注:onStart()方法已经被onStartCommand()方法替代
另外生命周期方法是根据业务需求,重写需要的方法,不是必须重写的。
下面代码利用服务完成了在后台对电话状态的监听,当打电话时,
会录音,并将录音文件存放在sd卡根目录。有兴趣,后面附有源
码,可以下载运行。 注意:运行时加上相关权限
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<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);
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
- 该服务需要配置一个意图过滤器,
//远程服务在配置时需配置意图过滤器,因为在其他程序中需要通过隐式意图访问
<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.在另一个工程中调用该远程服务:
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()方法