文章目录
参考文章
Android Service 启动方式
android有两种服务启动模式,startService 和 bindService
startService 和 bindService 区别
模式名称 | 特点 |
---|---|
startService | 一旦服务开启跟调用者(开启者)就没有任何关系了。开启者退出了,开启者挂了,服务还在后台长期的运行,只有通过调用停止服务的方法才能停止服务,或者是整个程序被kill掉,那么服务也会随之kill。开启者不能调用服务里面的方法 |
bindService | bind的方式开启服务,绑定服务,调用者挂了,服务也会跟着挂掉。绑定者可以调用服务里面的方法。(说白了就和小程序一样,打开的时候使用,用完了就关闭拍屁股走人,一次性滴)注意:绑定服务不会调用onstart()或者onstartcommand()方法 |
Service的创建以及在AndroidManifest.xml文件中的声明
我们通过android studio创建service的时候,编译器自动的帮助我们在清单文件中声明了相关属性
<service
android:name=".StartService"
android:enabled="true"
android:exported="true"></service>
- android:name:对应Service类名
- android:exported:代表是否能被其他应用隐式调用,其默认值是由service中有无intent-filter决定的,如果有intent-filter,默认值为true,否则为false。为false的情况下,即使有intent-filter匹配,也无法打开,即无法被其他应用隐式调用。
- android:enabled:是否可以被系统实例化,默认为 true因为父标签 也有 enable 属性,所以必须两个都为默认值true的情况下服务才会被激活,否则不会激活。
startService
startService生命周期
- startService(Intent)通过这种方式开启的服务,执行的生命周期方法:第一次调用startService的时候:onCreate→onStartCommand再次调用startService的时候:只执行onStartCommand
- 想停止用startService开启的服务要使用stopService(Intent),stopService执行之后,Service会走onDestroy()方法,执行之后Service销毁,再次调用stopService没有反应
- 如果在Activity中通过startService方法开启一个服务,当Activity退出的时候Service不会销毁,依然在后台运行,只有手动调用stopService或者在应用管理器中关闭Service,服务才会销毁
startService案例
设计一个界面,上面有两个按钮,分别是启动按钮与停止按钮,用来启动、停止服务
创建一个service
public class StartService extends Service {
// 声明一个线程
private Thread myThread;
// 控制线程的运行
private boolean flag=true;
// 判断当前service内的线程是否在运行
private boolean trigger=false;
public StartService() {
}
/**
* 绑定服务时才会调用
* 必须要实现的方法
* @param intent
* @return
*/
@Override
public IBinder onBind(Intent intent) {
Log.w("StartService", "onBind()");
return null;
}
/**
* 首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或 onBind() 之前)。
* 如果服务已在运行,则不会调用此方法。该方法只被调用一次
*/
@Override
public void onCreate() {
super.onCreate();
// 在服务创建时,实例化一个线程
myThread=new Thread(new Runnable() {
@Override
public void run() {
while(flag){
try {
SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Log.w(format.format(new Date(System.currentTimeMillis())), "服务正在运行。。。。");
Thread.sleep(1000);
}catch(Exception e){
e.printStackTrace();
}
}
}
});
Log.w("StartService", "服务被创建了");
}
/**
* 每次通过startService()方法启动Service时都会被回调。
* @param intent
* @param flags
* @param startId
* @return
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.w("StartService", "服务onStartCommand()被调用了");
// 在onStartCommand触发时启动线程,如果线程已经启动就无须再次启动
if(!trigger){
myThread.start();
trigger=true;
}
return super.onStartCommand(intent, flags, startId);
}
/**
* 调用stopService()停止服务销毁时的回调
*/
@Override
public void onDestroy() {
// 在service销毁时结束进程
// 将进程的运行标志设为false
flag=false;
trigger=false;
Log.w("StartService", "服务被销毁了");
super.onDestroy();
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
private Button startBtn;
private Button stopBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startBtn = this.findViewById(R.id.startBtn);
stopBtn = this.findViewById(R.id.stopBtn);
// 创建服务实例
final Intent service = new Intent(this, StartService.class);
startBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 启动服务
MainActivity.this.startService(service);
}
});
stopBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 停止服务
MainActivity.this.stopService(service);
}
});
}
}
点击启动服务时,启动服务的activity进入了后台,服务并不会结束
结束服务只有kill当前程序或者调用stopService方法来结束service
bindService
- bindService启动服务特点:(和小程序一样,一次性滴,进入页面的时候绑定service,退出的时候关闭service)所以一般我们都在Activity的onStart方法中绑定服务,在onStop中解绑服务
- bindService启动的服务和调用者之间是典型的client-server模式。调用者是client,service则是server端。service只有一个,但绑定到service上面的client可以有一个或很多个。这里所提到的client指的是组件,比如某个Activity。
- client可以通过IBinder接口获取Service实例,从而实现在client端直接调用Service中的方法以实现灵活交互,这在通过startService方法启动中是无法实现的。
- bindService启动服务的生命周期与其绑定的client息息相关。当client销毁时,client会自动与Service解除绑定。当然,client也可以明确调用Context的unbindService()方法与Service解除绑定。
bindService实例
结果实例
activity 界面
<?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/fun01_btn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="服务方法1"
app:layout_constraintBottom_toTopOf="@+id/fun02_btn"
app:layout_constraintEnd_toEndOf="@+id/fun02_btn"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/fun02_btn"
app:layout_constraintTop_toBottomOf="@+id/bind_btn" />
<Button
android:id="@+id/fun02_btn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="服务方法2"
app:layout_constraintBottom_toTopOf="@+id/fun03_btn"
app:layout_constraintEnd_toEndOf="@+id/fun03_btn"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/fun03_btn"
app:layout_constraintTop_toBottomOf="@+id/fun01_btn" />
<Button
android:id="@+id/fun03_btn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="服务方法3"
app:layout_constraintBottom_toTopOf="@+id/unbind_btn"
app:layout_constraintEnd_toEndOf="@+id/unbind_btn"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/unbind_btn"
app:layout_constraintTop_toBottomOf="@+id/fun02_btn" />
<Button
android:id="@+id/bind_btn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="绑定服务"
app:layout_constraintBottom_toTopOf="@+id/fun01_btn"
app:layout_constraintEnd_toEndOf="@+id/fun01_btn"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/fun01_btn"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/unbind_btn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="172dp"
android:text="解绑服务"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/fun03_btn" />
</androidx.constraintlayout.widget.ConstraintLayout>
activity
public class MainActivity extends AppCompatActivity {
Button btn_bind;
Button btn_unbind;
Button btn_fun01;
Button btn_fun02;
Button btn_fun03;
private MyService myService;
private ServiceConnection connection;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 绑定服务
btn_bind = findViewById(R.id.bind_btn);
btn_bind.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (connection == null) {
Intent intent = new Intent(MainActivity.this, MyService.class);
connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myService = ((MyService.MyBinder) service).getService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
MainActivity.this.bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
}
});
// 解绑服务
btn_unbind = findViewById(R.id.unbind_btn);
btn_unbind.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (connection != null) {
unbindService(connection);
connection = null;
}
}
});
btn_fun01 = findViewById(R.id.fun01_btn);
btn_fun01.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (connection != null) {
myService.fun01();
}
}
});
btn_fun02 = findViewById(R.id.fun02_btn);
btn_fun02.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (connection != null) {
myService.fun02();
}
}
});
btn_fun03 = findViewById(R.id.fun03_btn);
btn_fun03.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (connection != null) {
myService.fun03();
}
}
});
}
}
service(核心代码)
public class MyService extends Service {
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
Log.i("MyService", "onBind");
return new MyBinder();
}
public void fun01() {
Log.i("MyService", "fun01");
}
public void fun02() {
Log.i("MyService", "fun02");
}
public void fun03() {
Log.i("MyService", "fun03");
}
@Override
public boolean onUnbind(Intent intent) {
Log.i("MyService", "onUnBind");
return super.onUnbind(intent);
}
public class MyBinder extends Binder {
public MyService getService() {
return MyService.this;
}
}
}