Android-Service必须掌握的几点知识

请尊重他人劳动成果,请勿随意剽窃,转载请注明,谢谢!转载请注明出处:http://blog.csdn.net/evan_man/article/details/51800263

启动方式

启动Local Service(Client跟Service在同一个进程)

这类服务有个特点,就是它主要用于为某一个客户(Activity)提供单独的后台服务;

Context.startService()启动

  • 如果调用该方法时对应Service还没有创建出来,则会调用onCreate方法;即Service只会创建一个实例;
  • 调用多少次该方法就对应调用多少次Service端的onStartCommand方法;

Context.stopService()结束

  • 无论之前调用了多少次startService,只需要调用一次该方法

启动Remote Service(Client跟Service不在同一个进程)

这类服务有个特点,就是它会定义一些接口并把接口暴露出来,以便其他应用进行操作;

多个客户端可以绑定同一个服务;

Context.bindService()方法建立连接,并启动

  • 如果调用该方法时对应Service还没有创建出来,则会调用onCreate方法;即Service只会创建一个实例;
  • Context如果之前没有和该Service绑定过,即执行bindService方法,那么就会执行Service的bindService方法;如果绑定过了就不会执行onBind方法

Context.unbindService()关闭连接

注意:

  • 上面只是默认一种约定行为;如果是Remote Service建议使用bindService,因为bindService可以获取 Remote Service提供的接口;如果是Local Service建议使用sartService,因为startService很简单;

生命周期

Part1(纯粹的Start)

  • 启动:startService方法启动
  • 终止:调用stopService,或自身的stopSelf方法,系统资源不足android系统结束服务;(执行Service的onDestroy方法)

Part2(纯粹的Bind)

  • 启动:bindService方法启动
  • 终止:调用unbindService断开连接,之前调用bindService 的 Context 不存在了(如Activity被finish的时候);(执行Service的unBind和onDestroy方法)

Part3(混合的Start&Bind)

  • 启动:如先startService,后bindService
  • 终止:(调用stopService 或者 调用stopSelf)并且(不再有绑定的连接)==》onDestroy方法将会被调用;

注意:

  • Activity旋转的时候,意味着Activity重建了;旋转之前的使用 bindService 建立的连接便会断开(Context 不存在了);
  • 使用了startService启动Service就需要调用stopService关闭服务;使用了bindService启动Service就需要调用unbindService关闭服务;它们都是成对出现的!!!
  • 这里对bindService启动的Service会和启动它的Context共生死,这一点进行一下说明;如果ActivityA进行了bindService,ActivityB也bindService,那么当ActivityA进行了unbindService时,Service并不会调用onDestroy,因为它还有个bind没有解除(即跟ActivityB之间的bind)~;但是activityA跳转到ActivityB,有可能导致activityA被系统销毁,这样即使activityA代码中没有调用unbind,系统也会自动将activityA和service解绑,进而可能service就onDestroy了;当Activity2在bind的时候该service已经不存在了,最终还是要去创建一个service实例;为了避免上述问题这里建议,通过startService启动service,随后bindService进行activity和service的绑定,这样即使activity内容被销毁了,service还是不会调用onDestroy方法!

实现原理

Local Service:(Client和Service在同一个进程中)

Service端:

  • 编写类继承android.app.Service类;实现onCreate、onbind、onStartCommand、onDestroy等方法
  • 在Manifest.xml文件中注册该Service:如下
    • <!-- android:exported 这个属性用于指示该服务是否能够被其他应用程序组件调用或跟它交互。
           如果设置为true,则能够被调用或交互,否则不能。设置为false时,
           只有同一个应用程序的组件或带有相同用户ID的应用程序才能启动或绑定该服务。-->
      <service android:name=".ServiceDemo" android:exported="false">
      <!--android:name=“” The name of the Service subclass that implements the service 继承了Service的类,绝对路径:包名+类名-->
          <intent-filter><!--隐式调用才会用到这个;代表了一种Intent的组合方式;一个组件可以有多个Intent-filter-->
              <action android:name="com.demo.SERVICE_DEMO" /> <!--外界使用的名字-->
              <category android:name="android.intent.category.DEFAULT" /> <!--只有加上这个别的应用才能通过上面的action找到该Service-->
          </intent-filter>
      </service>

Client端:

  • bindService方式启动(关闭调用对应的unbindService())

    • bindService(new Intent(ServiceDemo.ACTION).setPackage(getPackageName()), conn, BIND_AUTO_CREATE);
    • 参数1说明:ServiceDemo.ACTION=="com.demo.SERVICE_DEMO";即上面Service在Manifest的定义的Action!public Intent (String action);Android5.0不支持隐式调用,需要指定packegename,如上面的方式,packegename指明了在哪个包中找和Action对应的组件,如果不指名package那么则在当前系统全局搜索,每个app对应一个package,定义在Manifest标签里面,此package并非指我们想要启动服务类所在的包名;
      • 或者用Intent intent = new Intent();  intent.setClass(this,MyLocalService.class);的方式启动服务;之前我们经常用这个方式,而不是用Action;其实这部分是Intent的内容,可以去研究一下intent的使用方法和构造器!
    • 参数3说明:BIND_AUTO_CREATE,即当服务不存在时,自动创建,如果服务已经启动了或者创建了,那么只会掉调用onBind方法
    • 参数2说明:conn是一个实现了ServiceConnection接口的对象;实现了下面两个方法
      • onServiceConnected(ComponentName name, IBinder service)

        • 客户端调用bindService;Service端对应调用onBind方法;如果onBind方法返回值不为null则执行这里的onServiceConnected方法!(就是该方法的第二个参数,就是onBind方法的返回值);无论这里是不是执行onServiceConnected方法,都已经完成了客户端和Service的绑定,最后还是需要调用unBindService进行解绑;
        • 通过该方法的第二个参数service可以获得Service提供的接口!!如:
        • MyService.SimpleBinder sBinder = (MyService.SimpleBinder)service;
        • //SimpleBinder是MyService的内部类,继承了Binder类,定义了add方法;
        • sBinder.add(3, 5);
      • onServiceDisconnected(ComponentName name)
        • 同上
  • startService方式启动(关闭调用对应的stopService())
    • startService(new Intent(ServiceDemo.ACTION)).setPackage(getPackageName());

Remote Service:(Client和Service不在同一个进程中)(进程间通信毫无疑问使用了Binder)

Service端:

  • 编写一个服务接口,不需要继承任何接口(假设该接口名为: ITestRemoteService);定义该服务会提供的服务(如一个add方法);以aidl格式保存!!

    • android会自动将该文件转换为java文件,并添加一些必要的内容,使其能够进行IPC(我们需要做的就是写aidl文件,随后编译一下工程即可!)
    • IPC即进程间通信,底层通过Binder技术实现
  • 编写类继承android.app.Service类;
    • 有一个如下的Field:private ITestRemoteService.Stub stub= new ITestRemoteService.Stub(){ ..//实现了上面定义的如add方法 }

      • 上面的ITestRemoteService是android对aidl文件转换为java文件后得到的java类,类中自动生成了一个Stub内部类;
    • 在实现的onbind方法中返回上面生成的stub;
    • 实现onCreate、onStartCommand、onDestroy等方法
  • 在Manifest.xml文件中注册该Service
    • <service android:name="com.yq.RemoteService"  android:process=":remote" android:exported="true">
      <!--android:name=“”The name of the Service subclass that implements the service 继承了Service的类,绝对路径:包名+类名-->
          <intent-filter><!--隐式调用才会用到这个;代表了一种Intent的组合方式;一个组件可以有多个Intent-filter-->
              <action android:name="com.yq.RemoteService" /> <!--Service对应名字-->
              <category android:name="android.intent.category.DEFAULT" /> <!--只有加上这个别的应用才能通过上面的action找到该Service-->
          </intent-filter>
      </service>
    • 注意:对于android:process="remote"和android:process=":remote"的区别

Client端:

  • bindService方式启动(关闭调用对应的unbindService())

    • bindService(intent, conn,Context.BIND_AUTO_CREATE);
    • 参数1说明:Intent intent = new Intent("com.yq.RemoteService").setPackage(getPackageName());//packegename指明了在哪个包中找和Action对应的组件,如果不指名package那么则在当前系统全局搜索,每个app对应一个package,定义在Manifest标签里面,此package并非指我们想要启动服务类所在的包名;
    • 参数2说明:BIND_AUTO_CREATE,即当服务不存在时,自动创建,如果服务已经启动了或者创建了,那么只会调用onBind方法
    • 参数3说明:conn是一个实现了ServiceConnection接口的对象;实现了下面两个方法
      • onServiceConnected(ComponentName name, IBinder service)

        • 客户端调用bindService;Service端对应调用onBind方法;如果onBind方法返回值不为null则执行这里的onServiceConnected方法!(就是该方法的第二个参数,就是onBind方法的返回值);无论这里是不是执行onServiceConnected方法,都已经完成了客户端和Service的绑定,最后还是需要调用unBindService进行解绑;
        • 通过该方法的第二个参数service可以获得Service提供的接口!!如:
        • ITestRemoteService remoteService = ITestRemoteService.Stub.asInterface(service);
        • ITestRemoteService就是我们定义了的接口,里面定义了add方法;
        • 之后我们的Client就获得了这个Service,就可以任意时间访问对应的服务了~~
      • onServiceDisconnected(ComponentName name)
        • 同上
  • startService方式启动(关闭调用对应的stopService())
    • startService(intent);
    • 参数说明:Intent intent = new Intent(); intent.setClassName("com.demo","com.demo.SERVICE_DEMO");
    • 可以发现如果通过startService启动服务那么就客户端没有任何返回可以收到!只能单向的向Service发送一个信号;

相关概念的区分(易模糊点)

StartService和bindService启动方法使用场景:

  • 如果你只是想要启动一个后台服务长期进行某项任务那么使用
    startService 便可以了;证明startService启动服务,你的期望不要太高;因为它不给客户端任何反馈;你可以通过broadcast来向客户端传数据,然而BroadcastReceiver 本身执行代码的时间是很短的!!因此不能对该方法期望过高!!总之startService很弱很弱的;
  • 想要与正在运行的 Service 取得联系,推荐我们的终极武器bindService!!bindService很好很强大;

AndroidManifest.xml 里 Service 元素的常见选项

  • android:name,服务类名
  • android:label,服务的名字,如果此项不设置,那么默认显示的服务名则为类名
  • android:process,表示该服务是否运行在另外一个进程,如果设置了此项,那么将会在包名后面加上这段字符串表示另一进程的名字
  • android:enabled,如果此项设置为 true,那么 Service 将会默认被系统启动,不设置默认此项为 false
  • android:exported,表示该服务是否能够被其他应用程序所控制或连接,不设置默认此项为 false
  • android:icon,服务的图标

Service&Thread

  • Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。
  • Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的(运行耗时操作会导致ANR);如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上;
  • 用Service而不用Thread的好处就是我们可以随时通过BindService或者startService跟Service进行通信,换成Thread一旦start我们将无能为力了~;Service很乖,Thread很野;
  • Service的职责是负责后台的耗时的工作;
  • Android的后台就是指,它的运行是完全不依赖UI的,即使Activity被销毁,或者程序被关闭,只要进程还在,Service就可以继续运行;所以在Service中创建Thread比在Acitivity中创建线程的好处在于,Service在一个应用中是稳定存在的,而Activity朝不保夕(应用中经常有各种Activity之间的跳转操作),一旦它销毁了,那么它所创建的线程,将处于游离状态,不受控制,Service不会出现这样的问题;
  • 一个比较好的Service往往是如下的样子:
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 开始执行后台任务
            }
        }).start();
        return super.onStartCommand(intent, flags, startId);
    }
    class MyBinder extends Binder {
        public void startDownload() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    // 执行具体的下载任务
                }
            }).start();
        }
    }  

前台Service和后台Service的区别于实现

后台Service存在被回收的隐患

我们启动的Service一般都是后台运行的Service;因为Service的系统优先级还是比较低的,当系统出现内存不足情况时,就有可能会回收掉正在后台运行的Service;

前台Service避免被回收的隐患

前台Service和普通Service最大的区别就在于,它会一直有一个正在运行的图标在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的效果;这让人想到,小米一个rom开发工程师控诉qq虽然进入了后台,但是在屏幕中展示一个像素点,使得该应用永远处于前台,所以Service永远不会被清除掉!!

创建一个前台Service(以下操作都是在Service里面进行的)

  1. 创建一个Notification

    • CharSequence text = getText(R.string.remote_service_started);
      PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, Controller.class), 0); //指定点击该Notification的时候,应该跳转到的Activity
      Notification notification = new Notification.Builder(this)
                      .setSmallIcon(R.drawable.stat_sample)  // the status icon
                      .setTicker(text)  // the status text
                      .setWhen(System.currentTimeMillis())  // the time stamp
                      .setContentTitle(getText(R.string.local_service_label))  // the label of the entry
                      .setContentText(text)  // the contents of the entry
                      .setContentIntent(contentIntent)  // The intent to send when the entry is clicked
                      .build();
  2. 让Service变成一个前台Service,并会将通知显示出来
    • startForeground(R.string.remote_service_started, notification);   //等价于NotificationManager.notify(int, Notification)
  3. 让Service变成一个后台Service,并会将通知从通知栏撤销
  • stopForeground(true); //该动作不会使得Service被destroy但是将Service转为后台应用

远程Service和本地Service的优劣比较

ANR问题

ANR问题,本地Service会运行本进程的主线程即UI线程中,因此运行耗时程序,触发ANR;如果是远程Service则阻塞的是另外一个进程的主线程,对当前进程无影响,因此不会触发ANR;

远程Service比本地Service要好?

其实远程Service实现起来比本地Service要复杂一点,大体流程如下,具体实现代码参考:

本地service:

  • 写一个继承Service类的子类
  • xml文件注册该Serive
  • 客户端startService、bindServcie;传入的intent为(this. MyService.class)的形式

远程Service:

  • 写一个aidl文件(RemoteServce.aidl),内容就是定义的一个普通java接口的代码;随后编译得到一个对应同名的java文件(RemoteService.java)
  • 写一个实现了RemoteService.Stub接口的类(RemoteServiceImp)
  • 写一个继承Service类的子类,该类中有一个RemoteServiceImp的对象,并在onBind方法中返回该对象
  • xml注册上面的service:注意添加标签android:process = ":remote" <intent-flter> <action>android:name = "com.evan.MyService"</action></Intent-filter>
  • 客户端startService、bindServcie;传入的intent为(this. "com.evan.MyService")的形式
  • ServiceConnection中得到的IBinder对象,转换RemoteServiceImp remoteService = RemoteService.Stub.AsInterface(ibinder);

Client和Service之间通信方式的概述:

  • 通过startAcitvity启动Service,可以传输一个Intent过去;这是单向的传输,适用于命令模式;
  • 通过bindActivity启动Service,可以利用ServiceConnection接口,回调得到Iservice对象(注意这里的Iservice是我们定义的一个接口),通过该对象我们可以获取到所有Service向外界提供的服务;
    • 用法一:(Android关于Serive给的例子中有这个案例)

      • 获得来自Service的一个android.os.Messenger对象;该Messenger跟Handler使用方法类似,其实Messenger的某一个构造器参数就可以是一个Handler对象;
      • 这样我们就可以利用该Messenger向Remote Service发送信息了;
      • Client也可以创建一个Messenger,将该Messenger注册到Remote Service那边,这样Service就可以通过这个Messenger向Client发送数据了;上面就实现了双向通行
      • 注意:服务端Messager就是通过Handler来构建的;利用mMessenger.getBinder()返回IBinder对象;客户单使用IBinder对象构造出Messager对象;而且Messager实现了Parcel接口!!意味着可以利用Binder在进程间进行传递了。
    • 用法二:利用获得的Iservice对象,调用其中的服务接口,获取相关数据,或者发送某种命令;
      • 跟StartActivity的区别:可以得到服务的返回值,因为是实实在在的调用了Service的一个方法;
      • 跟StartActivity相同的地方:Client占据了主动权;
时间: 2024-10-03 09:55:57

Android-Service必须掌握的几点知识的相关文章

Android Service基本知识总结(一)

一.简介 Service是Android系统的后台服务组件,适用于开发无界面.长时间运行的应用功能Service特点如下: 没有用户界面 不会轻易被Android系统终止 在系统资源恢复后Service也将自动恢复 运行状态 可用于进程间通信 二.生命周期 创建MyService extends Service 清单文件中注册: <service android:name=".MyService"/> 两种启动方式: 1.startService(Intent servic

Android Service 服务(一)—— Service

一. Service简单介绍 Service是android 系统中的四大组件之中的一个(Activity.Service.BroadcastReceiver.ContentProvider),它跟Activity的级别差点儿相同,但不能自己执行仅仅能后台执行,而且能够和其它组件进行交互.service能够在非常多场合的应用中使用,比方播放多媒体的时候用户启动了其它Activity这个时候程序要在后台继续播放,比方检測SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务总是藏在

Android Service使用详解

Service是Android系统中的四大组件之一,主要有两个应用场景:后台运行和跨进程访问.Service可以在后台执行长时间运行操作而不提供用户界面,除非系统必须回收内存资源,否则系统不会停止或销毁服务.服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行. 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC) 需要注意的是,Service是在主线程里执行操作的,可能会因为执行耗时操作而导致ANR 一.基础知识 Service可以分为以下三种形式

每个Android开发者必须知道的内存管理知识

原文:每个Android开发者必须知道的内存管理知识 拷贝在此处,以备后续查看. 相信一步步走过来的Android从业者,每个人都会遇到OOM的情况.如何避免和防范OOM的出现,对于每一个程序员来说确实是一门必不可少的能力.今天我们就谈谈在Android平台下内存的管理之道,开始今天的主题之前,先再次回顾两个概念. 内存泄漏:对象在内存heap堆中中分配的空间,当不再使用或没有引用指向的情况下,仍不能被GC正常回收的情况.多数出现在不合理的编码情况下,比如在 Activity中注册了一个广播接收

Android Service AIDL 远程调用服务 简单音乐播放实例的实现

Android Service是分为两种: 本地服务(Local Service): 同一个apk内被调用 远程服务(Remote Service):被另一个apk调用 远程服务需要借助AIDL来完成. AIDL 是什么 AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码.如果在一个进程中(例如Activi

Android Service完全解析,关于服务你所需知道的一切(下) (转载)

转自:http://blog.csdn.net/guolin_blog/article/details/9797169 转载请注册出处:http://blog.csdn.net/guolin_blog/article/details/9797169 在 上一篇文章中,我们学习了Android Service相关的许多重要内容,包括Service的基本用法.Service和Activity进行通信.Service的销毁方式. Service与Thread的关系.以及如何创建前台Service.以上

Android Service完全解析,关于服务你所需知道的一切(上)

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11952435 相信大多数朋友对Service这个名词都不会陌生,没错,一个老练的Android程序员如果连Service都没听说过的话,那确实也太逊了.Service作为Android四大组件之一,在每一个应用程序中都扮演着非常重要的角色.它主要用于在后台处理一些耗时的逻辑,或者去执行某些需要长期运行的任务.必要的时候我们甚至可以在程序退出的情况下,让Service在后台继续保持

Android Service完全解析,关于服务你所需知道的一切(下)

转载请注册出处:http://blog.csdn.net/guolin_blog/article/details/9797169 在上一篇文章中,我们学习了Android Service相关的许多重要内容,包括Service的基本用法.Service和Activity进行通信.Service的销毁方式.Service与Thread的关系.以及如何创建前台Service.以上所提到的这些知识点,基本上涵盖了大部分日常开发工作当中可能使用到的Service技术.不过关于Service其实还有一个更加

Android Service演义

摘要: 本文基于Android 5.1代码,介绍了Android Service的运作机理.按理说,网上此类文章已经很多了,本不需我再赘述.但每个人理解技术的方式多少会有所不同,我多写一篇自己理解的service,也未尝不可吧. (本文以Android 5.1为准) 侯亮 1.概述 在Android平台上,那种持续性工作一般都是由service来执行的.不少初学者总是搞不清service和线程.进程之间的关系,这当然会影响到他们开展具体的开发工作. 其实,简单说起来,service和线程.进程是

浅谈 Android Service

 浅谈Android Service的基本用法: 关于Service最基本的用法自然是启动和停止操作. 启动Service有两种方式: 1.通过startService(Intent intent)方式启动,启动时会自动执行onCreate(),onStartCommand()方法. 2.通过bindService(Intent intent,ServiceConnection connection,int flag) 第一个参数是一个Intent对象,第二个参数是连接Service的实例,