Service的常见用法分析

简介
Service四大组件之一,主要用于后台处理一些耗时的逻辑,或者去执行某些需要长期运行的任务。必要的时候我们甚至可以在程序退出的情况下,让Service在后台继续保持运行状态。例如:上传图片,大量计算,保活;Service后台执行任务,但是运行在主线程中,如果需要执行耗时任务,需要开启子线程;
Android的后台指:它的运行不依赖UI,即使Activity被销毁,或者程序关闭,只要进程还在,Service依然可以正常运行;例如,需要与服务器保持心跳连接,就可以用Service来实现,在Service中开启子线程;
Service的优势:所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例

声明周期
Service的常见用法分析Service的常见用法分析Service的常见用法分析Service的常见用法分析Service的常见用法分析
基本用法
开启方式:
1) startService(Intent intent) --stopService(Intent intent) :
on Create(只执行一次)-- onStartCommand(Intent intent)(每次都执行)--onDestory();
2)bindService(Intent service,ServiceConnection conn,int flag) --unBindService(ServiceConnection conn): 
onCreate() -- onBind(Intent intent)--onUnBind(Intent intent)--onDestory();
两种启动Service方式的区别:
1):启动Service,onCreat或onStartCommand() 里面执行具体逻辑,Service和Activity的关系并不大,只是通知Service可以干活了;
2):可以通过ServiceConnection里面的onServiceConnected 调用Service里的方法;一旦绑定成功,ServiceConnection接口中的onServiceConnected()就立刻执行;

进程内Service和Activity通信
分为两种情况:
1:Activity向Service传递消息的方法:
    1)利用BroadcastReceiver发送广播,Activity发送广播,Service中定义广播接收者进行接收。
   2)利用绑定服务的方式开启服务,暴露服务中的方法,Activity进行调用。
  3)利用Intent打开服务(开启服务)的方式,通过Intent传递数据,分别在onStartCommand(Intent intent)和onBind()可以通过intent获取到信息;onCreate()内无法获取到Intent实例

Activity向服务传递消息,暴露服务中的方法:
Activity
private ServiceConnection connection = new ServiceConnection() {
   @Override
   public void onServiceDisconnected(ComponentName name) {// 解除关联
   }
   @Override
   public void onServiceConnected(ComponentName name, IBinder service) {//建立关联
     myBinder = (MyService.MyBinder) service;
     myBinder.startDownload();
   }
};
Service
private MyBinder mBinder = new MyBinder();
  @Override
  public IBinder onBind(Intent intent) {
    return mBinder;
  }
class MyBinder extends Binder {
  public void startDownload() {
    Log.d("TAG", "startDownload() executed");
    // 执行具体的下载任务
  }
}
通过上面的方式,可以在Activity中根据具体的场景来调用MyBinder中的任何public方法,即实现了Activity指挥Service干什么Service就去干什么的功能
2:Service向Activity传递消息的方法:
    1)利用BroadcastReceiver,在Service中发送广播,Activity中接收。
    2)回调的方式 
2)回调的方式,Service更新UI。
Service 
public ServiceCallBack serviceCallBack;
public interface ServiceCallBack {
  void serviceCallBack(String string);
}
public void setServiceListener(ServiceCallBack serviceCallBack) {
  this.serviceCallBack = serviceCallBack;
}

//通信的桥梁
class MyBinder extends Binder {
  /**
  *获取当前Service的实例
  *@return
  */
  public InnerService getService() {
    return InnerService.this;
  }
  public void tell() {
    Log.d(TAG, "我执行了");
      //TODO 
      //方式一:广播
      //Intent intent = new Intent("InnerService");
      //sendBroadcast(intent);
      //方式二: 回调
      if (serviceCallBack != null) {
        serviceCallBack.serviceCallBack("通过回调,我执行了");
     }
  }
}

Activity
//和服务组件间通信
private ServiceConnection serviceConnection = new ServiceConnection() {
  private InnerService.MyBinder myBinder;
  @Override
  public void onServiceConnected(ComponentName name, IBinder service) {
    myBinder = (InnerService.MyBinder) service;
    InnerService service1 = myBinder.getService();
    service1.setServiceListener(new InnerService.ServiceCallBack() {
      @Override
      public void serviceCallBack(String string) {
       Log.d(TAG, "serviceCallBack::" + string);
       //改变UI
      }
    });
    //监听之后 在调用
    myBinder.tell();
  }
  @Override
  public void onServiceDisconnected(ComponentName name) {
   Log.d(TAG, "onServiceDisconnected");
   myBinder = null;
  }
};
Service销毁
思考:1:如果bindService(),点击stopService,服务会销毁吗?
不会,两种开启方式,只能用对应的停止方式,关闭Service;
2: startService,bindService 都执行了,Service怎么才能销毁?
如果我们既点击了Start Service按钮,又点击了Bind Service按钮会怎么样呢?这个时候你会发现,不管你是单独点击Stop Service按钮还是Unbind Service按钮,Service都不会被销毁,必要将两个按钮都点击一下,Service才会被销毁。也就是说,点击Stop Service按钮只会让Service停止,点击Unbind Service按钮只会让Service和Activity解除关联,一个Service必须要在既没有和任何Activity关联又处理停止状态的时候才会被销毁。即:先点击一下Start Service按钮,再点击一下Bind Service按钮,这样就将Service启动起来,并和Activity建立了关联。然后点击Stop Service按钮后Service并不会销毁,再点击一下Unbind Service按钮,Service就会销毁了;

Service和Thread的关系
Service和Thread没有任何关系,什么时候用Service呢?
Service运行在主线程,如果在Service中做耗时操作,肯定会报ANR;
既然在Service里也要创建一个子线程,那为什么不直接在Activity里创建呢?这是因为Activity很难对Thread进行控制,当Activity被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例。而且在一个Activity中创建的子线程,另一个Activity无法对其进行操作。但是Service就不同了,所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例。因此,使用Service来处理后台任务,Activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况。

参考文档

如有问题,请多指教,谢谢!