Android中 service组件详解
service组件跟activity组件及其类似,可以说service是没有界面的activity,
当然service的生命周期和activity还是有一定的差别的。
service组件一般用在什么地方的,上面讲了service组件没有界面,不用跟用户直接交互,
所以service组件一般运行在后台。比如做一些不需要界面的数据处理等等。
开发service需要两个步骤:
1,定义一个基础service的子类。
2,在AndroidManifest.xml文件中配置该service。
怎么启动service呢,想想启动activity是不是有两种方法:
startActivity(intent),
startActivityForResult(intent)
那么启动service也有两种方法:
startService(intent),
bindService(Intentservice,ServiceConnectionconn,intflags),
两者有什么区别可以先看下面的代码:
publicclassBindServiceextendsService { privateintcount; privatebooleanquit; //定义onBinder方法所返回的对象 privateMyBinderbinder=newMyBinder(); //通过继承Binder来实现IBinder类 publicclassMyBinderextendsBinder { publicintgetCount() { //获取Service的运行状态:count returncount; } } //必须实现的方法 @Override publicIBinderonBind(Intentintent) { System.out.println("ServiceisBinded"); //返回IBinder对象 returnbinder; } //Service被创建时回调该方法。 @Override publicvoidonCreate() { super.onCreate(); System.out.println("ServiceisCreated"); //启动一条线程、动态地修改count状态值 newThread() { @Override publicvoidrun() { while(!quit) { try { Thread.sleep(1000); } catch(InterruptedExceptione) { } count++; } } }.start(); } //Service被断开连接时回调该方法 @Override publicbooleanonUnbind(Intentintent) { System.out.println("ServiceisUnbinded"); returntrue; } //Service被关闭之前回调。 @Override publicvoidonDestroy() { super.onDestroy(); this.quit=true; System.out.println("ServiceisDestroyed"); } @Override publicvoidonRebind(Intentintent) { super.onRebind(intent); this.quit=true; System.out.println("ServiceisReBinded"); } }
上面的Service的作用是简单的开启一个线程,每1秒钟count++,这个count数据
通过binder对象传递给访问者。
待会再做详解,先看下面的代码怎么启动Service,并得到Service的count数据
publicclassMainActivityextendsActivity { ButtonstartService_bnt,bindService_bnt; //保持所启动的Service的IBinder对象 BindService.MyBinderbinder; @Override publicvoidonCreate(BundlesavedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); startService_bnt=(Button)findViewById(R.id.start_bnt); bindService_bnt=(Button)findViewById(R.id.bind_bnt); //创建启动Service的Intent Intentintent=newIntent(this,BindService.class); startService_bnt.setOnClickListener(newOnClickListener() { @Override publicvoidonClick(Viewsource) { //绑定指定Serivce startService(intent); } }); bindService_bnt.setOnClickListener(newOnClickListener() { @Override publicvoidonClick(Viewsource) { //绑定指定Serivce bindService(intent,conn,Service.BIND_AUTO_CREATE); Toast.makeText(MainActivity.this ,"Serivce的count值为:"+binder.getCount() ,4000) .show(); } }); } //定义一个ServiceConnection对象 privateServiceConnectionconn=newServiceConnection() { //当该Activity与Service连接成功时回调该方法 @Override publicvoidonServiceConnected(ComponentNamename ,IBinderservice) { System.out.println("--ServiceConnected--"); //获取Service的onBind方法所返回的MyBinder对象 binder=(BindService.MyBinder)service; } //当该Activity与Service断开连接时回调该方法 @Override publicvoidonServiceDisconnected(ComponentNamename) { System.out.println("--ServiceDisconnected--"); } }; }
上面activity定义了两个按钮,点击两个按钮有两种不同的方法启动Service:
startService(intent), bindService(Intentservice,ServiceConnectionconn,intflags),
现在来讲解一下两种启动方式的区别,并解释上面的代码。
startService(intent)启动Service呢它不具有与访问者交互的能力,就像activity的startActivity(),它不能从新启动的activity拿到返回数据一样
而bindService(Intentservice,ServiceConnectionconn,intflags),就不一样了
访问者能从启动的Service拿到数据,怎么拿到的呢,bindService的第二个参数conn,该参数是一个ServiceConnection 对象,当访问者与Service连接成功就会回调ServiceConnection 的onServiceConnected()方法,上面的程序就是在这个回调方法里面拿到IBinder 对象的。
可以在看一下
//定义一个ServiceConnection对象 privateServiceConnectionconn=newServiceConnection() { //当该Activity与Service连接成功时回调该方法 @Override publicvoidonServiceConnected(ComponentNamename ,IBinderservice) { System.out.println("--ServiceConnected--"); //获取Service的onBind方法所返回的MyBinder对象 binder=(BindService.MyBinder)service; } //当该Activity与Service断开连接时回调该方法 @Override publicvoidonServiceDisconnected(ComponentNamename) { System.out.println("--ServiceDisconnected--"); } };
简单点也就是说访问者通过bindService绑定到Service,绑定成功后会回调ServiceConnection中的onServiceConnected()方法,这个方法里面有IBinderservice参数,这个参数就是Service暴露给访问者的对象,访问者拿到这个对象就可以访问Service的数据了
这就是访问者与Service数据交互的原理,是通过IBinder对象来传递的。
可能到这这里你还对binder=(BindService.MyBinder)service;这句代码不理解。
你肯能觉得拿到的IBinder对象不应该是上面Service代码中onBind方法返回的binder才是嘛,怎么强转成BindService.MyBinder对象了。
而且返回的binder 也没count数据,访问者怎么就能binder.getCount()得到数据呢。
@Override publicIBinderonBind(Intentintent) { System.out.println("ServiceisBinded"); //返回IBinder对象 returnbinder; }
别忘了上面Service代码里面还对IBinder对象进行处理
//通过继承Binder来实现IBinder类 publicclassMyBinderextendsBinder { publicintgetCount() { //获取Service的运行状态:count returncount; } }
Binder是IBinder的实现类,MyBinder继承Binder并在里面定义了个方法。
那么拿到 IBinder 对象就相当于拿到 MyBinder对象,就可以访问getCount方法了,这也是为什么binder=(BindService.MyBinder)service;进行强转,并且binder.getCount()可以拿到count数据,因为IBinder里面并没有业务实现,是MyBinder帮它实现了。