1.基本概念
Service 是应用组件之一,用来执行需要长时间运行的操作,Service 运行在后台并且跟用户没有交互界面。
其他应用的组件可以启动一个Service,一旦启动起来,该Service就一直在后台运行,就算用户已经将该应用置为后台进程。
其他应用的组件也可以通过绑定的形式跟一个Service进行交互,甚至完成进程间通信
- Service的特点
1.Service 在Android中是一种长生命周期的组件,它不实现任何用户界面,是一个没有界面的Activity
2.Service 长期在后台运行,执行不关乎界面的一些操作比如:网易新闻服务,每隔1分钟去服务查看是否有最新新闻
3.Service 和Thread 有点相似,但是使用Thread 不安全,不严谨
4.Service 和其他组件一样,都是运行在主线程中,因此不能用它来做耗时的操作
2.Android中的进程
- 在Android 中进程优先级由高到低,依次分为:
1.Foreground process(前台进程)
2.Visible process(可见进程)
3.Service process(服务进程)
4.Background process(后台进程)
5.Empty process(空进程)
- 进程的回收机制
进程的回收顺序是:从低到高
1.当系统内存不够用时, 会把空进程一个一个回收掉
2.当系统回收所有的完空进程不够用时, 继续向上回收后台进程, 依次类推
3.面对服务进程、可视进程、前台进程时, 系统非必要情况下不会轻易回收
4.如果需要回收以上三种进程,在系统内存够用时,会再重新启动进程;但是服务进程如果用户手动的关闭服务, 这时服务不会再重启了
3. 使用service
1.服务是运行在后台的进程,跟我们熟悉的Thread很像
2.在使用Service 时一定要注意,Service默认运行在应用的主线程中,因此如果你需要在Service 中执行大量的或者阻塞(比如网络访问、IO等)的任务,那么依然需要在Service 中开启一个Thread 来完成这些工作
3.使用Service并不影响使用Thread,而且很多情形下,我们都是在Service中开启子Thread的混合使用方式
4.Code
- 自定义Service
/**
* 后台的服务 ,用来窃听电话
*/
public class PhoneService extends Service {
private TelephonyManager tm;//电话管理器
private MyPhoneListener listener;//监听器
private MediaRecorder mRecorder;//录音器
public IBinder onBind(Intent intent) {
return null;
}
//创建服务时
public void onCreate() {
//获取电话管理器
tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
listener = new MyPhoneListener();
//注册电话状态的监听器
tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
}
//自定义电话监听器
private class MyPhoneListener extends PhoneStateListener {
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
// 空闲状态,代表当前没有电话
case TelephonyManager.CALL_STATE_IDLE:
if(mRecorder!=null){
System.out.println("停止录音");
stopRecording();//停止录音方法
}
break;
// 响铃状态
case TelephonyManager.CALL_STATE_RINGING:
break;
// 通话状态
case TelephonyManager.CALL_STATE_OFFHOOK:
System.out.println("通话状态,开启录音机,录音.");
startRecording();//开始录音方法
break;
}
}
}
//销毁服务时
public void onDestroy() {
//注销电话状态的监听
tm.listen(listener, PhoneStateListener.LISTEN_NONE);
super.onDestroy();
}
//开始录音的方法
private void startRecording() {
mRecorder = new MediaRecorder();
//设置声音来源,从麦克风录音
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//设置输出格式为3gp
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
//设置输出到的文件
mRecorder.setOutputFile("/mnt/sdcard/"+SystemClock.uptimeMillis()+".3gp");
//设置输出的音频编码
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
try {
mRecorder.prepare();//录音器准备
} catch (Exception e) {
System.out.println("prepare() failed");
}
mRecorder.start();//开启
}
//停止录音的方法
private void stopRecording() {
mRecorder.stop();
//释放录音器资源
mRecorder.release();
mRecorder = null;
}
}
- 启动Service
startService 或 bindService两种启动方式
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void start(View view){
//创建一个Intent 对象
Intent intent = new Intent(this,PhoneService.class);
//启动服务
startService(intent);
}
}
- AndroidManifest.xml中注册
//保存录音文件到sdcard、监听电话状态、录音都需要添加权限
<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"/>
//注册Service:
<service android:name="com.demo.phonelistener.PhoneService" >
</service>
5.Service的生命周期
-
Service有生命周期,Service的生命周期,从它被创建开始,到它被销毁为止,可以有两条不同的路径:标准开启模式和绑定模式
-
started service(标准开启模式)
1.被开启的service 通过其他组件调用startService()被创建
2.这种service 可以无限地运行下去,必须调用stopSelf()方法或者其他组件调用stopService()方法来停止它
3.当service 被停止时,系统会销毁它
- bound service(绑定模式)
1.被绑定的service是当其他组件(一个客户)调用bindService()来创建的
2.客户可以通过一个IBinder接口和service 进行通信
3.客户可以通过unbindService()方法来关闭这种连接
4.一个service 可以同时和多个客户绑定,当多个客户都解除绑定之后,系统会销毁service
- 任何Service 都潜在地允许被绑定
- 一个被开启的Service仍然可能被绑定
6.AIDL实现进程间通信
1.Android 采用了一种轻量级的实现方式RPC(Remote Procedure Call 远程进程调用)来完成进程之间的通信
2.Android 通过接口定义语言(Android Interface Definition Language ,AIDL)来生成两个进程之间相互访问的代码
3.AIDL 是Android 的一种接口描述语言,编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的
-
aidl的使用步骤
-
service端
//1.远程服务定义的接口文件不能是.java文件,需要改成.aidl文件,里面的修饰符都不需要
package com.demo.remote;
interface IService {
void callMethodInService();
}
//2.程序会自动在gen目录下生成Iservice.java文件,会有一个抽象的静态类Stub继承了Binder对象并实现了IService接口
//3.创建服务,在服务中创建中间代理人对象,在onBind()方法中返回出去给绑定该服务的对象使用。
public class RemoteService extends Service {
/**中间代理人*/
private class MyBinder extends IService.Stub{
public void callMethodInService() {
//调用服务里面的方法
methodInService();
}
}
public IBinder onBind(Intent intent) {
//返回中间代理人
return new MyBinder();
}
public void onCreate() {
System.out.println("远程服务被创建了...");
super.onCreate();
}
public void onDestroy() {
System.out.println("远程服务被销毁了...");
super.onDestroy();
}
//服务里面的方法
public void methodInService(){
System.out.println("我是远程服务的方法,我被调用了....");
}
}
- 调用者端
public class MainActivity extends Activity {
private MyConn conn;
private IService iService;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void bind(View view){
Intent intent = new Intent();
//调用远程服务 :隐式意图
intent.setAction("com.demo.remote");
conn = new MyConn();
bindService(intent, conn, BIND_AUTO_CREATE);
}
private class MyConn implements ServiceConnection{
public void onServiceConnected(ComponentName name, IBinder service) {
//得到远程服务的代理对象
iService = IService.Stub.asInterface(service);
}
public void onServiceDisconnected(ComponentName name) {
}
}
public void call(View view){
try {
//通过代理对象调用远程服务的方法
iService.callMethodInService();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
网友评论