Fork me on GitHub

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生命周期

posted @ 2015-03-09 22:35  Zong_在路上  阅读(218)  评论(0编辑  收藏  举报