服务
- Service
- 四大组件之一
- 运行于后台,没有前台界面的组件,用于运行需要在后台运行的代码
- 可以理解为没有前台的Activity
- 定义方式:创建java类继承Service,清单文件中注册该类
服务的启动
- 用户手动停止服务,服务不会重启
生命周期
- onCreate->onStartCommand->onDestroy
- 重复的startService不会调用onCreate只会重复调用onStartCommand
进程优先级
- 前台进程:拥有一个正在与用户交互的Activity(onResume方法调用)
- 可见进程:拥有一个不在前台但是对用户依然可见的Activity(onPause方法调用)
- 服务进程:拥有一个通过startService启动的服务
- 后台进程:拥有一个对于用户不可见的Activity(onStop方法调用)
- 空进程:没有任何活动的应用组件(Activity和Service)
通话录音机
电话状态
- 空闲
- 响铃
- 摘机
Service
- 就是默默运行在后台的组件,可以理解为是没有前台的activity,适合用来运行不需要前台界面的代码,比如 下载功能,如果开线程下载,手机内存不足时系统会杀死进程,从而下载就不进行了,应改为服务
- 服务可以被手动关闭,不会重启,但是如果被自动关闭,内存充足就会重启
- startService启动服务的生命周期
- onCreate-onStartCommand-onDestroy
- 重复的调用startService会导致onStartCommand被重复调用
启动关闭服务
清单
<service android:name="com.itheima.runservice.MyService"></service>
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void start(View v){
//启动服务
Intent intent = new Intent(this, MyService.class);
startService(intent);
}
public void stop(View v){
//停止服务
Intent intent = new Intent(this, MyService.class);
stopService(intent);
}
}
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
System.out.println("bind");
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("start");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onCreate() {
System.out.println("create");
super.onCreate();
}
@Override
public void onDestroy() {
System.out.println("destroy");
super.onDestroy();
}
}
服务两种启动方式
- startService
- 开始服务,会使进程变成为服务进程
- 启动服务的activity和服务不再有一毛钱关系
- bindService
- 绑定服务不会使进程变成服务进程
- 绑定服务,是activity与服务建立连接,如果activity销毁了,服务也会被解绑并销毁,但是如果服务被销毁,activity不会被销毁
- 绑定服务和解绑服务的生命周期方法:onCreate->onBind->onUnbind->onDestroy
办证示例
- 把服务看成一个领导,服务中有一个banZheng方法,如何才能访问?
- 绑定服务时,会触发服务的onBind方法,此方法会返回一个Ibinder的对象给MainActivity,通过这个对象访问服务中的方法
绑定服务
Intent intent = new Intent(this, BanZhengService.class); bindService(intent, conn, BIND_AUTO_CREATE);
绑定服务时要求传入一个ServiceConnection实现类的对象
- 定义这个实现类
class MyServiceconn implements ServiceConnection{
//onBind有返回值此方法才会调用
//service:这个对象就是onBind返回的中间人
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
zjr = (PublicBusiness) service;
}
//连接因为异常而终止才会调用
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
创建实现类对象
conn = new MyServiceconn();
在服务中定义一个类实现Ibinder接口,以在onBind方法中返回
class ZhongJianRen extends Binder implements PublicBusiness{
public void QianXian(){
//访问服务中的banZheng方法
BanZheng();
}
public void daMaJiang(){
}
}
- 把QianXian方法抽取到接口PublicBusiness中定义
两种启动方法混合使用
- 用服务实现音乐播放时,因为音乐播放必须运行在服务进程中,可是音乐服务中的方法,需要被前台Activity所调用,所以需要混合启动音乐服务
- 先start,再bind,销毁时先unbind,在stop
使用服务注册广播接收者
- Android四大组件都要在清单文件中注册
- 广播接收者可以使用清单文件注册
- 一旦应用部署,广播接收者就生效了,直到用户手动停止应用或者应用被删除
- 广播接收者可以使用代码注册
- 需要广播接收者运行时,使用代码注册,不需要时,可以使用代码解除注册
电量改变、屏幕开关,必须使用代码注册
注册广播接收者
//创建广播接收者对象 receiver = new ScreenOnOffReceiver(); //通过IntentFilter对象指定广播接收者接收什么类型的广播 IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_SCREEN_ON); //注册广播接收者 registerReceiver(receiver, filter);
解除注册广播接收者
unregisterReceiver(receiver);
- 解除注册之后,广播接收者将失去作用
本地服务:服务和启动它的组件在同一个进程
远程服务:服务和启动它的组件不在同一个进程(不在同一应用)
- 远程服务只能隐式启动,类似隐式启动Activity,在清单文件中配置Service标签时,必须配置intent-filter子节点,并指定action子节点
AIDL
- Android interface definition language
- 安卓接口定义语言
- 作用:跨进程通信
- 应用场景:远程服务中的中间人对象,其他应用是拿不到的,那么在通过绑定服务获取中间人对象时,就无法强制转换,使用aidl,就可以在其他应用中拿到中间人类所实现的接口
步骤
修改 05远程服务
- 把接口文件的后缀名改成aidl
- aidl文件中所有东西都是public的,不需要也不能自己定义访问修饰符
- 中间人对象继承Stub,这个对象已经继承了Binder并实现了PublicBusiness接口
class FengMiShu extends Stub{
@Override
public void qianXian() {
// TODO Auto-generated method stub
remoteBanZheng();
}
}
修改 06启动远程服务
- 把05项目的aidl文件复制到06项目,然后aidl所在的包名06和05项目必须一致
- 把06项目获取到的中间人对象使用Stub.asInterface强转
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
pb = Stub.asInterface(service);
}
服务可能被用户停止,或被其他软件停止,这时调用服务的话要判断服务是否运行