安卓集中营AndroidAndroid进阶碎碎念

【Android】Service那点事儿

2016-07-20  本文已影响9069人  紫豪

1.Service简介

服务是一个应用程序组件,可以在后台执行长时间运行的操作,不提供用户界面。一个应用程序组件可以启动一个服务,它将继续在后台运行,即使用户切换到另一个应用程序。此外,一个组件可以绑定到一个服务与它交互,甚至执行进程间通信(IPC)。例如,一个服务可能处理网络通信、播放音乐、计时操作或与一个内容提供者交互,都在后台执行。


2.Service的种类

类别 区别 优点 缺点 应用
本地服务(Local Service) 该服务依附在主进程上 服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外Local服务因为是在同一进程因此不需要IPC,也不需要AIDL。相应bindService会方便很多。 主进程被Kill后,服务便会终止。 如:音乐播放器播放等不需要常驻的服务。
远程服务(Remote Service) 该服务是独立的进程 服务为独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。由于是独立的进程,因此在Activity所在进程被Kill的时候,该服务依然在运行,不受其他进程影响,有利于为多个进程提供服务具有较高的灵活性。 该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点。 一些提供系统服务的Service,这种Service是常驻的。
类别 区别 应用
前台服务 会在通知栏显示onGoing的 Notification 当服务被终止的时候,通知一栏的 Notification 也会消失,这样对于用户有一定的通知作用。常见的如音乐播放服务。
后台服务 默认的服务即为后台服务,即不会在通知一栏显示 onGoing的 Notification。 当服务被终止的时候,用户是看不到效果的。某些不需要运行或终止提示的服务,如天气更新,日期同步,邮件同步等。
类别 区别
startService启动的服务 主要用于启动一个服务执行后台任务,不进行通信。停止服务使用stopService。
bindService启动的服务 方法启动的服务要进行通信。停止服务使用unbindService。
同时使用startService、bindService 启动的服务 停止服务应同时使用stopService与unbindService。

3.Service的生命周期

不同启动方式下生命周期对比.png

通过这个图可以看到,两种启动Service的方式以及他们的生命周期,bindService的不同之处在于当绑定的组件销毁后,对应的service也就被kill了。

注:在系统资源不足的情况下,服务有可能被系统结束(kill);

官方原文:
If you do allow your service to be started and bound,then when then service has been started,the System does not destory the service when all clients unbind.Instead,you must explicitly stop the service,by calling stopSelf() or stopService().
如果你同意你的服务被开启和绑定,然后当服务被开启的时候,当所有的客户端都解除对服务的绑定android操作系统也不会销毁这个服务,相反的你必须显示的调用stopSelf()或者stopService()方法来停止服务。
什么情况下使用:
如果你想要与正在运行的Service取得联系,那么有两种方法,一种是使用广播,另外一种方法就是使用bindService来建立联系,前者的缺点是如果交流较为频繁,容易造成性能上的问题,并且BroadcastReceiver本身执行代码的时间是很短的(也许执行到一半,后面的代码便不会执行),而后者则没有这些问题,因此我们肯定选择使用bindService(这个时候你便同时在使用startService和bindService了,这在Activity中更新Service的某些运行状态是相当有用的)。

特别注意:
1.在使用startService方法启动服务后,一定要调用stopService方法来停止该服务(同上,可以在Activity的onDestory中来停止服务);
2.在某处调用bindService绑定Service的时候,要在对应的某处调用unbindService来解除绑定(如在Activity中绑定了Service,可以在onDestory中来解除绑定——虽然绑定的Service会在Activity结束时自动解除、停止);
3.如果同时使用startServicebindService方法启动Service,需要终止该Service时,要调用stopServiceunbindService方法(unbindService依附于启动它的Context,startServicec并不依附于启动它的Context。如果先调用unbindService,这时服务并不会被终止,当调用stopService后,服务才会被终止;如果先调用stopService,服务也不会被终止,当调用unbindService或者之前调用bindService的Context不存在了(如Activity被finish掉了)服务才会自动停止);
4.当手机屏幕发生旋转时,如果Activity设置的是自动旋转的话,在旋转的过程中,Activity会重新创建,那么之前通过bindService建立的连接便会断开(之前的Context不存在了),服务也会被自动停止。


4.Service的使用

在新建一个Service后,记得在AndroidManifest.xml中注册Service,在application内添加需要注册的Service信息:

<service android:name=".service.PlayerService"
    android:label="PlayerService"
    android:exported="true" />

Service示例如下:

public class PlayerService extends Service{

    @Override
    public void onCreate() {
        super.onCreate(); 
    } 

    /** 
    * onBind 是 Service 的虚方法,因此我们不得不实现它。
    * 返回 null,表示客服端不能建立到此服务的连接。
    */ 
    @Override
    public IBinder onBind(Intent intent) { 
        return new MyBinder();
    }

    // 已取代onStart方法--onStart方法是在Android2.0之前的平台使用的.
    // 在2.0及其之后,则需重写onStartCommand方法,同时,旧的onStart方法则不会再被直接调用
    // (外部调用onStartCommand,而onStartCommand里会再调用 onStart。在2.0之后,
    // 推荐覆盖onStartCommand方法,而为了向前兼容,在onStartCommand依然会调用onStart方法。
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId); 
    } 

    @Override
    public boolean onUnbind(Intent intent) { 
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy(); 
    } 
    // IBinder是远程对象的基本接口,是为高性能而设计的轻量级远程调用机制的核心部分。但它不仅用于远程
    // 调用,也用于进程内调用。这个接口定义了与远程对象交互的协议。
    // 不要直接实现这个接口,而应该从Binder派生。
    // Binder类已实现了IBinder接口
    class MyBinder extends Binder { 
        /** 
        * 获取Service的方法
        * @return 返回PlayerService
        */ 
        public  PlayerService getService(){
            return PlayerService.this;
        }
    }
}
public class PlayerActivity extends Activity{
  private Intent intent;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    intent = new Intent(this, PlayerService.class);
    startService(intent);// 启动服务
  }
  @Override
  protected void onDestroy() {
    super.onDestroy();
    stopService(intent);// 在退出Activity时停止该服务
  }
}
public class PlayerActivity extends Activity{
   @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Intent intent = new Intent(this, PlayerService.class);
    bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);//绑定目标Service
  }
  @Override
  protected void onDestroy() {
    super.onDestroy();
    unbindService(serviceConnection);// 解除绑定,断开连接
  }
  // 在Activity中,我们通过ServiceConnection接口来取得建立连接与连接意外丢失的回调
  ServiceConnection serviceConnection = new ServiceConnection() {            @Override
    public void onServiceConnected(ComponentName name, IBinder service){
      // 建立连接
      // 获取服务的操作对象
               PlayerService.MyBinder binder = (PlayerService.MyBinder)service;
               binder.getService();// 获取到的Service即PlayerService
    } 
    @Override
    public void onServiceDisconnected(ComponentName name) {
      // 连接断开
    }
  };
}


Service的onBind如果返回null,则调用bindService会启动Service,但不会连接上Service因此ServiceConnection.onServiceConnected不会被调用,但仍然需要使用unbindService方法来断开连接,这样Service才会停止。


  Service与Activity一样都存在与当前进程的主线程中,所以,一些阻塞UI的操作(如在Service进行网络请求等)不能放在Service里进行。如果在Service里进行一些耗CPU和耗时操作,可能会引发ANR警告,这时应用会弹出是强制关闭还是等待的对话框。所以,对Service的理解就是和Activity平级的,只不过是看不见的,在后台运行的一个组件,这也是为什么和Activity同被说为Android的基本组件。


5. AndroidManifest.xml中Service元素常见属性

服务类名。可以是完整的包名+类名。也可使用.代替包名。

其他应用能否访问该服务,如果不能,则只有本应用或有相同用户ID的应用能访问。默认为false。

标识服务是否可以被系统实例化。true--系统默认启动,false--不启动。(默认值为true)

显示给用户的服务名称。如果没有进行服务名称的设置,默认显示服务的类名。

服务所运行的进程名。默认是在当前进程下运行,与包名一致。如果进行了设置,将会在包名后加上设置的集成名。
如果名称设置为冒号 :开头,一个对应用程序私有的新进程会在需要时和运行到这个进程时建立。如果名称为小写字母开头,服务会在一个相同名字的全局进程运行,如果有权限这样的话。这允许不同应用程序的组件可以分享一个进程,减少了资源的使用。

服务的图标。

申请使用该服务的权限,如果没有配置下相关权限,服务将不执行,使用startService()bindService()方法将都得不到执行。


6.Thread与Service的区别


7.Service系列拓展阅读

【Android】Service前台服务的使用
【Android】远程服务(Remote Service)的使用

上一篇下一篇

猜你喜欢

热点阅读