目录
- 服务组件及应用
-
- 1. 服务概念
- 2. 服务类型
-
- 2.1 本地服务
- 2.2 远程服务
- 3. service启动方式与生命周期
- 4. 两种方法的简单实例
-
- 4.1 非绑定式的服务
-
- 4.1.1 效果
- 4.1.2 代码
- 4.2 绑定式的服务
-
- 4.2.1 效果
- 4.2.2 代码
服务组件及应用
1. 服务概念
Service也是Android系统四大组件1之一,它是一种长生命周期、没有可视化界面、运行于后台的一种服务程序。
比如:播放音乐的时候,你有可能想边听音乐边干些其他事情,当退出播放音乐的应用,如果不用Service,就听不到歌了——这就是Service的用武之地了。
Android后台运行的很多Service是在系统启动时被开启的,以支持系统的正常工作。
比如:MountService监听是否有SD卡安装及移除,PackageManagerService提供软件包的安装、移除及查看等。
激活和停止Service通常是由其他组件完成的。例如,组件Activity的超类Context提供了激活和停止Service的方法。
如同Activity组件一样,Service组件必须在清单文件里使用相应的标签。使用菜单File→New→Service创建的服务组件,将自动在清单文件里注册。
2. 服务类型
服务类型可划分为本地服务和远程服务,也可划分为绑定式服务与非绑定服务。
2.1 本地服务
本地服务用于应用程序内部(同一个apk内被调用),使用startService()启动服务,使用stopService()停止服务。
在服务内部可以调用Service.stopSelf() 或 Service.stopSelfResult()来自己停止。无论调用了多少次startService(),都只需调用一次stopService()来停止。
2.2 远程服务
远程服务用于应用程序之间(被另一个apk调用)。
可以定义接口并把接口暴露出来,以便其他应用进行操作,比如一个天气预报服务。客户端建立到服务对象的连接,并通过那个连接来调用服务。
通过调用bindService()方法建立连接并启动服务,调用 unbindService()关闭连接。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。
远程服务提供给可被其他应用复用。
3. service启动方式与生命周期
-
非绑定式服务:
使用
启动service,调用startService()
和onCreate()
2两个方法。该service只能创建一次,也就是说onStartCommand()
只会执行一次。(但每次调用onCreate()
时,startService()
onStartCommand()
方法都会被调用。)
使用
来结束服务,调用stopService()
方法即可终止服务。onDestroy()
-
绑定式服务:
第一次执行
时,会调用bindService()
和onCreate()
方法创建服务并将service与activity绑定。(但是多次执行onBind()
bindService()
时,并不会多次创建服务和绑定服务,也就不会再次调用这两个方法。)
当调用
方法或者调用者Context不存在时,比如绑定的activity调用unbindService()
方法,就会调用finish()
和onUnbind()
来结束服务。onDestroy()
- 非绑定式服务和绑定式服务的区别
- 1、startService启动的服务默认无限期执行,bindService启动的服务的生命周期与其绑定者相关。
- 2、若使用startService启动服务,则创建后将无法再与其传递消息;若使用bindService启动服务,则可以通过IBinder接口实现灵活的交互。
4. 两种方法的简单实例
4.1 非绑定式的服务
4.1.1 效果
界面如下图所示:
logcat中输出:
2020-04-17 16:10:52.756 24674-24674/com.example.myapplication_service V/MyService_unbind: service is created!
2020-04-17 16:10:52.756 24674-24674/com.example.myapplication_service V/MyService_unbind: service is started!
2020-04-17 16:11:01.823 24674-24674/com.example.myapplication_service V/MyService_unbind: service is destroyed!
4.1.2 代码
首先在项目中new一个Service(注意,Service中又两个选项,new的是Service而不是Service(IntentService))
创建初始会自带
onBind()
方法,由于此处写的是非绑定式的方法,直接在里面
return null;
即可。
MyService_unbind.java
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class MyService_unbind extends Service {
public MyService_unbind() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return null;
}
//创建服务
@Override
public void onCreate() {
super.onCreate();
Log.v("MyService_unbind","service is created!");
}
//开始服务
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v("MyService_unbind","service is started!");
return START_STICKY;
}
//结束服务
@Override
public void onDestroy() {
super.onDestroy();
Log.v("MyService_unbind","service is destroyed!");
}
}
由于服务是不与用户交互的,此处为了使代码更简单且演示效果更明显,就在每个方法中用logcat打印出一句话表明服务的生命周期,并在布局文件中写两个用于启动服务和终止服务的button。
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">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.403" />
<Button
android:id="@+id/btn_ubs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动非绑定式服务"
app:layout_constraintBottom_toTopOf="@+id/btn_ubd"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:layout_constraintVertical_bias="0.676" />
<Button
android:id="@+id/btn_ubd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="204dp"
android:text="关闭非绑定式服务"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
在MainActivity中写两个button的触发事件,在启动服务按钮中使用
startService()
启动service,在终止按钮中使用
stopService()
来结束服务。
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
Button btn_ubs;
Button btn_ubd;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取程序界面的两个按钮
btn_ubs = (Button)findViewById(R.id.btn_ubs);
btn_ubd = (Button)findViewById(R.id.btn_ubd);
btn_ubs.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,MyService_unbind.class);
startService(intent);
}
});
btn_ubd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,MyService_unbind.class);
stopService(intent);
}
});
}
}
需要注意的问题:
1、若没有直接new一个service,则要手动在
AndroidManifest.xml
文件里面注册自己写的service。若是new的service,则会在清单文件中自动注册,如下所示。
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"></service>
2、布局文件中的button的text最好写在strings.xml中,可以根据布局文件中的警告进一步修改。
4.2 绑定式的服务
4.2.1 效果
界面如下图所示:
每点一次按钮,textview就会刷新成自第一次点击按钮后到这次点击按钮所经历的秒数。
4.2.2 代码
new一个service,命名为BinderService来写绑定式服务。
绑定式服务需要重写
onBind()
方法,返回一个IBinder的对象。IBinder是一个接口,一般我们会继承实现了IBinder类的Binder类,在其中实现自己的方法。
BinderService.java
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
public class BinderService extends Service {
public BinderService() {
}
private int count = 0;
class Mybinder extends Binder{
public int getcount(){return count;}
}
Mybinder binder = new Mybinder();
@Override
public void onCreate() {
super.onCreate();
new Thread(new Runnable() {
@Override
public void run() {
while (true){
try{
//线程启动后每过1s,count+1
Thread.sleep(1000);
count++;
}catch (Exception e){e.printStackTrace();}
}
}
}).start();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return binder;
}
}
在布局文件中定义一个button来启动绑定式服务,textview显示当前秒数。
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">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.179" />
<Button
android:id="@+id/btn_bs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/btn_bs_text"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
</androidx.constraintlayout.widget.ConstraintLayout>
在MainActivity中写button的触发事件,在启动服务按钮中用
bindService()
来绑定服务。
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
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.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
Button btn_bs;
// 创建绑定服务下的binder的实例
BinderService.Mybinder mybinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_bs = (Button)findViewById(R.id.btn_bs);
final TextView textView = (TextView)findViewById(R.id.textView);
// 给出activity要调的服务BinderService,是bindService的第一个参数
Intent binderintent = new Intent(MainActivity.this,BinderService.class);
// bindService的第二个参数
ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 这里的service就是onBind()方法返回的binder对象
mybinder = (BinderService.Mybinder)service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
// 服务连接结束时,设置其为null
mybinder = null;
}
};
// 绑定服务,有三个参数:intent、ServiceConnection和int
// 其中的第三个参数是指明绑定效果
bindService(binderintent,connection, Context.BIND_AUTO_CREATE);
btn_bs.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
textView.setText(mybinder.getcount()+"");
}
});
}
}
- Android四大组件分别为:Activity/Service/BroadCast Recevicer/Content provider ↩︎
- Service的onStart方法在API 5时被废弃,替代它的是onStartCommand方法。 ↩︎