目录
1.Service 简介
Service 是Android四大组件之一,它的作用是实现程序后台运行。它的运行不依赖用户界面,生命周期长。比如执行下载,音乐播放等任务。Service一般依赖于创建它的进程,一旦所依赖进程被杀死,Service也会停止执行。Service默认执行在主线程,当执行耗时操作时,需要在Service内部手动开启子线程,防止阻塞主线程。
2.Service 的生命周期
在项目任何位置调用context的startService()方法,相应的服务就会启动起来,之后会一直保持运行状态,直到stopService()或者stopSelf()被调用。还可以调用context的bindService()方法来获得一个服务的持久连接,只要调用方跟服务之间的连接没有断开,服务就会一直保持运行状态。
①onCreate():当调用startService()或者bindService()时,如果这个Service之前没有创建过,onCreate()就会执行。
②onStartCommand():当调用startService()时,onStartCommand()方法就会回调,如果这个Service之前没有创建过,就会先执 行onCreate(),再执行onStartCommand()。每调用一次startService(),就会执行一次onStartCommand(),但每个服务只存在一个实例,只需调用一次stopService()或者stopSelf()方法服务就会停止。
③onBind():当调用bindService()时,onBind()方法就会回调,如果这个Service之前没有创建过,就会先执行onCreate(),再执行onBind()。可以获取onBind()中返回的IBinder对象的实例,自由地与服务通信。
④onDestroy():当调用startService(),再调用stopService(),onDestroy()就会执行,表示服务被销毁。当调用bindService(),再调用unBindService()也会执行。(注意:一个服务即调用了startService(),又调用了bindService(),这种情况下需要同时调用stopService()和unBindService(),onDertroy()才会执行)
3.Service 的基本用法
新建一个Service,如下:
public class MyService extends Service {
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
MyService继承于Service,onBind()方法是Service中唯一一个抽象方法,必须在子类实现。我们可以再重写其他方法。
public class MyService extends Service {
public MyService() {
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
如果我们希望服务一启动就执行某个动作,可以写在onStartCommand()方法里。我们也需要在onDestroy()方法里进行一些资源回收。注意记得在AndroidManifest.xml 文件中注册。
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"></service>
我们设置两个按钮,一个来启动服务,一个来停止服务。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/start_service"
android:text="Start"
android:layout_marginTop="90dp"
android:layout_marginStart="120dp"
android:layout_width="120dp"
android:layout_height="80dp" />
<Button
android:id="@+id/stop_service"
android:text="Stop"
android:layout_marginStart="120dp"
android:layout_below="@id/start_service"
android:layout_width="120dp"
android:layout_height="80dp" />
</RelativeLayout>
我们在MyService各方法中添加打印语句,来感受服务的执行。
public class MyService extends Service {
public MyService() {
Log.d("MyService","MyService()");
}
@Override
public void onCreate() {
super.onCreate();
Log.d("MyService","onCreate()");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("MyService","onStartCommand()");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.d("MyService","onDestroy()");
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.d("MyService","MyService()");
throw new UnsupportedOperationException("Not yet implemented");
}
}
活动代码:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Button btStart;
Button btStop;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btStart = findViewById(R.id.start_service);
btStop = findViewById(R.id.stop_service);
btStart.setOnClickListener(this);
btStop.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.start_service:
Intent startIntent = new Intent(this,MyService.class);
startService(startIntent); //开启服务
break;
case R.id.stop_service:
Intent stopIntent = new Intent(this,MyService.class);
stopService(stopIntent); //结束服务
break;
}
}
}
点击start按钮,观察打印日志,onCreate(),onStartCommand()都执行了,多次点击,只有onStartCommand()执行。点击stop按钮,onDestroy()执行了。
我们也可以通过bindService()启动服务,获取onBind()中返回的IBinder对象的实例,自由地与服务通信。首先先在MyService中新建一个继承Binder的类,假设是一个对下载进行管理的类,在内部提供开始下载和查看下载进度的虚拟方法(打印一条语句)。并在MyService中创建它的实例,在onBind()中返回这个实例。代码如下:
public class MyService extends Service {
private MyDownloadBinder mBinder = new MyDownloadBinder();
class MyDownloadBinder extends Binder{
public void startDownload(){
Log.d("MyService","Start download");
}
public void getProgress(){
Log.d("MyService","Get progress");
}
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return mBinder;
}
.....
}
在活动中将活动跟服务绑定,获取服务onbind()返回IBinder实例,就可以调用该服务里Binder的方法。代码如下:
public class SecondActivity extends Activity implements View.OnClickListener {
Button btStart;
Button btStop;
private MyService.MyDownloadBinder binder;
private ServiceConnection connection = new ServiceConnection() {
//活动与服务成功绑定时调用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
binder = (MyService.MyDownloadBinder)service;
binder.startDownload(); //调用服务中Binder方法
}
//活动与服务解绑时调用
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
btStart = findViewById(R.id.start_service);
btStop = findViewById(R.id.stop_service);
btStart.setOnClickListener(this);
btStop.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.start_service:
Intent startIntent = new Intent(this,MyService.class);
bindService(startIntent,connection,BIND_AUTO_CREATE); //绑定服务,第3个参
//数为标志位
break;
case R.id.stop_service:
unbindService(connection); //解绑服务
break;
}
}
}
我们创建了一个ServiceConnection的匿名类,在onServiceConnected()方法中获得实例,在bindService中与服务绑定,这样活动就可以与服务进行通信。一个服务可以与多个活动进行绑定通信,绑定后所有活动都获得相同的实例。
上面的服务都运行在后台,我们无法感知,这时我们可以使用前台服务,因为前台服务会有一个正在运行的标志在系统状态栏显示,类似于通知的效果。通过修改MyService代码可实现前台服务。
public class MyService extends Service {
@Override
public void onCreate() {
super.onCreate();
Intent intent = new Intent(this,MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,intent,0);
Notification notification = new Notification.Builder(this)
.setContentTitle("title")
.setContentText("text")
.setWhen(System.currentTimeMillis())
.setContentIntent(pendingIntent)
.build();
startForeground(1,notification);
}
.....
}
当我们在服务中执行耗时操作时,需要手动开子线程,当我们执行完想要服务停下来需要调用stopSelf()或者stopService()才能停下来。Androidt提供IntentService来方便我们,IntentService每次执行完都会自动停止,并且提供一个在子线程执行的方法给我们执行耗时操作。用法如下;
public class MyService extends IntentService {
MyService(){
super("MyService");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
//耗时操作
}
.....
}
我们可以在onHandleIntent()方法中执行耗时操作。这里先要提供一个无参构造函数,并且必须在其内部调用父类的有参构造函数。当执行完毕时,onDestroy()方法就会被调用。