根据下面的目录来介绍和理解Service中的知识点:
一.Service的两种生命周期
service启动有两种方式:启动服务startService,绑定服务bindService。有不同是生命周期,如下所示:
1.若一个Service被多次startService启动,onCreate被调用一次,只有onStartCommand被调用多次。
2.onStartCommand必须放回一个整数=描述系统在杀死服务后应该如何继续运行:
a.START_NOT_STICKY;不会重建服务,除非还存在未发送的intent。当服务不再是必需的,并且应用程序能够简单地重启那些未完成的工作时,这是避免服务运行的最安全的选项。
b.START_STICKY;如果系统在onStartCommand()返回后杀死了这个service,会重新创建这个service并且调用onStartCommand(),但是不再重新发送上次最后一个intent,而是使用一个nullintent调用onStartCommand(),除非有一些挂起的intent,在此情况下,这些挂起的intent被派送。(适用媒体播放器类似服务,它们不执行命令,但需要一直运行并随时待命)
c.START_REDELIVER_INTENT;如果系统在onStartCommand()返回后杀死了service,重新创建这个service并且使用上次最后一个intent调用onStartCommand().任何挂起的intent都顺序地被派送。(这适合于活跃地执行一个工作并且应被立即恢复的服务,比如下载一个文件)
3.启动并绑定一个service,如果没有解绑,调用stopService无法杀死服务。
4.unBindService()解除绑定服务,内部调用服务的生命周期方法onUnbind(),然后调用onDestory()销毁服务。服务只能被解除绑定一次,如果unBindService方法被调用多次,就会出错。
5.startService启动服务,调用者退出,service依旧还在;bindService绑定服务,调用者退出,service也就退出。
二.Service的两种启动方式
启动服务startService代码
Intent intent = new Intent(TestActivity.this,TestService.class);
startService(intent);
绑定服务bindService代码
private ServiceConnection mTestServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
myBinder = (TestService.MyBinder) iBinder;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
Intent intent = new Intent(TestActivity.this,TestService.class);
bindService(intent,mTestServiceConnection,BIND_AUTO_CREATE);
- 绑定服务,首先要做的事情就是先用Map记录当前绑定服务所需的一些信息。 然后启动服务。
- 解绑服务,先从早前的Map集合中移除记录,然后停止服务。
- 如果再次解绑,无非就是再到这个map集合中找找有没有这条记录,没有就抛出服务没有注册的异常,也就是早前根本没有注册过任何服务。
三.远程服务
下图是根据不同方式对服务的分类,这里重点介绍实现远程服务
实现远程服务的代码:
AIDL代码
// IRemoteService.aidl
package com.example.chenpeng.julyapplication.service;
// Declare any non-default types here with import statements
import com.example.chenpeng.julyapplication.IParticipateCallback;
interface IRemoteService {
int add(int a , int b);
void join(IBinder token,String userName);
void leave(IBinder token);
List<String> getParticipators();
void registerParticipateCallback(IParticipateCallback cb);
void unregisterParticipateCallback(IParticipateCallback cb);
}
创建完AIDL文件以后,点击Build->Rebuild Project,在app\build\generated\source\aidl\debug中会有对应的ADIL的Java接口文件。生成如下代码:
package com.example.chenpeng.julyapplication.service;
public interface IRemoteService extends android.os.IInterface
{
/** 内部类Stub,继承Binder */
public static abstract class Stub extends android.os.Binder implements com.example.chenpeng.julyapplication.service.IRemoteService
{
/**Binder的唯一标识,一般用当前的类名表示*/
private static final java.lang.String DESCRIPTOR = "com.example.chenpeng.julyapplication.service.IRemoteService";
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* 用于将服务端的Binder对象转换成客户端所需的AIDL接口类型的对象,这种转换过程区分进程
* 如果客户端和服务端位于同一个进程,返回服务端的Stub对象本身;否则返回系统封装后的Stub.proxy对象
*/
public static com.example.chenpeng.julyapplication.service.IRemoteService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.chenpeng.julyapplication.service.IRemoteService))) {
return ((com.example.chenpeng.julyapplication.service.IRemoteService)iin);
}
return new com.example.chenpeng.julyapplication.service.IRemoteService.Stub.Proxy(obj);
}
/**返回当前Binder对象*/
@Override public android.os.IBinder asBinder()
{
return this;
}
/**
* 这个方法运行在服务端中的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法处理。
* 通过code可以确定调用哪个方法,如有入参,从data中获取,方法完成后,如需要返回参数,将参数存入result中。
* 若果,onTransact返回false,则客户端的请求失败,因此可以利用这个特征来做权限验证。
* */
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_add:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.add(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_join:
{
data.enforceInterface(DESCRIPTOR);
android.os.IBinder _arg0;
_arg0 = data.readStrongBinder();
java.lang.String _arg1;
_arg1 = data.readString();
this.join(_arg0, _arg1);
reply.writeNoException();
return true;
}
case TRANSACTION_leave:
{
data.enforceInterface(DESCRIPTOR);
android.os.IBinder _arg0;
_arg0 = data.readStrongBinder();
this.leave(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_getParticipators:
{
data.enforceInterface(DESCRIPTOR);
java.util.List<java.lang.String> _result = this.getParticipators();
reply.writeNoException();
reply.writeStringList(_result);
return true;
}
case TRANSACTION_registerParticipateCallback:
{
data.enforceInterface(DESCRIPTOR);
com.example.chenpeng.julyapplication.IParticipateCallback _arg0;
_arg0 = com.example.chenpeng.julyapplication.IParticipateCallback.Stub.asInterface(data.readStrongBinder());
this.registerParticipateCallback(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_unregisterParticipateCallback:
{
data.enforceInterface(DESCRIPTOR);
com.example.chenpeng.julyapplication.IParticipateCallback _arg0;
_arg0 = com.example.chenpeng.julyapplication.IParticipateCallback.Stub.asInterface(data.readStrongBinder());
this.unregisterParticipateCallback(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
/**
* 这个方法运行在客户端
* 先把参数写入_data中,接着调用transact方法发起RPC(远程过程调用)请求,同时当前线程挂起;然后服务端的onTransact方法被调用,
* 直到RPC过程返回后,当前线程继续执行,并从_reply中取出RPC过程的返回结果,最后返回_reply中的数据
* */
private static class Proxy implements com.example.chenpeng.julyapplication.service.IRemoteService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public int add(int a, int b) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(a);
_data.writeInt(b);
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void join(android.os.IBinder token, java.lang.String userName) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder(token);
_data.writeString(userName);
mRemote.transact(Stub.TRANSACTION_join, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public void leave(android.os.IBinder token) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder(token);
mRemote.transact(Stub.TRANSACTION_leave, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public java.util.List<java.lang.String> getParticipators() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<java.lang.String> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getParticipators, _data, _reply, 0);
_reply.readException();
_result = _reply.createStringArrayList();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void registerParticipateCallback(com.example.chenpeng.julyapplication.IParticipateCallback cb) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((cb!=null))?(cb.asBinder()):(null)));
mRemote.transact(Stub.TRANSACTION_registerParticipateCallback, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public void unregisterParticipateCallback(com.example.chenpeng.julyapplication.IParticipateCallback cb) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((cb!=null))?(cb.asBinder()):(null)));
mRemote.transact(Stub.TRANSACTION_unregisterParticipateCallback, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_join = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_leave = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_getParticipators = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
static final int TRANSACTION_registerParticipateCallback = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
static final int TRANSACTION_unregisterParticipateCallback = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
}
public int add(int a, int b) throws android.os.RemoteException;
public void join(android.os.IBinder token, java.lang.String userName) throws android.os.RemoteException;
public void leave(android.os.IBinder token) throws android.os.RemoteException;
public java.util.List<java.lang.String> getParticipators() throws android.os.RemoteException;
public void registerParticipateCallback(com.example.chenpeng.julyapplication.IParticipateCallback cb) throws android.os.RemoteException;
public void unregisterParticipateCallback(com.example.chenpeng.julyapplication.IParticipateCallback cb) throws android.os.RemoteException;
}
创建在服务端的Service代码
public class RemoteService extends Service {
private static final String TAG = "RemoteService";
private List<Client> mClient = new ArrayList<>();
private List<String> mList = new ArrayList<>();
//RemoteCallbackList,帮我自动处理了Link-To-Death的问题
private RemoteCallbackList<IParticipateCallback> mRemoteCallbackList = new RemoteCallbackList<>();
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
@Override
public int add(int a, int b) throws RemoteException {
return a+b;
}
@Override
public void join(IBinder token, String userName) throws RemoteException {
if(findClient(token) < 0){
Client client = new Client(token,userName);
//注册客户端死掉的通知
mClient.add(client);
client.mToken.linkToDeath( client,0);
Log.i(TAG, "join: client token = " + token + " 加入client队列");
notifyParticipate(client.mName,true);
}else{
Log.i(TAG, "join: client成员已存在");
}
}
@Override
public void leave(IBinder token) throws RemoteException {
int index = findClient(token);
if(index >= 0 ){
Client client = mClient.get(index);
//取消注册
client.mToken.unlinkToDeath( client,0);
mClient.remove(client);
Log.i(TAG, "leave: 删除token = " + token);
notifyParticipate(client.mName,false);
}
}
@Override
public List<String> getParticipators() throws RemoteException {
int size = mClient.size();
for(int i = 0 ; i < size ; i++){
mList.add(mClient.get(i).mName);
}
return mList;
}
@Override
public void registerParticipateCallback(IParticipateCallback cb) throws RemoteException {
mRemoteCallbackList.register(cb);
}
@Override
public void unregisterParticipateCallback(IParticipateCallback cb) throws RemoteException {
mRemoteCallbackList.unregister(cb);
}
};
//更新通知
private void notifyParticipate(String mName, boolean joinOrLeave) {
int length = mRemoteCallbackList.beginBroadcast();
for(int i = 0 ; i < length ; i++){
try {
//通知回调
mRemoteCallbackList.getBroadcastItem(i).onParticipate(mName,joinOrLeave);
} catch (RemoteException e) {
e.printStackTrace();
}
}
mRemoteCallbackList.finishBroadcast();
}
private int findClient(IBinder token){
int index = -1;
int size = mClient.size();
for(int i = 0 ; i < size ; i++){
if(mClient.get(i).mToken == token){
index = i;
}
}
return index;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind: 绑定服务" );
return mBinder;
}
@Override
public void onDestroy() {
super.onDestroy();
mRemoteCallbackList.kill();
}
private class Client implements Binder.DeathRecipient{
IBinder mToken;
String mName;
public Client(IBinder token , String name){
mToken = token;
mName = name;
}
@Override
public void binderDied() {
//客户端的异常退出
int index = mClient.indexOf(this);
if(index < 0){
return;
}
Log.i(TAG, "binderDied: 异常退出的客户端名字 = " + mName);
mClient.remove(index);
}
}
}
在服务端的AndroidMinfest.xml中做一下配置
<!-- 将本地服务设置成远程服务,设置可被其他进程调用-->
<service
android:name=".service.RemoteService"
android:process=":remote"
android:exported="true"
>
<intent-filter>
//此处Intent的action最好写成“服务器端包名.aidl文件名”的形式
<action android:name="com.example.chenpeng.julyapplication.service.IRemoteService"/>
</intent-filter>
</service>
创建客户端,一个不同的应用,首先将aidl文件复制到工程中,位置内容必须原封不动,下面就是client的代码
public class MainActivity extends AppCompatActivity {
private Button mBindServiceBtn,mMethodBtn;
private IRemoteService mRemoteService;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mRemoteService = IRemoteService.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBindServiceBtn = findViewById(R.id.bindServiceBtn);
mMethodBtn = findViewById(R.id.methodBtn);
mBindServiceBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//通过Intent指定服务端的服务名称和所在包,与远程Service进行绑定
//参数与服务器端的action要一致,即"服务器包名.aidl接口文件名"
Intent intent = new Intent("com.example.chenpeng.julyapplication.service.IRemoteService");
//Android5.0后无法只通过隐式Intent绑定远程Service
//需要通过setPackage()方法指定包名,否则启动失败
intent.setPackage("com.example.chenpeng.julyapplication");
bindService(intent,mServiceConnection,BIND_AUTO_CREATE);
}
});
mMethodBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(mRemoteService != null){
try {
int sum = mRemoteService.add(2,4);
Toast.makeText(getApplicationContext(),String.valueOf(sum),Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
}
}
四.IntentService原理
参考这篇IntentService原理