在Android王国中,Service是一个劳动模范,总是默默的在后台运行,无怨无悔,且总是干最脏最累的活,比如下载文件,倾听音乐,网络操作等这些耗时的操作,所以我们请尊重的叫他一声:"劳模,您辛苦了".

    带着这份好尊重,我又重新研读了API的文档,发现老外写东西还是很靠谱的,人家在文档中告诉你Service是什么,又告诉你Service又不是什么,我觉得这种思路不错,那就从这两个个方面开始谈起吧:

  1. Service是什么?
    1. A Service is an application component. ☆ Service 是一个应用程序组件
    2. that can perform long-running operations in the background. ☆ 它能在后台执行一些耗时较长的操作.
    3. and does not provide a user interface. ☆ 并且不提供用户界面
    4. Another application component can start a service and it will continue to run in the background event if the user switches to another application. ☆ 服务能被其它的应用程序组件启动,即使用户切换到其他的应用程序时还能保持在后台运行.
    5. Additionally,a component can bind to a service to interact with it and even perform interprocess communcation(IPC). ☆ 此外,组件还能绑定服务,并与服务交互,甚至执行进程间通信(IPC).
    6. For example,a service might handle network transactions,play music,perform file I/O,or interact with a content provider,all from the background. ☆ 比如,一个服务可以处理网络传输,听音乐,执行文件操作,或者与内容提供者进行交互,所有这些都在后台进行.
    7. A service can essentially tack two forms.☆ 服务有以下两种基本类型
      1. Started --> startService()
      2. Bound --> bindService()
  2. Service又不是什么?
    1. A service is not a separate process.☆ 服务不是一个单独的进程.
    2. A service is not a thread.it runs in the main thread of its hosting process. ☆ 服务不是一个线程,它运行在主线程.
    3. the service does not create its own thread and does not run in a separate process(unless you specify otherwise). ☆ 服务不能自己创建并且不能运行在单独的进程中(除非你明确指定).
    4. This means that, if your service is going to do any CPU intensive work ot blocking operations(such as MP3 playback or network). ☆ 这意味着如果你的服务要执行一些很耗CUP的工作或者阻塞的操作(比如播放mp3或网络操作),you should create a new thread within the service to do that work. ☆ 你应该在服务中创建一个新的线程来执行这些工作.
    5. By using a separate thread, you will reduce the risk of Application Not Responding(ANR) errors and the application's main thread can remain dedicated to user interaction with your activities. ☆ 利用一个分离的进程,将减少你的activities发生应用程序停止响应(ANR)错误的风险.
  3. 如何创建一个Started服务
    1. 继承service

      1. publicclassFirstServiceextendsService{
      2. privatestaticfinalString TAG ="--FirstService-->";
      3. publicFirstService(){
      4. Log.i(TAG,"Service is running.");
      5. }
      6. @Override
      7. publicvoid onCreate(){
      8. Log.i(TAG,"onCreate is running.");
      9. super.onCreate();
      10. }
      11. @Override
      12. publicint onStartCommand(Intent intent,int flags,int startId){
      13. Log.i(TAG,"onStartCommand is running.");
      14. returnsuper.onStartCommand(intent, flags, startId);
      15. }
      16. @Override
      17. publicIBinder onBind(Intent intent){
      18. Log.i(TAG,"IBinder is running.");
      19. returnnull;
      20. }
      21. }
       
    2. 四大组件都需要在manifests.xml中注册,这个也不例外.
    3. 如何启动它
      1. Intent intent =newIntent(ServiceActivity.this,FirstService.class);
      2. startService(intent);
    4. 生命周期onCreate(), onStartCommand(), onDestory()就这三个生命周期
      1. --FirstService-->:Service is running.
      2. --FirstService-->: onCreate is running.
      3. --FirstService-->: onStartCommand is running.
    5. 我们在onStartCommand方法中打印下当前线程
      1. @Override
      2. publicint onStartCommand(Intent intent,int flags,int startId){
      3. Log.i(TAG,"onStartCommand is running.Thread:"+Thread.currentThread());
      4. returnsuper.onStartCommand(intent, flags, startId);
      5. }
      打印结果如下:
      1. onStartCommand is running.Thread:Thread[main,5,main]
      验证了两点:①由于是第二次运行,构造方法和onStart都没有打印,说明服务一旦启动是默默运行在后台的;②服务是运行在主线程的 
    6. 如何结束服务:①调用stopService()方法 ,会回调service的onDestory()方法;
      1. Intent intent2 =newIntent(ServiceActivity.this,FirstService.class);
      2. stopService(intent2);
      还可以在Android系统设置-->应用-->正在运行-->找到后是如下样式,会告诉我们有一个服务在运行;
    7. onStartCommand的返回值:
      1. START_STICKY:粘性的,被意外中止后自动重启,重新调用onStartCommand(),但会丢失原来激活它的Intent,会用一个null intent来调用onStartCommand(),可以用于播放器.值为1
      2. START_NOT_STICKY:非粘性的,被意外中止后不会重启,除非还存在未发送的Intent,这是避免服务运行的最安全选项; 值为2
      3. START_REDELIVER_INTENT:粘性的且重新发送Intent,被意外中止后重新启动,且该service组件将得到用于激活它的Intent对象,这中服务适用于需要立即恢复工作的活跃服务,比如下载文件; 值为3
    8. onStartCommand的参数:
      1. @Override //第一个参数:为我们传入的intent;第二个flags:启动服务的方式,与返回值有关;第三个为我们启动service的次数.
      2. publicint onStartCommand(Intent intent,int flags,int startId){
      3. Log.i(TAG,"onStartCommand is running.Thread:"+Thread.currentThread());
      4. Log.i(TAG,"flags:"+flags);
      5. Log.i(TAG,"startId:"+startId);
      6. returnsuper.onStartCommand(intent, flags, startId);
      7. }
      因为前面服务已经启动了,这次我们连续点了三次启动服务的按钮,打印日志如下:
      1. 11-1602:56:28.3859039-9039/com.wanghx.androidstudy I/--FirstService-->: onStartCommand is running.Thread:Thread[main,5,main]
      2. 11-1602:56:28.3859039-9039/com.wanghx.androidstudy I/--FirstService-->: flags:0
      3. 11-1602:56:28.3859039-9039/com.wanghx.androidstudy I/--FirstService-->: startId:2
      4. 11-1602:56:33.9859039-9039/com.wanghx.androidstudy I/--FirstService-->: onStartCommand is running.Thread:Thread[main,5,main]
      5. 11-1602:56:33.9859039-9039/com.wanghx.androidstudy I/--FirstService-->: flags:0
      6. 11-1602:56:33.9859039-9039/com.wanghx.androidstudy I/--FirstService-->: startId:3
      7. 11-1602:56:35.5359039-9039/com.wanghx.androidstudy I/--FirstService-->: onStartCommand is running.Thread:Thread[main,5,main]
      8. 11-1602:56:35.5359039-9039/com.wanghx.androidstudy I/--FirstService-->: flags:0
      9. 11-1602:56:35.5359039-9039/com.wanghx.androidstudy I/--FirstService-->: startId:4
      我们发现flags的值没有发生改变,而startId再按顺序增加.
  4. 如何启动一个绑定服务
    1. 在activity中创建一个内部类,继承ServiceConnection.

      1. classMyServiceConnectionimplementsServiceConnection{
      2. @Override
      3. publicvoid onServiceConnected(ComponentName name,IBinder service){
      4. Log.i(TAG,"onServiceConnected");
      5. }
      6. @Override
      7. publicvoid onServiceDisconnected(ComponentName name){
      8. Log.i(TAG,"onServiceDisconnected");
      9. }
      10. }
       
    2. 在activity中定义一个成员connection
      1. privateMyServiceConnection connection =newMyServiceConnection();
       
    3. 在绑定服务按钮中加入绑定代码
      1. Intent intent3 =newIntent(ServiceActivity.this,FirstService.class);
      2. bindService(intent3, connection, BIND_AUTO_CREATE);
      按钮点击后打印如下日志:
      1. I/--FirstService-->:Service is running.
      2. I/--FirstService-->: onCreate is running.
      3. I/--FirstService-->:IBinder is running.
       
    4. 在解绑服务中加入代码,这里的connection必须和上边的绑定服务的connection实例一致.
      1. unbindService(connection);
       
  5. Service和Thread的关系
    1. 其实他两个没有一毛钱关系.只是因为service需要做耗时操作,需要重新建立一线程来处理工作,而不阻塞主线程;
    2. service是运行在主线程的;
    3. activity启动service后,即使activity被销毁了,如果没有主动关闭服务,服务还是会在后台默默运行的;
  6. 如何连接远程的service,只需要在manifests.xml中这样写即可
    1. <service
    2. android:name="com.example.servicetest.MyService"
    3. android:process=":remote">
    4. </service>
    如何让activity与远程的service进行通信呢?这就要使用AIDL进行跨进程通信(IPC)了.
  7. AIDL:Android Interface Definition Language:Android接口定义语言,它可以用于让多个service与多个应用程序组件之间进行跨进程通信;
  8. 这些都不是重点,我们还是弄一下在我们自己的程序中service与activity之间的通信吧;
    1. activity-->service 通过intent传递数据给service;
    2. activity调用onServiceConnected()中的IBind对象来访问service中的方法;
    3. IBinder通信的关键是利用activity中的IBinder对象获得service对象,然后调用方法;
      1. publicclassFirstServiceextendsService{
      2. privatestaticfinalString TAG ="FirstService-->";
      3. privateMyBinder myBinder =newMyBinder();
      4. publicFirstService(){
      5. Log.i(TAG,"Service is running.");
      6. }
      7. @Override
      8. publicvoid onCreate(){
      9. Log.i(TAG,"onCreate is running.");
      10. super.onCreate();
      11. }
      12. @Override
      13. publicint onStartCommand(Intent intent,int flags,int startId){
      14. String name = intent.getStringExtra("name");
      15. Log.i(TAG,"onStartCommand is running.Thread:"+Thread.currentThread());
      16. Log.i(TAG,"flags:"+flags);
      17. Log.i(TAG,"startId:"+startId);
      18. Log.i(TAG,"name:"+name);
      19. return START_STICKY;
      20. }
      21. @Override
      22. publicvoid onDestroy(){
      23. Log.i(TAG,"onDestroy is running.");
      24. super.onDestroy();
      25. }
      26. @Override
      27. publicIBinder onBind(Intent intent){
      28. Log.i(TAG,"IBinder is running.");
      29. return myBinder;
      30. }
      31. publicclassMyBinderextendsBinder{
      32. publicFirstService getService(){
      33. returnFirstService.this;
      34. }
      35. }
      36. publicint getRandomNumber(){
      37. returnnewRandom().nextInt(10)+1;
      38. }
      39. }
      1. publicclassServiceActivityextendsAppCompatActivityimplementsView.OnClickListener{
      2. privateMyServiceConnection connection =newMyServiceConnection();
      3. privatestaticfinalString TAG ="ServiceActivity-->";
      4. privateFirstService mFirstService;
      5. privateboolean isBinder;// 服务是否绑定
      6. @Override
      7. protectedvoid onCreate(Bundle savedInstanceState){
      8. super.onCreate(savedInstanceState);
      9. setContentView(R.layout.activity_service);
      10. findViewById(R.id.btn_start_service).setOnClickListener(this);
      11. findViewById(R.id.btn_stop_service).setOnClickListener(this);
      12. findViewById(R.id.btn_bound_service).setOnClickListener(this);
      13. findViewById(R.id.btn_unbound_service).setOnClickListener(this);
      14. findViewById(R.id.btn_get_number).setOnClickListener(this);
      15. }
      16. @Override
      17. publicvoid onClick(View v){
      18. switch(v.getId()){
      19. case R.id.btn_start_service:
      20. Intent intent =newIntent(ServiceActivity.this,FirstService.class);
      21. intent.putExtra("name","Zhangsan");
      22. startService(intent);
      23. break;
      24. case R.id.btn_stop_service:
      25. Intent intent2 =newIntent(ServiceActivity.this,FirstService.class);
      26. stopService(intent2);
      27. break;
      28. case R.id.btn_bound_service:
      29. if(!isBinder){
      30. Intent intent3 =newIntent(ServiceActivity.this,FirstService.class);
      31. bindService(intent3, connection, BIND_AUTO_CREATE);
      32. isBinder =true;
      33. }
      34. break;
      35. case R.id.btn_unbound_service:
      36. if(isBinder){
      37. unbindService(connection);
      38. isBinder =false;
      39. }
      40. break;
      41. case R.id.btn_get_number:
      42. if(mFirstService ==null){
      43. Toast.makeText(getApplicationContext(),"请先绑定服务",Toast.LENGTH_SHORT).show();
      44. }else{
      45. Toast.makeText(getApplicationContext(),"得到的随机数为:"+ mFirstService.getRandomNumber(),Toast
      46. .LENGTH_SHORT).show();
      47. }
      48. break;
      49. }
      50. }
      51. classMyServiceConnectionimplementsServiceConnection{
      52. @Override
      53. publicvoid onServiceConnected(ComponentName name,IBinder service){
      54. Log.i(TAG,"onServiceConnected");
      55. FirstService.MyBinder myBinder =(FirstService.MyBinder) service;
      56. mFirstService = myBinder.getService();
      57. }
      58. @Override
      59. publicvoid onServiceDisconnected(ComponentName name){
      60. Log.i(TAG,"onServiceDisconnected");
      61. }
      62. }
      63. }
      这里有一个小插曲:一起写出来大家分享下:记得以前学java基础时,老师曾说过一个java文件中只能有一个public类,类名称必须与java文件名相同,为什么这个FirstService中有两个public类,只是因为MyBinder虽然是一个public class,但是MyBinder是一个内部类,这里必须要用public修饰,否则其他包就访问不到这个内部类了;

Service是什么?Service又不是什么?的更多相关文章

  1. Failed to stop iptables.service: Unit iptables.service not loaded.

    redhat 7 [root@lk0 ~]# service iptables stop Redirecting to /bin/systemctl stop iptables.service Fai ...

  2. Local System、Local Service與Network Service

    CreateService参数介绍SC_HANDLE CreateService( SC_HANDLE hSCManager, //服务控制管理程序维护的登记数据库的句柄,由系统函数OpenSCMan ...

  3. 关于Failed to check the status of the service com.taotao.service.ItemService. No provider available fo

    原文:http://www.bubuko.com/infodetail-2250226.html 项目中用dubbo发生: Failed to check the status of the serv ...

  4. Failed to stop iptables.service: Unit iptables.service not loaded.解决方法

    CentOS7中执行 service iptables start/stop 会报错Failed to start iptables.service: Unit iptables.service fa ...

  5. 从Web Service和Remoting Service引出WCF服务

    本篇先通过Web Service和Remoting Service创建服务,抛砖引玉,再体验WCF服务.首先一些基本面: 什么是WCF? Windows Communication Foundatio ...

  6. Android Service总结02 service介绍

    Android Service总结02 service介绍 版本 版本说明 发布时间 发布人 V1.0 介绍了Service的种类,常用API,生命周期等内容. 2013-03-16 Skywang ...

  7. Service Fabric —— Stateful Service 概念

    作者:潘罡 (Van Pan) @ Microsoft 上节中我们谈到了Service Fabric最底层的两个概念,一个是针对硬件层面而言的Node Type和Node.另一个是Applicatio ...

  8. CentOS 7 防火墙 出现Failed to start iptables.service: Unit iptables.service failed to load

    错误信息如下: [root]# service iptables start Redirecting to /bin/systemctl start iptables.service Failed t ...

  9. service: no such service mysqld 与MySQL的开启,关闭和重启

    1.问题原因与解决办法 因为修改了MySQL临时文件的目录后,使用service mysqld restart重启MySQL出现如下错误: service: no such service mysql ...

  10. dubbo Failed to check the status of the service com.user.service.UserService. No provider available for the service

    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'u ...

随机推荐

  1. 分享MSSQL、MySql、Oracle的大数据批量导入方法及编程手法细节

    1:MSSQL SQL语法篇: BULK INSERT [ database_name . [ schema_name ] . | schema_name . ] [ table_name | vie ...

  2. jexus5.8.2 linux x64专业版 配置https

    一.环境 1.jexus版本:Jexus/5.8.2.8 Linux专业版 内置mono版本:Mono/4.6.2.7 2.操作系统:centOs7 jexus独立版由于是免安装版并且内置mono,所 ...

  3. ENode 2.8 最新架构图简介

    ENode架构图 什么是ENode ENode是一个.NET平台下,纯C#开发的,基于DDD,CQRS,ES,EDA,In-Memory架构风格的,可以帮助开发者开发高并发.高吞吐.可伸缩.可扩展的应 ...

  4. MyBatis6:MyBatis集成Spring事物管理(下篇)

    前言 前一篇文章<MyBatis5:MyBatis集成Spring事物管理(上篇)>复习了MyBatis的基本使用以及使用Spring管理MyBatis的事物的做法,本文的目的是在这个的基 ...

  5. C# 委托Delegate(一) 基础介绍&用法

    本文是根据书本&网络 前人总结的. 1. 前言 定义&介绍: 委托Delegate是一个类,定义了方法的类型, 使得可以将方法当做另一个方法的参数来进行传递,这种将方法动态地赋给参数的 ...

  6. Js删除数组重复元素的多种方法

    js对数组元素去重有很多种处理的方法,本篇文章中为网络资源整理,当然每个方法我都去实现了:写下来的目的是希望自己活学活用,下次遇到问题后方便解决. 第一种 function oSort(arr){ v ...

  7. 【.net深呼吸】WPF异步加载大批量图像

    如何在WPF中加载大批量数据,并且不会阻塞UI线程,尤其是加载大量图片时,这活儿一直是很多朋友都相当关注的.世上没有最完美的解决之道,咱们但求相对较优的方案. 经过一些试验和对比,老周找到了一种算是不 ...

  8. JavaScript权威设计--JavaScript语言核心(简要学习笔记一)

    1.对象名/值得映射 var book={ top:"a", fat:true }   2.访问对象属性 book.top book["fat"] 3.通过赋值 ...

  9. 4. ValueStack 和 OGNL

    1. 属性哪来的 当我们通过Action处理完用户请求以后,可以直接在页面中获取到 action 的属性值. 如果我们在页面中尝试遍历四个域中的属性,会发现域中并没有username之类的Action ...

  10. 浅析MySQL二进制日志

    查看MySQL二进制文件中的内容有两种方式 1.  mysqlbinlog 2.  SHOW BINLOG EVENTS [IN 'log_name'] [FROM pos] [LIMIT [offs ...