四大组件之Service

2020-03-30  本文已影响0人  C调路过

四大组件之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通信的底层原理还在学习中。。。

上一篇下一篇

猜你喜欢

热点阅读