服务(Service)

概述

进程 :进程是一个应用程序运行的载体。在Android中,进程的底层是Linux管理的。Android中应用启动的一般过程为:Linux系统创建一个进程(pid),进程里运行dvm,dvm里运行这个应用
应用程序
一个应用程序可以对应多个进程,在Android中,一个任务栈里可以有多个Activity,而Android应用程序推出后,Android会尽量将进程保留。其目的时为了下一次启动应用时提高启动速度。但这种做法容易引发内存不足的缺陷。而当内存不足时,Android会自动回收部分进程,其回收的顺序为:

  • 空进程 :没有任何组件运行,所有Activity和任务栈都已被关闭的进程
  • 后台进程 :应用程序没有服务处于运行状态,并且应用程序处于最小化的状态。当某个程序按home键返回,若该程序未启动任何服务,那么,此时进程属于后台进程
  • 服务进程 :服务进程是运行于后台的没有界面显示的进程。Android回收内存空间时会优先回收后台进程,若内存仍然不足时才回收服务进程
  • 可见进程 :应用UI可见,但失去焦点,不能操作。一般情况下这类进程很少被回收
  • 前台进程 :当前正在操作的进程,具有焦点,可以响应事件。一般情况下这类进程是不会被回收的。

服务概念

服务的概念最先是由微软引入。由上述回收机制可知,服务就是没有界面但长期运行于后台的进程。服务被回收的情况较少发生,因此,当某一应用程序不需要前台UI,但需要长期运行时可以使用服务。如音乐播放器、后台下载等。

创建服务

  • 写一个类集成Service
public class ServerDemo extends Service{
 
  @Override
  public IBinder onBind(Intent intent) {
    return null;
  }

  @Override
  public void onCreate() {
  //TODO 此方法会在服务创建时调用。当服务创建完成后,将不会再调用此方法。也就是说此方法只会被调用一次
  //具体代码写在这里
  super.onCreate();
  }
  @Override
  public void onDestroy() {
  // TODO 此方法会在服务销毁时被调用
  super.onDestroy();
  //service继承了ContextWrapper类,因此,具有许多与Activity相同的方法,因此参数Context值可以是this
  //Intent intent = new Intent(this,ServerDemo.class);
  //startService(intent);    
  }
  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
  // TODO 当服务被调用时执行此方法,此方法与onStart()方法相同
    return super.onStartCommand(intent, flags, startId);
  }
}
  • 然后再清单文件中application标签内配置Service
    <service android:name="com.asksky.ser.ServerDemo"></service>
  • 开启服务:服务不能自己运行,需要发送Intent开启
Intent intent = new Intent(packageContext, cls);
startService(intent);

服务的生命周期

服务只会被创建一次,如果重复被创建不会重复执行onCreate方法
服务只会被停止一次,如果服务已经停止不会重复执行onDestory方法
如果服务已经开启,多次调用startService方法,服务只会执行onstartCommand方法,onCreate方法不会执行

绑定服务

在服务中,onCreate方法会在服务被创建时执行,而onDestory方法会在服务销毁时执行.诸如此类方法都可以在一定的条件下就会被自动执行,改变某一条件就可以达到执行这些方法的目的.但是,服务中有可能存在自定义的方法,这些方法需要被调用必须手动new一个对象,但是,在Android中,四大组件一般是不会被手动创建的,因为,这些组件由Android框架创建,在内可以直接使用Context等对象,若手动创建,这些对象就不能使用了.
为了解决四大组件不能创建对象,但须调用其中方法这一问题,Android提供了绑定服务的机制。可以将Activity和服务绑定在一起,绑定过后就可以通过中间类来调用服务中的方法了。

绑定服务

bindService(intent, conn , BIND_AUTO_CREATE)
将当前Activity和Service绑定起来,用一个conn对象保持连接,在绑定时如果服务不存在则服务会被创建出来,如果服务已经存在则直接绑定.重复绑定无效果.
绑定服务将触发服务中的onBind方法
conn对象可以保持Activity和Service之间的绑定,当绑定状态发生变化时其中的方法自动被调用

移除绑定服务

unbindService(conn)
将当前Activity和Serivce的绑定解除,如果服务不再被需要则销毁(如果服务最初是被绑定时由绑定的动作而创建的则随着移除绑定销毁,如果不是则不销毁).不可以在未绑定的情况下移除绑定.
移除绑定服务将触发服务中的onUnBind方法
另外,Activity退出时,绑定自动解除了

具体实现

  • 服务类
public class MyService extends Service {
 /**
  * 在Android中,四大组件一般不能手动创建
  * 当需要调用以下自定义方法时,需要使用服务绑定机制
  * */
 public void show(){
  System.out.println("这是一个show()方法");
 }
/**
 * 写一个内部类作为service服务类与Activity类之间调用方法的中间类
 * 此类可以看做是服务类用于对外提供方法的基站
 * 可以将所有有可能被调用到的方法写进中间类,Activity类通过此类来调用具体方法
 * */
class GetService extends Binder{
  public void getShow(){
   show();
  }
  public void otherMethod(){
   Toast.makeText(MyService.this, "所有其它需要被调用的方法都可以写在此类中",0).show();
  }
 }
 /**
  * 绑定服务需要使用onBind方法,此方法用于将中间类返回
  * */
 @Override
 public IBinder onBind(Intent intent) {
  return new GetService();
 }
 
 @Override
 public void onCreate() {
  // TODO 创建服务时执行此方法
  super.onCreate();
 }
}
  • Activity类
public class MainActivity extends ActionBarActivity {
 GetService ms = null;
 /**
  * 此时,在Activity类中调用服务类中所需要的方法,就可以通过绑定服务的机制获取指定方法了
  * 服务方法中对外提供的获取方法的中间类也可以被看做一个接口,使用此接口需要先获取链接
  * 创建一个类继承ServiceConnection
  * */
 class MyServConn implements ServiceConnection{

 @Override
 public void onServiceConnected(ComponentName name, IBinder service) {
 /** 当Service中有方法被调用时,需要用到链接,此方法会执行
  * 注意必须有binder返回这个方法才有效
  * IBinder service 就是服务类中public IBinder onBind(Intent intent)方法返回的中间类
   * ComponentName name 貌似是被代理类的包名/全路径名
  */
  ms = (GetService) service;
  System.out.println(name.toString());
  }

  @Override
  public void onServiceDisconnected(ComponentName name) {
  }
 }
@Override
 protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       Intent intent = new Intent(this, MyService.class);
       bindService(intent, new MyServConn(), BIND_AUTO_CREATE);
       //ms.getShow();此处不能在onCreate方法中调用,因为此时的中间类对象为空.
   }
 public void show(View v){
       ms.getShow();
       ms.otherMethod();
   }
}

代码进阶

上述绑定服务机制存在一个小bug:中间类所有的方法都可以被调用者调用
解决方案:

  • 写一个接口
public interface IService {
    public void show();
}
  • 将中间类私有化,并继承此接口
private class GetService extends Binder implements IService{
 public void getShow(){
   show();
 }
 public void otherMethod(){
   Toast.makeText(MyService.this, "所有其它需要被调用的方法都可以卸载此类中",0).show();
   }
}

  • 此时,Activity类若直接调用中间类就会报错,此时必须调用接口,然后通过接口调用中间类中的方法,这样,只有接口中声明过的方法才可以被调用
IService ms = (IService) service;
ms.otherMethod();//此时若是调用此方法就会报错

注意:在调用服务时,若使用startService()可以启动服务,且Activity退出后,service仍然可以后台运行

但在使用绑定服务机制时,不能使用startService()方法,需要用bindService()方法来启动服务.此时,当Activity退出后,Service也会跟着退出!

解决方案

先创建服务:
  Intent intent = new Intent(this, MyService.class);
创建完成后直接启动,防止上述问题发生
  startService(intent);
当需要用到绑定服务获取方法时,再使用bindService
  bindService(intent, new MyServConn(), BIND_AUTO_CREATE);
这样,问题可以解决

相关链接:
远程服务(AIDL)

如以上内容有任何错误或补充,欢迎加QQ:1195211669 ,验证信息:简书

推荐阅读更多精彩内容