AndroidService 相关知识
启动一个 Service
MyServices.java
必须继承自 Service,或者如 IntentService 本身就是等其子类
public class MyServices extends Service { @Nullable @Override public IBinder onBind(Intent intent) { Log.d("TAG","onBind"); return null; } @Override public void onCreate() { super.onCreate(); Log.d("TAG","onCreate"); } @Override public void onDestroy() { super.onDestroy(); Log.d("TAG", "onDestroy: "); } }AndroidManifest.xml
注册 MyServices
<application> <service android:name=".MyServices" android:exported="true"> <intent-filter> <action android:name="cf.android666.myservices" /> </intent-filter> </service> </application>MainActivity.java
在 java 中调用 Service,需要
ServiceConnection类ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d(TAG, "onServiceConnected: 服务绑定"); } @Override public void onServiceDisconnected(ComponentName name) { Log.d(TAG, "onServiceDisconnected: 服务解绑"); } }; Intent intent = new Intent(context, MyServices.class); bindService(intent, mConnection, Service.BIND_AUTO_CREATE);//绑定 Service //startService(intent); 启动 service unbindService(mConnection);//解绑 ServicebindService()和startService()的区别在于:**
bindService()将 service 和当前的 activity 绑定在一起,activity 销毁时,service 也会被销毁;**
startService()则只是“启动”service,在此后 service 的活动和 activity 无关,并一直存活。
Service 具体分析
Service 在 AndroidManifest.xml 中的属性:
android:name=".MyService"//必须被指定
android:exported=true/false //是否能被其他应用隐式调用
//有 intent-filter 则默认为 true,否则默认 false;若手动指定为 false 则即使有 intent-filter 也无法隐式调用
android:process="remote"/":remote"//前者在共有的进程中进行,后者在名字为{packageName}:remote 的私有进程中进行,其他进行不可访问;如果不设置该属性,则 service 在应用自己的进程里面运行Service 默认运行在创建他的线程中,要是进行耗时操作,最好在 service 中单独创建一个线程,这样子可以在子线程工作,在主线程中更新工作进度。
Service 中的方法:
//在初次创建服务时调用,并且直至服务死亡,只会被调用一次
void onCreate()
//在绑定服务是才会被调用,必须实现该方法
IBinder onBind(Intent intent)
//每一次通过 startService() 方法启动 Service 的时候都会被调用
int onStartCommand(Intent intent, int flags, int startId)
  //1.intent 启动时,启动组件传递过来的 Intent
  //2.flags 表示启动请求时是否有额外数据,可以是:
  //  0:无
  //  START_FLAG_REDELIVERY:表示该方法返回值为 START_REDELIVER_INTENT,在上个服务被杀死之前调用 stopSelf() 停止服务
  //  START_FLAG_RETRY:在 onStartCommand() 被调用后一直无返回值时,会尝试重新调用 onStartCommand()
  //3.当前服务 id其中onStartCommand()方法的返回值意义如下:
START_STICKY :service 在内存不足被杀死后,内存空闲时系统会重新创建 service,一旦成功创建会回调onStartCommand()方法,此时 intent 是 null,除非是挂起的 intent 如 pendingintent,无限期运行
START_NOT_STICKY:service 因内存不足被杀死,内存再次空闲系统也不会再重新创建服务,最安全
START_REDELIVER_INTENT:service 因内存不足被杀死,会重建服务并传递给最后一个 intent(最后一次调用startService() 时的 intent),用于连续作业,如下载等
Service 绑定服务的三种方式
1.拓展 Binder 类
要求客户端和服务在同一应用的同一进程内。客户端通过其访问 service 中的公共方法。
步骤如下:
- 创建 BindService 服务端,在类中创建一个实现了 IBinder 接口的实力对象并提供公共方法给客户端使用
 - 在 onBind() 回调方法返回此 Binder 实例
 - 在客户端的 onServiceConnected() 方法接收 Binder,使用提供的方法绑定服务
 
//service 服务端
public class LocalService extends Service{
  LocalService mService;
  private LocalBinder binder = new LocalBinder();
  ...
  public IBinder onBind(Intent intent){
    return binder;
  }
  public void doSomeThing(){
    //服务中公共方法,可以被客户端通过 IBInder 获取实例调用
  }
  public class LocalBinder extends Binder{
    LocalService getService(){
      return LocalService.this;
    }
  }
}
//客户端
public class BindActivity extends Activity{
  protected void onCreate(...){
    ServiceConnection conn = new ServiceConnection(){
      //绑定服务时被调用,实现客户端和服务端交互(IBinder)
      public void onServiceConnected(ComponentName name, IBinder service){
        LocalService.LocalBinder binder = (LocalService.LocalBinder)service;//获取服务端 IBinder
        mService = binder.getService();//获取服务实例,以调用服务的公共方法
      }
      //取消绑定时回调,多数时候是 service 被意外销毁,如内存不足
      //当客户端取消绑定时,系统“绝对不会”调用该方法。
      public void onServiceDisconnected(ComponentName name){
        mService = null;
      }
    };
    //创建绑定对象
    Intent intent = new Intent(this,LocalService.class);
    //绑定服务
    //参数 3 flags 则是指定绑定时是否自动创建 Service。0 代表不自动创建、BIND_AUTO_CREATE 则代表自动创建
    bindService(intent,conn,Service.BIND_AUTO_CREATE);
    //调用服务中的方法,最好先判断是否为 null
    mService.doSomeThing();
    //解除绑定
    unbindService(conn);
  }
}2.Messenger
service 与不同进程通信(IPC) 。
步骤如下:
- Service 实现一个 Handler,接收客户端每个调用的回调
 - 用 Handler 创建 Messenger 对象
 - 用 Messenger 创建 IBinder 对象,并通过 onBind() 返回客户端
 - 客户端使用 IBinder 实例化 Messenger,用其将 Message 对象发送给 Service
 - Service 在 Handler 接收并处理 Message
 
//Service
public class MessageService extends Service{
  public final static int MSG_WHAT = 1;
  //创建 Handler 接收、处理客户端 msg
  class IncomingHanler extends Handler{
    public void handleMessage(Message msg){
      //do sth with msg...
    }
  }
  Messenger messenger = new Messenger(new IncomingHanlder());
  public IBinder onBind(Intent intent){
    return messenger.getBinder();
  }
}
//客户端
//onCreate() 方法中:
mConnection = new ServiceConnection(){
  public void onServiceConnected(ComponentName className, IBinder service){
    Messenger mService = new Messenger(service);
  }
};
//给服务发消息
Message msg = Message.obtain(null,MessengerService.MSG_WHAT,0,0);
mService.send(msg);注意 service 要在不同的进程中:
AndroidMinafast.xml
<service android:name=".messenger.MessengerService"
         android:process=":remote"
        />服务与客户端双向通信
服务端,修改 IncomingHandler,回复客户端消息
class IncomingHandler extends Handler{
  public void handleMessage(Message msg){
    //回复消息
    Messenger client = msg.replyTo;
    Message replyMsg = Message.obtain(null,MessengerService.MSG_WHAT);
    Bundle bundle = new Bundle();
    bundle.putString("key","value");
    replyMsg.setData(bundle);
    try{
      client.send(replyMsg);
    }catch(){}
  }
}客户端,增加 Messenger 和 Handler 处理服务端回复
private static class RecyclerReplyMsgHandler extends Hanlder{
  public void handleMessage(Message msg){
    //接收服务端返回的 msg
  //do sth ...
  }
}
private Messenger mRecevierReplyMsg = new Messenger(new RecyclerReplyMsgHandler());此外,在发送消息是需要将接收服务端回复的 Messenger 通过 Message 的 replyTo 传递给服务端
//create msg...
msg.replyTo = mRecevierReplyMsg;
//send msg...3.AIDL
一般不会使用,具体使用可以参考这篇文章
绑定服务时的注意事项
- 多个客户端可连接一个服务端,只有第一个客户端绑定时才会调用服务
onBind()方法来检索 IBinder,此后无需调用就可将同一个 IBinder 传递给其他客户端 bindService()绑定服务是异步进行的- 一般在 activity 可见生命周期内绑定 - 取消服务,不要在
onResume()、onPause()期间执行绑定/解绑 
Service 绑定和启动转换
| 顺序 | 结果 | 
|---|---|
| 先绑定后启动 service | 启动 service | 
| 先启动后绑定 service | 会绑定宿主,但是宿主死后仍按照启动 service 方式存活 | 
前台服务和通知
- startForeground(int id, Notification notification)
 
该方法的作用是把当前服务设置为前台服务,其中 id 参数代表唯一标识通知的整型数,需要注意的是提供给 startForeground() 的整型 ID 不得为 0,而 notification 是一个状态栏的通知。- stopForeground(boolean removeNotification)
 
该方法是用来从前台删除服务,此方法传入一个布尔值,指示是否也删除状态栏通知,true 为删除。注意该方法并不会停止服务。但是,如果在服务正在前台运行时将其停止,则通知也会被删除。
文章参考:
