zoukankan      html  css  js  c++  java
  • Service

    Service

    Service是Android四大组件中与Activity最相似的组件,它们都代表可执行的程序,Service与Activity的区别在于:Service一直在后台运行,它没有用户界面,所以绝不会到前台来。一旦Service被启动起来之后,它就与Activity一样。它完全具有自己的生命周期。关于程序中Activity与Service的选择标准是:如果某个程序组件需要在运行时向用户呈现某种界面,或者该程序需要与用户交互,就需要使用Activity,否则就应该考虑使用Service了。

    开发者开发Service的步骤与开发Activity的步骤很像,开发Service组件需要先开发一个Service的子类,然后在AndroidManifest.xml文件中配置该Service,配置时可通过

    Service简介

    Service组件也是可执行的程序,它也有自己的生命周期。创建、配置Service与创建、配置Activity的过程基本相似。

    创建、配置Service

    就像开发Activity需要两个步骤,开发Service也需要两个步骤:

    1. 定义一个继承Service的子类。
    2. 在AndroidManifest.xml文件中配置该Service。

    Service与Activity还有一点相似之处,它们都是从Context派生出来的,因此它们都可调用Context里定义的如getResources()、getContentResolver()等方法。

    与Activity相似的是,Service中也定义了系列生命周期方法,如下所示。

    • abstract IBinder onBind(Intent intent):该方法是Service子类必须实现的方法。该方法返回一个IBinder对象,应用程序可通过该对象与Service组件通信。
    • void onCreate():当该Service第一次被创建后将立即回调该方法。
    • void onDestroy():当该Service被关闭之前将会回调该方法。
    • void onStartCommand(Intent intent, int flags, int startId):该方法的早期版本是void onStart(Intent intent, int startId),每次客户端调用startService(Intent)方法启动该Service时都会回调该方法。
    • boolean onUnbind(Intent intent):当该Service上绑定的所有客户端都断开连接时将会回调该方法。

    下面的类定义了第一个Service组件。

    public class FirstService extends Service {
        public FirstService() {
        }
    
        // 必须实现的方法
        @Override
        public IBinder onBind(Intent intent) {
            // TODO: Return the communication channel to the service.
            throw new UnsupportedOperationException("Not yet implemented");
        }
    
        // Service被创建时回调该方法
        @Override
        public void onCreate() {
            super.onCreate();
            System.out.println("Service is Created");
        }
    
        // Service被启动时回调该方法
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            System.out.println("Service is Started");
            return START_STICKY;
        }
    
        // Service被关闭之前回调
        @Override
        public void onDestroy() {
            super.onDestroy();
            System.out.println("Service is Destroyed");
        }
    }

    定义了上面的Service之后,接下来需要在AndroidManifest.xml文件中配置该Service,配置Service使用

    <!-- 配置一个Service组件 -->
    <service android:name=".FirstService">
        <intent-filter>
            <!-- 为该Service组件的intent-filter配置action -->
            <action android:name="tk.zongzhankui.firstservice.FIRST_SERVICE">
        </intent-filter>
    </service>
    

    从上面的配置片段不难看出,配置Service与配置Activity的差别并不大,只是配置Service使用

    启动和停止Service

    下面的程序使用Activity作为Service的访问者,该Activity的界面中包含两个按钮,一个按钮用于启动Service,一个按钮用于关闭Service。

    该Activity的代码如下。

    public class MainActivity extends Activity {
        Button start, stop;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            start = (Button) findViewById(R.id.start);
            stop = (Button) findViewById(R.id.stop);
    
            // 创建启动Service的Intent
            final Intent intent = new Intent();
            intent.setAction("tk.zongzhankui.firstservice.FIRST_SERVICE");
            start.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    startService(intent);
                }
            });
            stop.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    stopService(intent);
                }
            });
        }
    
    }

    示例代码下载

    每当Service被创建时会回调onCreate方法,每次Service被启动时都会回调onStart方法——多次启动一个已有的Service组件将不会再回调onCreate方法,但每次启动时都会回调onStart方法。

    绑定本地Service并与之通信

    当程序通过startService()和stopService()启动、关闭Service时,Service与访问者之间基本上不存在太多的关联,因此Service和访问者之间也无法进行通信、数据交换。

    如果Service和访问者之间需要进行方法调用或数据交换,则应该使用bindService()和unbindService()方法启动、关闭服务。

    Context的bindService()方法的完整方法签名为:bindService(Intent service, ServiceConnection conn, int flags),该方法的三个参数的结束如下。

    • service:该参数通过Intent指定要启动的Service。
    • conn:该参数是一个ServiceConnection对象,该对象用于监听访问者与Service之间的连接情况。当访问者与Service之间连接成功时将回调该ServiceConnection对象的onServiceConnected(ComponentName name, IBinder service)方法;当访问者与Service之间断开连接时将回调该ServiceConnection对象的onServiceDisconnected(ComponentName name)方法。
    • flags:指定绑定时是否自动创建Service(如果Service还未创建)。该参数可指定为0(不自动创建)或BIND_AUTO_CREATE(自动创建)。

    注意到ServiceConnection对象的onServiceConnected方法中有一个IBinder对象,该对象即可实现与被绑定Service之间的通信。

    当开发Service类时,该Service类必须提供一个IBinder onBind(Intent intent)方法,在绑定本地Servcie的情况下,onBind(Intent intent)方法所返回的IBinder对象将会传给ServiceConnection对象里onServiceConnected(ComponentName name, IBinder service)方法的service参数,这样访问者就可通过该IBinder对象与Service进行通信。

    实际上开发时通常会采用继承Binder(IBinder的实现类)的方式实现自己的IBinder对象。

    下面的程序示范了如何在Activity中绑定本地Service,并获取Service的运行状态。该程序的Service类需要“真正”实现onBind()方法,并让该方法返回一个有效的IBinder对象,该Service类的代码如下。

    public class BindService extends Service {
        private int count;
        private boolean quit;
        // 定义onBinder方法所返回的对象
        private MyBinder binder = new MyBinder();
        // 通过继承Binder来实现IBinder类
        public class MyBinder extends Binder {
            public int getCount() {
                // 获取Service的运行状态:count
                return count;
            }
        }
    
        // 必须实现的方法
        @Override
        public IBinder onBind(Intent intent) {
            System.out.println("Service is Binded");
            // 返回IBinder对象
            return binder;
        }
    
        // Service被创建时回调该方法
        @Override
        public void onCreate() {
            super.onCreate();
            System.out.println("Service is Created");
            // 启动一条线程,动态地修改count状态值
            new Thread() {
                @Override
                public void run() {
                    while (!quit) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        count++;
                    }
                }
            }.start();
        }
    
        // Service被关闭之前回调
        @Override
        public void onDestroy() {
            super.onDestroy();
            this.quit = true;
            System.out.println("Service is Destroyed");
        }
    
        // Service被断开连接时回调该方法
        @Override
        public boolean onUnbind(Intent intent) {
            System.out.println("Service is Unbinded");
            return true;
        }
    }

    上面Service类的粗体字代码实现了onBind()方法,该方法返回了一个可访问该Service状态数据(count值)的IBinder对象,该对象将被传给该Service的访问者。

    上面程序通过继承Binder类实现了一个IBinder对象,这个MyBinder类是Service的内部类,这对于绑定本地Service并与之通信的场景是一种常见的情形。当然也可以为MyBinder类提供一个借口,或把MyBinder类定义成一个外部类的形式,这无关紧要。

    接下来定义一个Activity来绑定该Service,并在该Activity中通过MyBinder对象访问Service的内部状态。该Activity的界面上包含三个按钮,第一个按钮用于绑定Service,第二个按钮用于解除绑定;第三个按钮用于获取Service的运行状态。该Activity的代码如下。

    public class MainActivity extends Activity {
        Button bind, unbind, getServiceStatus;
        // 保持所启动的Service的IBinder对象
        BindService.MyBinder binder;
        // 定义一个ServiceConnection对象
        private ServiceConnection conn = new ServiceConnection() {
            // 当该Activity与Service连接成功时回调该方法
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                System.out.println("--Service Connected--");
                // 获取Service的onBind方法所返回的MyBinder对象
                binder = (BindService.MyBinder) service;
            }
    
            // 当该Activity与Service断开连接时回调该方法
            @Override
            public void onServiceDisconnected(ComponentName name) {
                System.out.println("--Service Disconnected--");
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            bind = (Button) findViewById(R.id.bind);
            unbind = (Button) findViewById(R.id.unbind);
            getServiceStatus = (Button) findViewById(R.id.getServiceStatus);
    
            // 创建启动Service的Intent
            final Intent intent = new Intent();
            // 为Intent设置Action属性
            intent.setAction("tk.zongzhankui.bindservice.BIND_SERVICE");
            bind.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // 绑定指定Service
                    bindService(intent, conn, BindService.BIND_AUTO_CREATE);
                }
            });
            unbind.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // 解除绑定Service
                    unbindService(conn);
                }
            });
            getServiceStatus.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // 获取并显示Service的count值
                    Toast.makeText(MainActivity.this, "Service的count值为:"
                            + binder.getCount(), Toast.LENGTH_LONG).show();
                }
            });
        }
    
    }

    示例代码下载

    对于Service的onBind()方法所返回的IBinder对象来说,它可被当成该Service组件所返回的回调对象,Service允许客户端通过该IBinder对象来访问Service内部的数据,这样即可实现客户端与Service之间的通信。

    与多次调用startService()方法启动Service不同的是,多次调用bindService()方法并不会执行重复绑定。对于前一个实例程序,用户每单击“启动Service”按钮一次,系统就会回调Service的onStart()方法一次;对于这个实例程序,不管用户单击“绑定Service”多少次,系统只会回调Service的onBind()方法一次。

    Service的生命周期

    随着应用程序启动Service方式的不同,Service的生命周期也略有差异。

    这里写图片描述

    Service生命周期

    如果觉得本文对您有帮助,请“打赏”,谢谢。
    您的鼓励,我的动力。
    微信 支付宝
  • 相关阅读:
    iOS new Date() 报invalid Date
    Windows查找端口对应进程
    Dbvisualizer Free版本无sql自动提示功能解决方案
    Docker
    更换k8s集群,或者创建集群使用用户不对,导致ranchar无法显示容器处理
    linux下mysql5.7.30安装
    ansible 使用redis缓存
    tr命令
    ipvsadm安装配置NAT
    2019新电脑主板安装win10系统
  • 原文地址:https://www.cnblogs.com/zongzhankui/p/5875321.html
Copyright © 2011-2022 走看看