• Android四大组件之Service的使用
  • Service与Thread的区别
  • Service的使用
  • Service的绑定
  • Service的生命周期
  • IntentService


Android四大组件之Service的使用

Service与Thread的区别

Thread的运行是独立于Activity的,也就是说当一个Activity被finish掉之后,如果没有主动停止Thread或者Thread还没有执行完毕,Thread还会一直执行。因此这里会出现一个问题:当Activity被finish之后,你就不再持有该Thread的引用,另一个方面,你没有办法在不同的Activity中对同一个Thread进行控制。

举个例子:假设我们需要周期性的连接服务器进行数据的更新,该Thread需要在Activity没有start的时候也在运行。这个时候当你start一个 Activity 就没有办法在该 Activity 里面控制之前创建的Thread。因此你便需要创建并启动一个Service,在 Service里面创建、运行并控制该Thread,这样便解决了该问题(因为任何Activity都可以控制同一Service,而系统也只会创建一个对应 Service 的实例)。

因此你可以把 Service 想象成一种消息服务,而你可以在任何有 Context 的地方调用 Context.startService、Context.stopService、Context.bindService,Context.unbindService,来控制它,你也可以在Service里注册BroadcastReceiver,在其他地方通过发送 broadcast 来控制它,当然这些都是 Thread 做不到的。

Service的使用

Service的使用和Activity非常相似。

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

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

同时Activity和Service都是从Context派生出来的,所以都可以调用如getResources(),getContentResolver()等方法;

Service也定义了一系列的生命周期相关的方法:

onCreate():Service在创建的时候调用;

onStartCommand():当客户端调用startService方法的时候调用。

onBind():该方法是Service子类必须实现的方法。该方法会返回一个IBinder对象,应用程序可以通过该对象与Service进行通信。

onUnbind():当Service上绑定的所有客户断开连接的时候会调用该方法。

onDestory():在Service被关闭的时候调用。

service的启动方式有两种,startService 和 bindService;

startService(Intent service):该方法启动的Service与访问者没有任何关联,因此不能用于数据的交换。

bindService(Intent service, ServiceConnection conn,
int flags):通过这种方法可以将Service与访问者进行绑定。

Service的绑定

我们着重看一下Service的绑定:

@Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        return mBase.bindService(service, conn, flags);
    }

bindService需要三个参数:

service:该参数通过Intent指定需要启动的Service;

conn:该参数是一个ServiceConnection对象,该对象用于监听访问者与Service之间的连接情况;该对象有两个方法,onServiceConnected用于当与Service连接成功时会进行回掉,onServiceDisconnected用于当service所在的宿主进程异常中止或其他原因导致与访问者断开连接时会回调该方法,但是在unBindService时不会回调该方法。

flags:指定绑定时是否自动创建Service,当我们绑定一个已经运行的service的时候,该参数可以设置为0,如果Service还未创建,该参数可以设置为Service.BIND_AUTO_CREATE,这样将会自动创建一个service;

当我们在创建一个Service类时,该Service类需要继承Service,因此必须实现onBind方法,当我们需要与访问者进行绑定的时候,需要通过该方法返回一个IBinder对象,通常我们会在Service中定义一个继承了Binder的内部类,该类提供需要开放给访问者的数据接口,然后再onBind的时候将该Binder返回给访问者,然后在访问者与Service连接成功的时候,会通过onServiceConnected将IBinder对象传递给访问者,这时候我们只需要在onServiceConnected回调的到时候获取对应的IBinder,就可以通过Binder提供的数据接口拿到Service的内部数据,这样就可以通过该IBinder与Service进行数据的交互。

下面我们来看一个具体的实现例子,该例子在Service中将一个数据每两秒钟加1,然后在Activity中通过一个按钮随时获取Service中该数据的值。

public class DataService extends Service{
    private boolean quit = false;
    private int count = 0;
    private MyBinder binder = new MyBinder();
    //通过集成Binder实现IBinder类
    public class MyBinder extends Binder{
        //可以定义需要外界使用的方法
        public int getCount(){
            return count;
        }
    }
    //绑定Service的时候调用该方法
    @Override
    public IBinder onBind(Intent intent) {
        System.out.println("onBInd");
        return binder;
    }

    //当service被断开连接的时候调用该方法
    @Override
    public boolean onUnbind(Intent intent) {
        System.out.println("onUnbind");
        return true;
    }

    //当Service被关闭的时候调用该方法(可以终止线程的执行等操作)
    @Override
    public void onDestroy() {
        System.out.println("onDestroy");
        super.onDestroy();
        this.quit = true;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onCreate() {
        System.out.println("onCreate");
        super.onCreate();
        new Thread(){
            @Override
            public void run() {
                while (!quit){
                    //执行我们需要的操做
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    count++;
                }
            }
        }.start();
    }
}
public class MyServiceActivity extends Activity{
    private Button btn_count;
    private DataService.MyBinder binder;
    //用于监听访问者与Service之间的连接情况
    private ServiceConnection serviceConnection = new ServiceConnection() {
        //当连接成功时调用该方法
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            binder = (DataService.MyBinder) service;
            System.out.println("onServiceConnected");
        }
        //当Service所在的宿主进程异常中止或其他原因导致与访问者断开
        // 连接调用该方法,unBindService时不会调用该方法
        @Override
        public void onServiceDisconnected(ComponentName name) {
            System.out.println("onServiceDisconnected");
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btn_count = (Button) findViewById(R.id.mySvg);
        initEvent();
        startMyService();
    }

    //启动Service
    private void startMyService() {
        Intent intent = new Intent(this, DataService.class);
        bindService(intent, serviceConnection, Service.BIND_AUTO_CREATE);
    }

    private void initEvent(){
        btn_count.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MyServiceActivity.this, "COUNT:" + binder.getCount(), Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    protected void onDestroy() {
        //unbindService会直接关闭Service
        unbindService(serviceConnection);
        super.onDestroy();
    }

}

注意需要在AndroidManifest.xml注册Service。

当我们需要绑定一个已有的Service的时候,方法基本相同,就不再赘述。

Service的生命周期

我们首先看一下通过bindService调用Service的过程:

03-02 10:05:44.307  12982-12982/com.example.zhangyi.androidsvg I/System.out﹕ onCreate
03-02 10:05:44.309  12982-12982/com.example.zhangyi.androidsvg I/System.out﹕ onBInd
03-02 10:05:44.407  12982-12982/com.example.zhangyi.androidsvg I/System.out﹕ onServiceConnected

通过log信息可以看到,当通过bindService调用的时候,onCreate->onBind,然后会回调访问者中的onServiceConnected,然后客户端就与Service绑定好了。

当客户端调用unbindService的时候:

03-02 10:16:42.091  18889-18889/com.example.zhangyi.androidsvg I/System.out﹕ onUnbind
03-02 10:16:42.092  18889-18889/com.example.zhangyi.androidsvg I/System.out﹕ onDestroy

会执行onUnbind->onDestroy。

当通过startService启动Service的时候:

03-02 10:19:26.677  20731-20731/com.example.zhangyi.androidsvg I/System.out﹕ onCreate
03-02 10:19:26.679  20731-20731/com.example.zhangyi.androidsvg I/System.out﹕ onStartCommand

当我们通过stopService进行停止的时候,会调用onDestory.

因此:onCreate->onStartCommand->Service运行中->onDestory;

当我们绑定一个已经启动的Serice的时候,然后调用unbindService:

03-02 10:24:44.184  23473-23473/com.example.zhangyi.androidsvg I/System.out﹕ onCreate
03-02 10:24:44.186  23473-23473/com.example.zhangyi.androidsvg I/System.out﹕ onStartCommand
03-02 10:24:44.187  23473-23473/com.example.zhangyi.androidsvg I/System.out﹕ onBInd
03-02 10:24:44.264  23473-23473/com.example.zhangyi.androidsvg I/System.out﹕ onServiceConnected
03-02 10:25:36.906  23473-23473/com.example.zhangyi.androidsvg I/System.out﹕ onUnbind

我们发现,调用bindService只是通过onBind方法将IBinder对象传递给Activity,并不会把Service的生命周期与Activity进行绑定,当调用unbindService时,只是进行断开连接,并没有停止该Service。即使Activity退出也不能停止该Service。

IntentService

我们知道,Service并不能执行耗时任务,当我们需要执行耗时任务的时候,需要在Service中开启一条线程,IntentServiceh会使用消息队列管理请求的Intent,然后开启一条新的线程来处理该Intent。关于IntentService的具体使用方法,请参见之前的Android线程和线程池(三)–IntentService。