Android四大组件之Service服务学习笔记(一)
Service是安卓四大组件之一,服务是用在后台处理事情的,并且是不可见的,该服务不是我们所说的服务器的服务,他经常用来处理一些循环操作,但是它不同于子线程,服务是运行在主线程中的。
服务一般分为本地服务和远程服务,这里先介绍本地服务。
本地服务通常用两种启动方式
1. 直接启动模式
我们可以通过startService(Intent intent)方式去直接启动一个服务,对于intent意图,我们也可以用两种形式
创建,一种是显示启动,一种是隐示启动,但是需要注意的是,在android5.0以后,所有的服务尽量通过显示
意图来启动。否则就直接程序崩溃。所以建议都使用显示方式启动服务。如果一定要使用隐示启动方式, 则在对应的intent中添加一句intent.setPackage(对应服务所在的包名)
,通过这个方法,可以防止5.0后隐示启动发生崩溃的作用。下面通过代码来详细讲解下。
MainActivity.java
public class MainActivity extends AppCompatActivity {
private Intent intent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClick(View view){
intent = new Intent(this,MyService.class);
//intent.setPackage("cn.itrealman.servicedemo");5.0以后需要加上这句代码
switch (view.getId()) {
case R.id.start:
//启动服务
startService(intent);
break;
case R.id.stop:
//停止服务
stopService(intent);
break; }
}
}
在AndroidManifest.xml中配置Service
<service
android:name=".MyService"
android:enabled="true"
android:exported="true">
<!--<intent-filter>-->
<!--建议不用写,因为5.0后的系统不支持隐示启动-->
<!--<action android:name="test.service" />-->
<!--</intent-filter>-->
</service>
MyService.java
public class MyService extends Service {
public MyService() {
Log.d("IT_Real", "MyService: 构造方法");
}
/**
* 这个方法是通过绑定的方式才会调用该方法
* @param intent
* @return
*/
@Override
public IBinder onBind(Intent intent) {
Log.d("IT_Real", "onBind: ");
return null;
}
/**
* 服务启动后初始化内部数据的方法,只会在第一次启动该服务的时候调用一次
*/
@Override
public void onCreate() {
Log.d("IT_Real", "onCreate: ");
super.onCreate();
}
/**
* 销毁服务
*/
@Override
public void onDestroy() {
Log.d("IT_Real", "onDestroy: ");
super.onDestroy();
}
@Override
public boolean onUnbind(Intent intent) {
Log.d("IT_Real", "onUnbind: ");
return super.onUnbind(intent);
}
/**
* 这个方法是直接启动服务时调用的方法,不过该方法已经过时了
* 被下面的onStartCommand方法代替了
* @param intent
* @param startId
*/
@Override
public void onStart(Intent intent, int startId) {
Log.d("IT_Real", "onStart: ");
super.onStart(intent, startId);
}
/**
* 这个方法也是直接启动服务时调用的方法
* @param intent
* @param flags
* @param startId
* @return
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("IT_Real", "onStartCommand: ");
return super.onStartCommand(intent, flags, startId);
}
}
在上面的代码中,当我们点击启动按钮时,相应的服务被启动,在此之前,我们先看一下直接启动方式服务的生命周期图:
在上面的图中,我可以了解到,当我们第一次启动服务时,会先调用onCreate()——>onStartCommand()——onStart(),然后服务会开始运行,直到调用stopService()方法才会停止服务,然后会调用相应的onDestory()方法,如果服务已经启动,我们多次点击启动服务按钮,则会多次掉用onStartCommand()——>onStart()方法
对于上面的这种方式,我们不会获取任何服务对象,也不能操作任何服务里面的数据,都是系统自己去操作的,加入说,我们的服务里面有一个doSth()方法,我想去调用这个方法做该事情,那么该怎么调用呢?这个时候,我们就只能去通过在onStartCommand()方法里面去调用了(在onStart()方法中也可以调用,但是不推荐这样使用,过时的方法我能不用就不用),代码如下:
/**
* 这个方法也是直接启动服务时调用的方法
* @param intent
* @param flags
* @param startId
* @return
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("IT_Real", "onStartCommand: ");
//通过调用该方法
doSth();
return super.onStartCommand(intent, flags, startId);
}
private void doSth(){
Log.d("IT_Real", "doSth: 我正在做某事...");
}
这样我们就能完成需要操作的事情了,但是这样的操作往往会很不方便,不能很好的让用户去通过某种方式去操作,比如在播放音乐的时候,我们就会很难去控制服务去处理某些事情,所以一般我们会通过绑定的方式来启动服务。
2. 绑定启动模式
对于绑定启动服务,我们可以很好的获取到服务给我们返回的Ibinder对象,由于Ibinder是一个接口,通常我们会返回一个Ibinder的子类Binder对象。一般情况下,我们会去继承Binder对象,添加自己所需要的实现功能。绑定启动的方式是通过bindService(Intent intent, ServiceConnection conn, int flags)绑定服务,该方法的三个参数如下:
intent:通过Intent指定要启动的服务
conn:该参数是一个ServiceConnection对象,该对象用于监听访问者与service之间的连接情况。当访问者与Service直接连接成功时将回调ServiceConnection对象的onServiceConnected(ComponentName name, IBinder service)方法,当Service所在的宿主进程由于异常中断或者其他原因终止,导致该Service与访问者之间断开连接时,会调用ServiceConnection对象的onServiceDisconnected(ComponentName name)方法。
flags:指定绑定时,是否通过自动创建Service(未创建的情况下),如果该参数指定0(不创建),或者写BIND_AUTO_CREATE(自动创建)
创建代码如下:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private Intent intent;
private MyServiceConnection conn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
conn = new MyServiceConnection();
}
public void onClick(View view){
intent = new Intent(this,MyService.class);
switch (view.getId()) {
case R.id.bindStart:
bindService(intent,conn,BIND_AUTO_CREATE);
break;
case R.id.bindStop:
unbindService(conn);
break; }
}
/**
* ServiceConnection类,通过该类中的onServiceConnected方法
* 中的IBinder service对象可以获取到绑定的服务对象中的MyBinder对象
* 然后可以通过MyBinder对象中的getBindService方法获取我们的
* MyBindService对象
*/
class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//获取Binder对象
MyBindService.MyBinder service1 = (MyBindService.MyBinder) service;
MyBindService service2 = service1.getBindService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
}
在AndroidManifest.xml中配置Service
<service
android:name=".MyBindService"
android:enabled="true"
android:exported="true">
</service>
MyBindService.java
public class MyBindService extends Service {
public MyBindService() {
}
/**
* 返回的IBinder对象
*/
class MyBinder extends Binder{
public MyBindService getBindService(){
returnMyBindService.this;
}
}
@Override
public void onCreate() {
Log.d("IT_Real", "onCreate: ");
super.onCreate();
}
/**
* 绑定服务时调用该方法
* @param intent
* @return
*/
@Override
public IBinder onBind(Intent intent) {
Log.d("IT_Real", "onBind: ");
return new MyBinder();
}
@Override
public boolean onUnbind(Intent intent) {
Log.d("IT_Real", "onUnbind: ");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
Log.d("IT_Real", "onDestroy: ");
super.onDestroy();
}
}
这样我们就可以获取绑定服务对象了。然后我们看一下下面的生命周期图
通过绑定服务我们可以看出该生命周期。当调用了bindService方法时,生命周期为onCreate()——>onBind()——>服务运行,当调用unbindService()方法时,服务被关闭,执行onUnbind()——>onDestroy()
通过绑定服务,我们可以获取到对应的服务对象,如果说要实现某些操作,在服务里面定义对应的该操作,然后通过服务对象可以去调用该方法。我们去调用一个播放、暂停、上一首、下一首等。代码如下
MainActivity.java
public class MainActivity extends AppCompatActivity {
private Intent intent;
private MyServiceConnection conn;
private MyBindService service2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
conn = new MyServiceConnection();
}
public void onClick(View view){
intent = new Intent(this,MyBindService.class);
switch (view.getId()) {
case R.id.bindStart:
bindService(intent,conn,BIND_AUTO_CREATE);
break;
case R.id.bindStop:
unbindService(conn);
break;
case R.id.startMusic:
//播放
service2.start();
break;
case R.id.pause:
//暂停
service2.pause();
break;
case R.id.previous:
//上一首
service2.previous();
break;
case R.id.next:
//下一首
service2.next();
break;
}
}
/**
* ServiceConnection类,通过该类中的onServiceConnected方法
* 中的IBinder service对象可以获取到绑定的服务对象中的MyBinder对象
* 然后可以通过MyBinder对象中的getBindService方法获取我们的
* MyBindService对象
*/
class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//获取Binder对象
MyBindService.MyBinder service1 = (MyBindService.MyBinder) service;
service2 = service1.getBindService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
}
MyBindService.java
public class MyBindService extends Service {
public MyBindService() {
}
/**
* 返回的IBinder对象
*/
class MyBinder extends Binder{
public MyBindService getBindService(){
return MyBindService.this;
}
}
/**
* 服务被创建时调用该方法
*/
@Override
public void onCreate() {
Log.d("IT_Real", "onCreate: ");
super.onCreate();
}
/**
* 绑定服务时调用该方法
* @param intent
* @return
*/
@Override
public IBinder onBind(Intent intent) {
Log.d("IT_Real", "onBind: ");
return new MyBinder();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("IT_Real", "onStartCommand: ");
return super.onStartCommand(intent, flags, startId);
}
/**
* 当调用了unbindService方法是,调用该方法
* @param intent
* @return
*/
@Override
public boolean onUnbind(Intent intent) {
Log.d("IT_Real", "onUnbind: ");
return super.onUnbind(intent);
}
/**
* 被关闭之前调用该方法
*/
@Override
public void onDestroy() {
Log.d("IT_Real", "onDestroy: ");
super.onDestroy();
}
public void start(){
Log.d("IT_Real", "start: 播放");
}
public void pause(){
Log.d("IT_Real", "pause: 暂停");
}
public void next(){
Log.d("IT_Real", "next: 下一首");
}
public void previous(){
Log.d("IT_Real", "previous: 上一首");
}
}
这样就可以很好的操作服务里面的方法了。对于绑定服务,有一个地方需要注意,那就是,我们在启动服务后,如果退出了当前activity,或者结束该进程的时候,没有调用unbindService()方法,程序会报一个
Activity cn.itrealman.servicedemo.MainActivity has leaked ServiceConnectioncn.itrealman.service
异常
demo.MainActivity$MyServiceConnection@6c1837b that was originally bound here
这个异常表示连接已经绑定,我们没有解绑,会导致泄露问题。所以,一般我们建议在销毁Activity时,我们需要在Activity的onDestroy()方法中添加如下代码:
@Override
protected void onDestroy() {
unbindService(conn);
super.onDestroy();
}
或者说,我们在关闭Activity之前,自己手动调用解绑方法。这样就能保证我们的程序不出错。