安卓开发之服务Service

一、Service是什么?

  1. Service是一个应用组件,它用来在后台完成一个时间跨度比较大的工作,且没有关联任何界面。(生命周期在应用程序进程的主线程运行)
  2. 一个Service可以完成的工作:访问网络(在Service中启动分线程)、播放音乐、文件IO操作、大数据量的数据库操作等。如果需要在Service中处理一些网络连接等耗时的操作,那么应该将这些任务放在分线程中处理,避免在主线程中阻塞用户界面。
  3. 特点:Service在后台运行,不用与用户进行交互。即使应用退出,服务也不会停止。当应用进程被杀死时(例如一键清理),服务便会停止。

二、Service的分类

  1. Local Service (本地服务)
    Service对象与Service的启动者在同个进程中进行,两者的通信是进程内的通信。
  2. Remote Service (远程服务)
    Service对象与Service的启动者不在同个进程中进行,这时存在一个进程间的通信问题,Android专门为此设计了AIDL来实现进程间的通信。

三、Service的定义

  1. 定义一个类继承于Service类,重写方法。

    public class MusicService extends Service {
    
        public MusicService(){
    
            Log.i("TAG","MusicService");
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            Log.i("TAG","onBind");
            return new Binder();
           //return 到ServiceConnection的onServiceConnected中
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            Log.i("TAG","onCreate");
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
    
            Log.i("TAG","onStartCommand");
            return super.onStartCommand(intent, flags, startId);
            //返回值不同,Service被杀掉的情况也不同
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.i("TAG","onDestroy");
        }
    
        @Override
        public boolean onUnbind(Intent intent) {
    
            Log.i("TAG","onUnbind");
            return super.onUnbind(intent);
        }
    
    }
    
  2. AndroidManifest.xml中配置Service

    <service android:name="com.cxmscb.cxm.moodmusic.MusicService" />
    <!--本地Service不需要intent-filter-->
    
    <!--可以使用process标签让服务运行在另一个进程-->
    <service android:name="com.cxmscb.cxm.moodmusic.MusicService"
        android:process=":remote"
        />
    
  3. 注意:onStartCommand()方法必须返回一个整数,这个整数是一个描述了在系统的杀死事件中,系统应该如何继续这个服务的值。从onStartCommand()方法中返回的值必须是以下常量:

    START_NOT_STICKY
    如果系统在onStartCommand()方法返回之后杀死这个服务,那么直到接受到新的Intent对象,这个服务才会被重新创建。
    
    START_STICKY
    如果系统在onStartCommand()返回后杀死了这个服务,系统就会重新创建这个服务并且调用onStartCommand()方法,但是它不会重新传递最后的Intent对象,系统会用一个null的Intent对象来调用onStartCommand()方法。
    在这个情况下,除非有一些被发送的Intent对象在等待启动服务。这适用于不执行命令的媒体播放器(或类似的服务),它只是无限期的运行着并等待工作的到来。
    
    START_REDELIVER_INTENT
    如果系统在onStartCommand()方法返回后,系统就会重新创建了这个服务,并且用发送给这个服务的最后的Intent对象调用了onStartCommand()方法。任意等待中的Intent对象会依次被发送。这适用于那些应该立即恢复正在执行的工作的服务,如下载文件。
    

四、启动/停止服务Service

  1. Service分为两种工作状态,一种是启动状态,主要用于执行后台计算;另一种是绑定状态,主要用于其他组件和Service的交互。

  2. Service的这两种状态是可以共存的,即Service既可以处于启动状态也可以同时处于绑定状态。

    启动服务:(不绑定)

    Intent intent = new Intent(this,MusicService.class);
    this.startService(intent);
    //通过intent信使来启动
    

    停止服务:

    Intent intent = new Intent(this,MusicService.class);
    this.stopService(intent);
    //通过intent信使来停止
    // 也可以在Service中调用 stopSelf() 来停止服务
    

    绑定服务:

    ServiceConnection serviceConnection;
    
    // 与Activity绑定服务来启动服务
    
    Intent intent = new Intent(this,MusicService.class);
    
    if(serviceConnection==null){
    
        serviceConnection = new ServiceConnection() {
    
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            //当Activity与服务连接上时回调。 
            //onBind() --> onServiceConnected()
            //iBinder为Service中的onBind返回的iBinder
        }
    
        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            //当Activity与服务断开后回调。
        }
    };
        this.bindService(intent,serviceConnection,Context.BIND_AUTO_CREATE);
    

    解绑服务:

    //当Activity销毁时,要与绑定的服务Sercive解绑,否则会报错
    
    if(serviceConnection!=null){
    
        Intent intent = new Intent(this,MusicService.class);
        this.unbindService(intent,serviceConnection);
        serviceConnection = null;
    
    }
    

五、Service的生命周期

因启动服务的方式不同,Service的生命周期也不同。

这里写图片描述

  1. startService
    第一次启动服务: —>构造方法—>onCreate—>onStartCommand
    再次启动该服务:—>onStartCommand

    stopService( )
    调用:—>onDestory

  2. bindService
    调用:—>构造方法—>onCreate—>onBind—->onServiceConneted

    unbindService
    调用:(当前Activity与该Service连接)—>onUnbind—>onDestory

六、Activity与Service的数据交流

  1. Activity传数据给Service:在启动服务时通过Intent传递数据。(注意第一次启动服务时和再次启动服务时的方法调用区别。)

  2. Service传即时数据给Activity:Service可以通过特定广播来传递即时数据给接收特定广播的Activity,发送广播时也会带有Intent对象,可通过Intent携带数据。

  3. 当Activity和Service绑定时,可以通过Binder来链接Service和Activity,通过Binder来返回绑定的Service来获取Service对象内部的数据。

    a。使用Binder扩展类对象进行交流:返回Service对象(非跨进程)

    @Override
        public IBinder onBind(Intent intent) {
            Log.i("TAG","onBind");
            return new LocalBinder();
           //return 到ServiceConnection的onServiceConnected中
        }
    
    ------------------------------------------------------------
    // MyService的内部类LocalBinder
    public class LocalBinder  extends Binder{
    
            public MyService getService(){
    
                    return MyService.this;
            }
    
    }
    ---------------------------------------------------------------------- 
    
    MyService service = null;
    
    // 在Activity绑定服务时需要的ServiceConnection中的onServiceConnected方法
    
    @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            //当Activity与服务连接上时回调。 
            //onBind() --> onServiceConnected()
            //iBinder为Service中的onBind返回的iBinder
    
            MyService.LocalBinder  localBinder  = (MyService.LocalBinder)iBinder;
            service = localBinder.getService();
    
    
    
        }       
    

    b. 使用AIDL / Messenger 进行跨进程交流

    使用Messenger进行交流:

    1. 服务端实现一个 Handler,由其处理来自客户端的消息Message

      class ServiceHandler extends Handler {
          @Override
          public void handleMessage(Message msg) {
              switch (msg.what) {
                  case 0:
                      Log.i(TAG, "thanks,Service had receiver message from client!");
                      break;
                  default:
                      super.handleMessage(msg);
              }
          }
      }
      
    2. 在服务端将 Handler实例 封装为 Messenger 对象

      Messenger mMessenger = new Messenger(new ServiceHandler());
      
    3. 获取Messenger的IBinder实例,在 onBind() 中将其返回客户端

      @Override
      public IBinder onBind(Intent intent) {
          return mMessenger.getBinder();
      }
      
    4. 客户端获取 IBinder 对象后将其 再封装 Messenger 对象,然后使用Messenger将 Message 对象发送给服务端

      /**
       * 与服务端交互的Messenger
       */
      Messenger mMessenger = null;    
      
      private ServiceConnection mConnection = new ServiceConnection() {
          public void onServiceConnected(ComponentName className, IBinder service) {
              /**
               * 通过服务端传递的IBinder对象,封装为相应的Messenger
               */
              mMessenger = new Messenger(service);
      
          }
      
          public void onServiceDisconnected(ComponentName className) {
               mMessenger = null;
          }
      };
      
      
      // 使用mMessenger发送消息 :
      .... // 创建Messager对象msg
      // 发送msg对象,由服务端的Handler来处理消息
      mMessenger..send(msg) ;
      

      (同理可以在客户端创建客户端的Handler和Messenger,将Messenger对象通过消息msg传递给服务端,服务端再使用客户端的Messenger对象来发送消息)

    使用AIDL进行交流:

七、前台服务

将服务置为前台状态,可对服务的进程进行提权,即在内存不足时,系统也不会考虑将其进程终止。不过将服务置为前台时,需要在状态栏中显示一个通知Notification来告知用户。

  • startForeground(int id, Notification notification)

    把当前服务设置为前台服务,其中id参数代表唯一标识通知的整型数(不可以为 0),notification是一个状态栏的通知实例。
    
  • stopForeground(boolean removeNotification)

    将处于前台状态的服务降权,恢复原来的状态。方法传入一个布尔值,表示是否删除状态栏通知,true为删除。 (该方法并不会停止服务) 
    

八、IntentService

  1. IntentService是Service类的子类,为异步服务。可以通过startService(Intent)方法传递请求给IntentService。
  2. 可以在IntentService实现虚函数onHandleIntent,在里面根据Intent的不同进行不同的处理,按队列来一一处理。当执行完一个Intent请求对象所对应的工作之后,如果没有新的Intent请求达到,则自动停止Service;否则执行下一个Intent请求所对应的任务。
  3. 使用场景:需要将任务按队列来排列处理时,可以用IntentService。
  4. IntentService默认实现了Onbind()方法,返回值为null。
  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值