服务
- 就是默默运行在后台的组件,可以理解为是没有前台的activity,适合用来运行不需要前台界面的代码
- 服务可以被手动关闭,不会重启,但是如果被自动关闭,内存充足就会重启
下载代码和播放音乐这种运行于后台的代码,必须要写在服务里面。
为什么呢?例如下载:
activity 其实也是可以在后台下载,但是,点返回键的时候,activity死掉了(activity被onDestory()不代表该APP进程会被销毁),进程还在,那么子线程就依然可以下载,但当进程被销毁的时候,下载就会中断了。那进程什么时候销毁呢?在内存不足的时候进程就会很有可能被销毁…这时候就会涉及到进程优先级的知识。
进程优先级
- 前台进程:拥有前台activity(onResume方法被调用)
- 可见进程:拥有可见activity(onPause方法被调用)
- 服务进程:不到万不得已不会被回收,而且即便被回收,内存充足时也会被重启
- 后台进程:拥有后台activity(activity的onStop方法被调用了),很容易被回收
- 空进程:没有运行任何activity,很容易被回收
服务:开启方式
1.Context.startService()
- (重点)该方法启动的服务所在的进程属于服务进程
- Activity一旦启动服务,服务就跟Activity一毛钱关系也没有了
-
不论调用了多少次startService()方法,你只需要调用一次stopService()来停止服务。
-
在需要开启服务的Activity中:
Intent intent = new Intent(this, MyService.class);
startService(intent);//开启
stopService(intent);//关闭
2.Context.bindService()
- (重点)该方法启动的服务所在进程不属于服务进程
- Activity与服务建立连接,Activity一旦死亡,服务也会死亡
*在需要开启服务的Activity中:
Intent intent = new Intent(this, MyService.class);
MyServiceConn conn = new MyServiceConn();
bindService(intent, conn, BIND_AUTO_CREATE);
class MyServiceConn implements ServiceConnection{ //内部类,服务链接对象
//连接服务成功,此方法调用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
pb = (PublicBusiness) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
}
MyService类内容:
public class MyService extends Service {
//绑定时调用
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
System.out.println("bind方法");
return null;
}
//解绑时调用
@Override
public boolean onUnbind(Intent intent) {
// TODO Auto-generated method stub
System.out.println("unbind方法");
return super.onUnbind(intent);
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
System.out.println("create方法");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
System.out.println("start方法");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
System.out.println("destroy方法");
super.onDestroy();
}
}
生命周期
1.ContextstartService启动服务的生命周期
onCreate()->onStartCommand()->onDestroy()
- 重复的调用Context.startService()会导致onStartCommand()被重复调用,而onCreate()只会被调用一次
2.Context.bindService()绑定服务的生命周期
onCreate()->onBind()->onUnbind() -> onDestroy()
- 重复的调用Context.bindService(),只会走一次onCreate()->onBind()。同时也不能重复地解绑,启动后,只能解绑一次。
服务的混合调用(重点)
-
先startService()、再bindService(),先解绑、再停止,比如:用服务实现音乐播放时,因为音乐播放必须运行在服务进程中,可是音乐服务中的方法,需要被前台Activity所调用,所以需要混合启动音乐服务先start,再bind,销毁时先unbind,再stop
onCreate()->onStartCommand()->onBind()->onUnbind()-> onDestroy()
服务运行在主线程
Service和其他的应用组件一样,运行在进程的主线程中。这就是说如果service需要很多耗时或者阻塞的操作,需要在其子线程中实现。
找领导办证(访问服务里面的方法)
- 把服务看成一个领导,服务中有一个banZheng方法,如何才能访问?
-
绑定服务时,会触发服务的onBind方法,此方法会返回一个Ibinder的对象给MainActivity,通过这个对象访问服务中的方法
-
在服务中定义一个类实现Ibinder接口,以在onBind方法中返回
class ZhongJianRen extends Binder implements PublicBusiness{
public void QianXian(){
//访问服务中的banZheng方法
BanZheng();
}
public void daMaJiang(){
}
}
public class MainActivity extends Activity {
private Intent intent;
private MyServiceConn conn;
PublicBusiness pb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent(this, LeaderService.class);
//绑定服务时要求传入一个ServiceConnection实现类的对象
conn = new MyServiceConn();
//1.绑定领导服务
bindService(intent, conn, BIND_AUTO_CREATE);
}
//2.内部类,服务链接对象
class MyServiceConn implements ServiceConnection{
//连接服务成功,此方法调用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//5. TODO Auto-generated method stub
pb = (PublicBusiness) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
}
public void click(View v){
//调用服务的办证方法
pb.QianXian();
}
}
LeaderService服务类:
public class LeaderService extends Service {
@Override
public IBinder onBind(Intent intent) {
//3. 返回一个Binder对象,这个对象就是中间人对象
return new ZhouMi();
}
//4.在服务中定义一个类实现Ibinder接口,以在onBind方法中返回
class ZhouMi extends Binder implements PublicBusiness{
public void QianXian(){
banZheng();
}
public void daMaJiang(){
System.out.println("陪李处打麻将");
}
}
public void banZheng(){
System.out.println("李处帮你来办证");
}
}
把QianXian方法抽取到接口PublicBusiness中定义
public interface PublicBusiness {
void QianXian();
}
服务的分类
- 本地服务:指的是服务和启动服务的activity在同一个进程中
- 远程服务:指的是服务和启动服务的activity不在同一个进程中
AIDL
- Android interface definition language
- 进程间通信
- 把远程服务的方法抽取成一个单独的接口java文件
- 把接口java文件的后缀名改成aidl
- 在自动生成的PublicBusiness.java文件中,有一个静态抽象类Stub,它已经继承了binder类,实现了publicBusiness接口,这个类就是新的中间人(继承的时候直接:中间人类名Stub)
- 把aidl文件复制粘贴到06项目,粘贴的时候注意,aidl文件所在的包名必须跟05项目中aidl所在的包名一致
- 在06项目中,ServiceConnection对象链接类中的onServiceConnected()方法中强转中间人对象得到中间人对象:mService = IMusicService.Stub.asInterface(serviceIBinder);