美文网首页
关于Service你所需要知道内容(一)

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

作者: 帝王鲨kingcp | 来源:发表于2018-07-19 14:11 被阅读0次

    根据下面的目录来介绍和理解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原理

    相关文章

      网友评论

          本文标题:关于Service你所需要知道内容(一)

          本文链接:https://www.haomeiwen.com/subject/ixtblftx.html