关于Service你所需要知道内容(一)

2018-07-19  本文已影响0人  帝王鲨kingcp

根据下面的目录来介绍和理解Service中的知识点:

一.Service的两种生命周期

service启动有两种方式:启动服务startService,绑定服务bindService。有不同是生命周期,如下所示:


image
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);
  1. 绑定服务,首先要做的事情就是先用Map记录当前绑定服务所需的一些信息。 然后启动服务。
  2. 解绑服务,先从早前的Map集合中移除记录,然后停止服务。
  3. 如果再次解绑,无非就是再到这个map集合中找找有没有这条记录,没有就抛出服务没有注册的异常,也就是早前根本没有注册过任何服务。

三.远程服务

下图是根据不同方式对服务的分类,这里重点介绍实现远程服务


服务分类.png

实现远程服务的代码:

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原理

上一篇下一篇

猜你喜欢

热点阅读