目录
2. 定义布局--设置按钮来开启服务和关闭服务和调用服务方法
一、什么是Service
Service是安卓四大组件之一。Service即服务,与另一组件Activity不同的是,Service是跑在后台的,用户是看不到的,而Activity是用于与用户交互的,用户是能看到的。
服务是一个后台运行的组件,执行长时间运行且不需要用户交互的任务。即使应用被销毁也依然可以工作。
二、Service的启动方式
Service的启动有两种方法:
1. 调用startService()启动服务:
若安卓的应用程序组件(如Activity)调用了startService(),则服务就会在后台启动起来,但是无法与用户交互。
特点:
一旦服务开启,那么就跟调用者(开启者)没有关系了,即使开启者关闭或者挂了,服务都仍然会在后台运行,若要关闭服务,需要额外调用stopService()来关闭。而且开启者也不能够调用服务中的方法。
2. 调用bindService()绑定服务:
当安卓应用程序的组件调用了bindService()来开启服务,那么调用者(开启者)就会和服务绑定在一起,
特点:
如果调用者挂了,那么服务也会跟着挂。当需要停止服务时,调用unbindServer()来解绑并关闭。
而且,这种方式能够让用户与服务进行交互,例如通过点击按钮调用服务中的某个方法。
三、Service的生命周期
简介
以下是官方给出的Service两种启动方式的生命周期:
通过 startService()启动:
通过startService()启动的Service,会自动调用onCreate() ,进行初始化工作,然后将会自动调用 onStartCommand(),执行相对应的服务的代码,这时候服务就相当于跑起来了。但手动调用stopService()后,服务就会停止,并自动调用onDestroy()对相应的资源进行释放。
因此其生命周期一般是:
onCreate()->onStartCommand()->onDestroy()
但注意的是,一个Service只会调用一次onCreate(),若调用了多次 startService()的话,只会调用一次onCreate(),但会多次调用onStartCommand()。因此这时候的生命周期是:
onCreate->onStartCommand()->....onStartCommand()->onDestroy()
通过bindService()启动:
通过bindService()启动的Service,也会自动调用onCreate()进行初始化工作,但不同的是,接下是会调用onBind()进行绑定,当手动调用unbindService()时,就会自动调用 onUnbind()解绑,并最后调用onDestroy()做一个资源的释放。
因此其生命周期是:
onCreate->onBind->onUnBind->onDestroy
若是先startService()开启服务,再通过bindService()绑定,则生命周期是:
onCreate->onStartCommand->...服务运行中....->(此时外界要求绑定服务)->onBind-> ...服务绑定&运行中...->onUnBind->onDestroy
4个常用的手动调用方法:
5个自动调用的方法:
总体的Service生命周期流程图:
四、Service的创建过程
无论是对于startService()或者是bindService()方式的开启服务,都首先需要:
1.定义对应的Service类
2. 在Androidmanifest.xml 文件中添加定义的Service类
1. 定义要创建的Service类
我们定义两个Service类,分别演示用 startService()方式启动和bindService()方式启动。
新建MyService.java -----用startService()启动的服务
package com.example.servicetest;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import androidx.annotation.Nullable;
public class MyService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
System.out.println(" onBInd... ");
return null;
}
public void onCreate(){
System.out.println(" onCreate... ");
super.onCreate();
}
public int onStartCommand(Intent intent,int flags,int startId){
System.out.println(" startCommand...(此处启动服务对应操作。。) ");
return super.onStartCommand(intent,flags,startId);
}
public void onDestroy(){
System.out.println(" ondestroy... ");
super.onDestroy();
}
}
新建MyBindService() --- 用bindService()方式启动的服务
package com.example.servicetest;
import android.app.Service;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
public class MyBindService extends Service {
public static int SIZE = 3;
public void onCreate() {
System.out.println("onCreate()...");
super.onCreate();
}
public class MyBinder extends Binder {
public MyBindService getService() {
System.out.println("MyBinder extends Binder的MyBindService getService()方法");
return MyBindService.this;
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d("DEBUG","public IBinder onBind(Intent arg0) 方法。。。");
return new MyBinder();
}
@Override
public boolean onUnbind(Intent intent) {
Log.d("DEBUG","onUnbind(Intent intent)方法。。。");
return super.onUnbind(intent);
}
@Override
public void unbindService(ServiceConnection conn) {
Log.d("DEBUG","unbindService(ServiceConnection conn)方法。。。");
super.unbindService(conn);
}
@Override
public void onDestroy() {
Log.d("DEBUG","onDestroy()方法。。。");
super.onDestroy();
}
public void Play(){
Log.d("DEBUG","MyBindService.Play()方法,播放音乐");
}
public void Pause(){
Log.d("DEBUG","MyBindService.Pause()方法,暂停");
}
}
2. 定义布局--设置按钮来开启服务和关闭服务和调用服务方法
在布局中,为了演示startService()和bindService()两种方法启动服务,和stopService()关闭服务和unbindService()解绑服务,我们创建的按钮如下布局:
其中MUSIC和STOPMUSIC为提供为用户使用的服务的方法,用于用户与服务之间的交互。
布局的xml文件如下:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/start"
android:onClick="onClick"
android:layout_width="234dp"
android:layout_height="93dp"
android:layout_marginStart="88dp"
android:layout_marginLeft="88dp"
android:layout_marginTop="16dp"
android:text="startService"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<Button
android:id="@+id/stop"
android:onClick="onClick"
android:layout_width="234dp"
android:layout_height="93dp"
android:text="stopService"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.17" />
<Button
android:id="@+id/unbind"
android:onClick="onClick"
android:layout_width="234dp"
android:layout_height="93dp"
android:text="unbindservice"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.462" />
<Button
android:id="@+id/music"
android:onClick="onClick"
android:layout_width="234dp"
android:layout_height="93dp"
android:text="music"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.608" />
<Button
android:id="@+id/stopmusic"
android:onClick="onClick"
android:layout_width="234dp"
android:layout_height="93dp"
android:text="stopmusic"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.753" />
<Button
android:id="@+id/bind"
android:onClick="onClick"
android:layout_width="234dp"
android:layout_height="93dp"
android:text="bindService"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/start"
app:layout_constraintVertical_bias="0.299" />
</androidx.constraintlayout.widget.ConstraintLayout>
3. MainActivity入口程序
MainActivity 要 新建一个 ServiceConnection对象,此对象要实现两个回调函数,分别是 onServiceConnected() 和 onServiceDisconnected(),前者是当调用bindService()对服务进行绑定时 调用,后者是当调用unbindService()对服务进行解绑时 调用。
MainActivity.java
package com.example.servicetest;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Service;
import android.content.ComponentName;
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.widget.Toast;
public class MainActivity extends AppCompatActivity {
Intent intent;
Intent intent2;
MyBindService service;
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
service = ((MyBindService.MyBinder)binder).getService();
int s = service.SIZE;
Log.d("DEBUG","SIZE:"+s+",onServiceConnected()方法所在线程为:"+Thread.currentThread().getName());
}
@Override
public void onServiceDisconnected(ComponentName name) {
int s = service.SIZE;
Log.d("DEBUG","SIZE:"+s+",onServiceDisconnected()方法所在线程为:"+Thread.currentThread().getName());
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClick(View view){
switch (view.getId()){
case R.id.start:
intent = new Intent(MainActivity.this,MyService.class);
Log.d("DEBUG","onClick.startService()");
Toast.makeText(this,"开启线程startService",Toast.LENGTH_LONG).show();
startService(intent);
break;
case R.id.stop:
Log.d("DEBUG","onClick.stopService()");
Toast.makeText(this, "关闭线程stopService", Toast.LENGTH_LONG).show();
stopService(intent);
break;
case R.id.bind:
intent2 = new Intent(MainActivity.this,MyBindService.class);
//flag为true表示绑定成功,为false表示绑定失败
boolean flag = bindService(intent2,conn, Service.BIND_AUTO_CREATE);
//System.out.println(flag);
Log.d("DEBUG","onClick.bindService()");
Toast.makeText(this,"开始绑定",Toast.LENGTH_LONG).show();
break;
case R.id.unbind:
stopService(intent2);
unbindService(conn);
Log.d("DEBUG","onClick.unbindService()");
Toast.makeText(this, "解除绑定", Toast.LENGTH_SHORT).show();
break;
case R.id.music:
service.Play();
Toast.makeText(this,"播放音乐",Toast.LENGTH_LONG).show();
break;
case R.id.stopmusic:
service.Pause();
Toast.makeText(this,"暂停音乐",Toast.LENGTH_LONG).show();
break;
}
}
}
4. 加入Service
若需要让定义的Service生效,必须将定义的Service写到Androidmanifest.xml中
如下图:分别定义了两个服务 MyService和MyBindService,然后想要使得自定义的服务有效,则必须在Androidmanifest.xml中记录。
5. 效果