服务(Service)是Android中实现程序后台运行的解决方案,它非常适合用于去执行那些不需要和用户交互而且还要求长期运行的任务,服务的运行不依赖于任何用户界面,比如说需要下载一个文件,因为耗时可能比较长,这个时候我们就可以把它放到后台去执行,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,即使当程序被切换到后台, 或者用户打开了另外一个应用程序, 服务仍然能够保持正常运行,但需要注意的是当某个应用程序进程被杀掉时, 所有依赖于该进程的服务也会停止运行。
开启服务也有两种方式:
一种是startService(),对应的结束服务的方法是stopService()
另一种是bindService(),对应的结束服务的是unBindService()
以下以具体实例来讲解下这调用者几个方法后Service的生命周期
1.设置好布局如下:
2.创建MyService类继承Service类并且重写其中的方法:
package com.example.androidstudyservice;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service{
@Override
public IBinder onBind(Intent intent) {
Log.d("SERVICE", "onBind()方法被调用");
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.d("SERVICE", "onCreate()方法被调用");
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
Log.d("SERVICE", "onStart()方法被调用");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("SERVICE", "onDestroy()方法被调用");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("SERVICE", "onStartCommand()方法被调用");
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
Log.d("SERVICE", "onUnbind()方法被调用");
return super.onUnbind(intent);
}
}
3.以下给出MainActivity中的代码:
package com.example.androidstudyservice;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity implements OnClickListener{
private Button button1;
private Button button2;
private Button button3;
private Button button4;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button1 = (Button) findViewById(R.id.bt1);
button2 = (Button) findViewById(R.id.bt2);
button3 = (Button) findViewById(R.id.bt3);
button4 = (Button) findViewById(R.id.bt4);
button1.setOnClickListener(this);
button2.setOnClickListener(this);
button3.setOnClickListener(this);
button4.setOnClickListener(this);
}
//创建了一个ServiceConnection的匿名类,重写onServiceConnected(方法和onServiceDisconnected()方法
//这两个方法分别会在活动与服务,成功绑定以及解除绑定的时候调用
private ServiceConnection conn = new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.bt1:
Intent startserviceintent = new Intent(MainActivity.this, MyService.class);
startService(startserviceintent);
break;
case R.id.bt2:
Intent stopserviceintent = new Intent(MainActivity.this, MyService.class);
stopService(stopserviceintent);
break;
case R.id.bt3:
Intent bindserviceintent = new Intent(MainActivity.this, MyService.class);
//bindService()方法接收三个参数,第一个参数就是构建出的Intent对象
//第二个参数是前面创建出的ServiceConnection的实例
//第三个参数则是一个标志位,这里传入BIND_AUTO_CREATE表示在活动和服务进行绑定后自动创建服务MyService中的onCreate()方法得到执行,但 onStartCommand()方法不会执行。
bindService(bindserviceintent, conn, Context.BIND_AUTO_CREATE);
break;
case R.id.bt4:
Intent unbindserviceintent = new Intent(MainActivity.this, MyService.class);
unbindService(conn);
break;
}
}
}
4.最后还需要在AndroidManifest.xml注册用到的服务类才行:
<service android:name=".MyService" >
</service>
以下是触发startService()->startService()->stopService()过程中Logcat的截图:
可以看到触发startService()方法方法后会先回调onCreate()方法,其次是回调onStartCommand()方法以及onStart()方法,再次调用startService()方法,onCreate()方法不会再执行,而是会再次执行一遍onStartCommand()方法以及onStart()方法,最后触发stopService()方法会回调onDestory()方法,服务销毁。
需要注意的是每调用一次 startService()方法,onStartCommand()以及onStart()都会执行一次, 但实际上每个服务都只会存在一个实例。也就是说不管调用了多少次 startService()方法, 只需调用一次 stopService()方法, 服务就会停止下来了。
如果我们希望服务一旦启动就立刻去执行某个动作, 就可以将逻辑写在onStartCommand()方法里。而当服务销毁时,我们又应该在 onDestroy()方法中去回收那些不再使用的资源。
以下是bindService()->bindService()->unbindService()过程中Logcat的截图:
可以看触发bindService()后首先也是会回调onCreate()方法创建服务,然后回调的是onBind()方法,这个时候如果我们再次触发bindService()方法,是不会再次回调MyService类中的方法了,最后触发unbindService()方法,回调onUnbind()方法,服务销毁。
以下是触发startService()->bindService()->unbindService()->stopService()过程中Logcat的截图:
因为我们完全有可能对一个服务既调用了startService()方法, 又调用了bindService()方法的, 这种情况下该如何才能让服务销毁掉呢,根据 Android系统的机制, 一个服务只要被启动或者被绑定了之后, 就会一直处于运行状态, 必须要让以上两种条件同时不满足,服务才能被销毁。所以, 这种情况下要同时调用stopService()和unbindService()方法, onDestroy()方法才会执行,上面的截图也验证了这一点。
那么这为什么需要startService()和bindService()两种启动服务的方法呢,这两种方法启动服务的区别是什么呢,我们以一下几个方面来说清楚这两者的区别:
1.使用StartService()方法来进行方法启动服务的情况下,Activity和Service之间没有联系,即使Activity退出了,Service依然在进行,我们可以这样验证下:
在MainActivity中添加一个onDestory方法:
@Override
protected void onDestroy() {
super.onDestroy();
Log.d("SERVICE", "MainActivity中onDestory()方法被调用");
}
现在启动程序并触发startService(),然后我们直接按BACK键退出程序,按下BACK键后Activity其实已经执行了onDestory()被销毁了:
但这个时候我们去设置-APP-Running正在运行的服务列表中任然可以看到我们的程序,所以服务没有随着Activity的退出而销毁:
2.使用bindService()方法来进行方法启动服务的情况下, Activity和Service绑在一起,Activity一旦退出Service就终止了。
我们启动程序并触发bindService(),然后我们直接按BACK键退出程序,Logcat输出如下,可以看到服务在Activity被destory后也执行了onDestoy()方法被销毁了:
3.startService()方法启动服务Service和Activity的关系并不大,只是Activity通知了Service一下:“你可以启动了。”然后Service就去忙自己的事情了。如果需要让Activity和Service关联更多一些,比如说在Activity中可以指定让Service去执行什么任务,这就需要用到onBind()方法了,因为onBind()方法中可以返回一个Binder类的对象,在Activity中获取到这个对象之后就可以对Service中Binder类中的方法进行操作了。
以下给出MyService类的代码,在前面的基础上增了一个MyBinder内部类继承自Binder类,并且在MyBinder类中写了两个方法,一个是开始下载startDownload()方法,一个是获取进度getProgress()方法(这里没有写逻辑代码,只是以分别打印一串字符串为例),然后实例化一个MyBinder类的对象,在onBind()方法中将这个对象返回。
package com.example.androidstudyservice;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service {
//实例化一个MyBinder类的对象
MyBinder myBinder = new MyBinder();
@Override
public IBinder onBind(Intent intent) {
Log.d("SERVICE", "onBind()方法被调用");
//返回MyBinder类的对象
return myBinder;
}
@Override
public void onCreate() {
super.onCreate();
Log.d("SERVICE", "onCreate()方法被调用");
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
Log.d("SERVICE", "onStart()方法被调用");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("SERVICE", "onDestroy()方法被调用");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("SERVICE", "onStartCommand()方法被调用");
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
Log.d("SERVICE", "onUnbind()方法被调用");
return super.onUnbind(intent);
}
//新建一个MyBinder内部类继承自Binder类
public class MyBinder extends Binder {
public void startDownload() {
Log.d("SERVICE", "startDownload()方法被执行");
}
public int getProgress() {
Log.d("SERVICE", "getProgress()方法被调用");
return 0;
}
}
}
给出MainActivity中的代码如下:
package com.example.androidstudyservice;
import com.example.androidstudyservice.MyService.MyBinder;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity implements OnClickListener{
private Button button1;
private Button button2;
private Button button3;
private Button button4;
//声明一个myBinder类,MyService.MyBinder这个是一种语法,调用内部类的时候用到
private MyService.MyBinder myBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button1 = (Button) findViewById(R.id.bt1);
button2 = (Button) findViewById(R.id.bt2);
button3 = (Button) findViewById(R.id.bt3);
button4 = (Button) findViewById(R.id.bt4);
button1.setOnClickListener(this);
button2.setOnClickListener(this);
button3.setOnClickListener(this);
button4.setOnClickListener(this);
}
private ServiceConnection conn = new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d("SERVICE", "onServiceConnected()方法被调用");
//使用(MyService.MyBinder)将myBinder向下转型得到了MyBinder的实例
myBinder = (MyService.MyBinder) service;
//有了myBinder类的实例就可以调用其中的方法了
myBinder.startDownload();
myBinder.getProgress();
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d("SERVICE", "onServiceDisconnected()方法被调用");
}
};
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.bt1:
Intent startserviceintent = new Intent(MainActivity.this, MyService.class);
startService(startserviceintent);
break;
case R.id.bt2:
Intent stopserviceintent = new Intent(MainActivity.this, MyService.class);
stopService(stopserviceintent);
break;
case R.id.bt3:
Intent bindserviceintent = new Intent(MainActivity.this, MyService.class);
bindService(bindserviceintent, conn, Context.BIND_AUTO_CREATE);
break;
case R.id.bt4:
Intent unbindserviceintent = new Intent(MainActivity.this, MyService.class);
unbindService(conn);
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d("SERVICE", "MainActivity中onDestory()方法被调用");
}
}
这个时候再触发bindService()方法启动服务可以就可以看到MyService中的startDownload()和getProgress()方法被执行了: