美文网首页
四大组件之Service

四大组件之Service

作者: C调路过 | 来源:发表于2020-03-30 14:35 被阅读0次

    四大组件之Service

    Service是Android开发的基础之一,但是在实际项目开发中用到较少,有必要梳理一下,就先篇文章记录下。

    Service的启动方式

    与Activity一样,service需要在manifest.xml 中进行注册

            <service android:name=".service.TestService" />
    

    Service的启动方式有两种,接下来分别进行介绍

    方式一

    方法一使用上也与Activity跳转相似,通过Intent的方式进行启动。

          startService(new Intent(ServiceActivity.this, TestService.class));
    

    我们在相关生命周期中打印日志观察启动流程。

        @Override
        public void onCreate() {
            Log.e(TAG, "onCreate:");
            super.onCreate();
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.e(TAG, "onStartCommand:");
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void onDestroy() {
            Log.e(TAG, "onDestroy:");
            super.onDestroy();
        }
    

    当第一次点击按钮触发startService时,

        service.TestService: onCreate:
        service.TestService: onStartCommand:
    

    第二次点击触发

        service.TestService: onStartCommand:
    

    发现后面start多少次都只会走onStartCommand函数,可以与Activity的onNewIntent进行类比,已经初始化的Service不需要被重复创建。

    接着触发stopService后再启动Service,则会从OnCreate开始。

    方式二

    若要Activity与Service之间有交互,就需要通过方法二bindService的方式。创建ServiceConnection对象进行关联。

        private ServiceConnection connection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
    
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        };
    
        bindService(new Intent(ServiceActivity.this, TestService.class),connection, 1);
    

    通过bindService的方式只会绑定一次

        service.TestService: onCreate:
        service.TestService: onBind:
    

    同样的通过unbindService之后重复创建绑定流程。

    Service的使用

    相对于Activity来说,Service并没有页面,也就没有控件上的交互,单纯用于处理逻辑。

    现在我们通过方式一执行下1s的耗时任务,使用Sleep进行模拟,然后进行Toast。

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            try {
                Thread.sleep(1000);
                Toast.makeText(getBaseContext(), "任务完成", Toast.LENGTH_LONG).show();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Log.e(TAG, "onStartCommand:");
            return super.onStartCommand(intent, flags, startId);
        }
    

    但是如果任务时间过长,由于处于主线程中,就会造成ANR的现象。这个时候就可以创建一个线程执行,或者使用IntentService的方式。

    IntentService封装了HandlerThread,创建启动线程并进行Loop。Handler接收消息处理任务后直接关闭Service。

        private final class ServiceHandler extends Handler {
            public ServiceHandler(Looper looper) {
                super(looper);
            }
    
            @Override
            public void handleMessage(Message msg) {
                onHandleIntent((Intent)msg.obj);
                stopSelf(msg.arg1);
            }
        }
    

    另一种通过Bind的方式更加的灵活,可以根据需要执行任务。在TestService中定义LocalBinder类,在创建Service时进行初始化,执行bindService后返回该对象。

        private LocalBinder mbinder = new LocalBinder();
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            Log.e(TAG, "onBind:");
            return mbinder;
        }
    
        public class LocalBinder extends Binder {
            public TestService getservices() {
                return TestService.this;
            }
    
            public void method1() {
                Toast.makeText(getBaseContext(), "method1", Toast.LENGTH_LONG).show();
                Log.e(TAG, "start:");
            }
    
            public void method2() {
                Toast.makeText(getBaseContext(), "method2", Toast.LENGTH_LONG).show();
                Log.e(TAG, "start:");
            }
        }
    

    在Activity中的onServiceConnected时保存对象。

        private TestService.LocalBinder localBinder;
        private ServiceConnection connection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                localBinder = (TestService.LocalBinder) service;
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        };
    

    即可根据需要调用localBinder.method1()。

    Service的跨进程通信

    IBinder这个东西是用来实现跨进程通信的,像上面那样使用简直是杀鸡用牛刀。

    使用Messenger来发送跨进程消息

    首先在Manifest中将TestService设置其他进程

            <service android:name=".service.TestService"
                android:process=":remote"/>
    

    在TestService中创建Messenger对象,在onBind中返回

        private Messenger messenger = new Messenger(new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case 1:
                        Log.e(TAG, "remoteService接收到了Activity发送的消息");
                        break;
                    default:
                        super.handleMessage(msg);
                        break;
                }
            }
        });
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            Log.e(TAG, "onBind:");
            return messenger.getBinder();
        }
    

    在Activity中使用通过onBind返回的IBinder对象创建Messenger发送远程消息。

        private Messenger mMessenger;
    
        private ServiceConnection connection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                mMessenger = new Messenger(service);
                Message message = Message.obtain(null, 1);
                try {
                    mMessenger.send(message);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        };
    

    运行观察结果

        service.TestService: remoteService接收到了Activity发送的消息
    

    也可以设置message.replyTo 为本地的Messenger ,接收远程的消息。

    Activity中

      private Messenger remoteMessenger;
    
        private Messenger localMessenger;
        private ServiceConnection connection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                remoteMessenger = new Messenger(service);
                localMessenger = new Messenger(new Handler() {
                    @Override
                    public void handleMessage(Message msg) {
                        switch (msg.what) {
                            case 1:
                                Log.e(TAG, "Activity接收到了remoteService返回的消息");
                                break;
                            default:
                                super.handleMessage(msg);
                                break;
                        }
                    }
                });
                Message message = Message.obtain(null, 1);
                message.replyTo = localMessenger;
                try {
                    remoteMessenger.send(message);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        };
    

    Service中

        private Messenger messenger = new Messenger(new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case 1:
                        Log.e(TAG, "remoteService接收到了Activity发送的消息");
                        Message message = Message.obtain(null, 1);
                        try {
                            msg.replyTo.send(message);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        break;
                    default:
                        super.handleMessage(msg);
                        break;
                }
    
            }
        });
    

    就实现了远程与本地的跨进程双端通信。

    使用AIDL来发送跨进程消息

    首先创建一个RemoteServer的aidl文件,点击锤子编译一下。在debug中会生成对应RemoteServer.java类,生成的文件中有对应的Stub、Proxy和在aidl中写的request方法。

        // RemoteServer.aidl
        interface RemoteServer {
        
            void request();
        }
    

    在Service中实现Binder方法

        IBinder RemoteServer = new RemoteServer.Stub() {
            @Override
            public void request() throws RemoteException {
                Log.e(TAG, "RemoteServer接收到了Activity发送的消息");
            }
        };
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            Log.e(TAG, "onBind:");
            return RemoteServer;
        }
    
    在Activity中使用与Messenger类似,通过IBinder创建代理对象进行调用。
    
        private ServiceConnection connection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                try {
                    RemoteServer.Stub.asInterface(service).request();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        };
    

    本文以Service的创建使用为主,AIDL以及binder通信的底层原理还在学习中。。。

    相关文章

      网友评论

          本文标题:四大组件之Service

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