1 一张图解读Service
这里用一张图解读 生命周期 & 基本概念 & 关键回调方法解读
2 Service类关系解读
关于Service类的父类、子类的继承关系图如下所示:
3 配置Service
Service和Activity都是android系统组件,都需要在AndroidManifest.xml配置文件中声明,否则系统将不识别也不执行该Service。简单的service组件内容如下:
<service android:name=".FirstService">
</service>
常见属性一般有name、exported(是否允许被其他应用调用),permission(启动service需要的权限)、process(该service所在进程,默认是在APP进程中,但可以指定其他进程),无需指定label属性(因为没有界面)。如果未设置intent-filter这一选项时则不能直接响应Intent,只能通过指定Component的Intent来启动。
4 Service操作
4.1 Service启动/停止
启动和停止服务的关键API如下所示:
//定义Intent,携带service
Intent intent = new Intent(MainActivity.this,com.ags.XXXService.class);
//启动服务
startService(intent);
//停止服务
stopService(intent);
关于service:
- 连续多次启动service后,onCreate回调函数执行一次,onStartCommand回调函数执行多次。
- 使用启动/停止服务的API并不能与原来的调用者之间有数据交换/通信的能力,想要有通信能力,需要绑定service。
注意:从android 5.0开始Google要求必须使用显式Intent启动service组件。
4.2 绑定Service并通信
如果service想和启动者之间进行通信和交换数据,则应该使用bindService()和unbindService()方法启动/关闭service。这里使用一个案例来解读下bindService和unbindService方法。这里设置了两个按键,一个绑定服务,绑定成功后调用service组件的方法addNum;另一个解绑服务。
首先,写一个自定义的service继承系统服务,名为BinderService,代码实现如下:
public class BinderService extends Service {
private static String TAG = "BinderService";
public class AgsBinder extends Binder {
public BinderService getService(){
return BinderService.this;
}
}
//通过binder实现 调用者和service之间的通信
private AgsBinder binder = new AgsBinder();
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return binder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "onUnBind");
return super.onUnbind(intent);
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
/**参数解读:
*service:通过intent指定要启动的service
* conn:监听访问者和service的连接情况,有连接成功/失败的回调处理
* flags:是否自动创建service
*/
@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
Log.d(TAG, "bindService");
return super.bindService(service, conn, flags);
}
@Override
public void unbindService(ServiceConnection conn) {
super.unbindService(conn);
Log.d(TAG, "unbindService");
}
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy");
super.onDestroy();
}
public int addNum(int a,int b){
Log.d(TAG, "addNum: "+(a+b));
return a+b;
}
}
其次,MainActivity代码的实现如下所示:
public class MainActivity extends AppCompatActivity {
private static String TAG = "MainActivity";
private Button btn_bind;
private Button btn_unbind;
private BinderService binderservice = null;
private boolean isBound = false;
private ServiceConnection connection = new ServiceConnection() {
@Override //连接成功回调
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "onServiceConnected");
isBound = true;
BinderService.AgsBinder binder = (BinderService.AgsBinder)service;
binderservice = binder.getService();
Log.d(TAG, "Activity onServiceConnected");
//连接成功后就可以调用binderservice的各种方法了。
int x = binderservice.addNum(3,4);
Log.d(TAG, "Activity call binderservice.addNum:"+x);
}
@Override //发生意外回调,unbind并不会导致回调
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "onServiceDisconnected");
isBound = false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_bind = findViewById(R.id.btn_bind);
btn_unbind = findViewById(R.id.btn_unbind);
btn_bind.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, com.ags.myapplication.BinderService.class);
//intent.putExtra("from", "MainActivity");
Log.d(TAG, "onClick:bindService");
//启动并绑定service
bindService(intent,connection,BIND_AUTO_CREATE);
}
});
btn_unbind.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(isBound){
Log.d(TAG, "onClick:unbindService");
//解绑service
unbindService(connection);
isBound = false;
}
}
});
}
}
注意:启用端和Service解绑时,onServiceDisconnected不会被调用。onServiceDisconnected被调用的情况是发生在启用端和Service连接意外丢失时,这个时候确定 启用端和Service一定是断开连接的。
5 IntentService
service存在的问题:与所在应用位于同一个进程中,不能在service中直接处理耗时任务。要想解决这个问题就需要使用IntentService了,IntentService有如下优势:
- 会创建单独的worker线程来处理所有Intent请求 以及 处理onHandleIntent方法实现的代码。
- 请求处理完成后自动停止,无需使用stopSelf方法来停止该service。
- 只需实现onHandleIntent方法就可以启动service在后台执行耗时工作。
这里使用一个案例来解读下耗时任务的处理,耗时任务intentService代码实现如下:
public class SecondService extends IntentService {
private static String TAG = "IntentService";
public SecondService() {
super("SecondService");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
//该方法内可以执行耗时函数而不阻塞UI主线程
@Override
protected void onHandleIntent(@Nullable Intent intent) {
Log.d(TAG, "onHandleIntent: Start Task");
synchronized (this){
try {
wait(20*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Log.d(TAG, "onHandleIntent: End Task");
}
}
MainActivity代码如下所示:
public class MainActivity extends AppCompatActivity {
private static String TAG = "MainActivity";
private Button btn_start;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_start = findViewById(R.id.btn_start);
btn_start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//和正常service一样启动。
Intent intent = new Intent(MainActivity.this, com.ags.myapplication.SecondService.class);
startService(intent);
}
});
}
}
由于IntentService使用的是单独的worker线程,因此不会阻塞UI主线程。
6 跨进程AIDL Service
6.1 aidl简介
关键词解读:
- IPC(Inter-Process Communication):即跨进程通信,用于进程间的数据交换。
- AIDL(android interface definition language):Android接口定义语言用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能。
AIDL的目的:用来定义远程接口,即定义两个进程之间的通信接口。
为啥要弄AIDL?实现跨进程需要编写很多复杂的代码,于是android提供了AIDL,通过编写简单的AIDL文件,编译器根据AIDL的规则生成那些复杂的代码,化繁为简是根本。
6.2 接口规则与编译
aidl接口文件( .aidl为后缀)支持的数据类型如下:
- 基本数据类型 byte、char、short、int、long、float、double、boolean(默认tag为in)
- 字符串 String,CharSequence(默认tag为in)
- 实现Parcelable接口的数据类型(需要import)
- List 类型(内容必须是AIDL支持的类型,或是其它AIDL声明的接口,需要import)
- Map类型(内容必须是AIDL支持的类型,或是其它AIDL声明的接口,需要import)
关于定向tag:AIDL中的定向 tag 表示了在跨进程通信中数据的流向:
- in 表示数据只能由客户端流向服务端。可理解为 客户端的输入,服务端输出。
- out 表示数据只能由服务端流向客户端。可理解为 服务端输入,客户端输出。
- inout 表示数据可在服务端与客户端之间双向流通。客户端/服务端均可输入/输出。
接下来直接新建一个aidl文件即可,内容如下:
// IMyAidlInterface.aidl
package com.ags.myservice;
interface IMyAidlInterface {
void testMethod1(String str);
void testMethod2(int id);
}
执行make project后 编译生成IMyAidlInterface.java文件。
6.3 aidl的使用
这里从两个方面:client(获取并使用服务)和service(实现并提供服务)来看如何使用:
- service端关键步骤:建立并定义aidl文件->实现接口方法和生命周期方法->在AndroidMainfest.xml文件中注册服务 & 声明为远程服务。
- client端关键步骤:拷贝服务端AIDL文件到客户端目录下->通过Intent对指定的Service进行绑定->使用Stub.asInterface接口获取服务端Binder,调用服务提供的接口方法。
案例实现如下:
@1 服务端Service:
这里建立一个aidl文件,直接copy上面的,如下所示:
// IMyAidlInterface.aidl
package com.ags.myservice;
interface IMyAidlInterface {
void testMethod1(String str);
void testMethod2(int id);
}
编译后,生成IMyAidlInterface.java。内容较多,这里仅展示框架部分,如下所示:
package com.ags.myservice;
public interface IMyAidlInterface extends android.os.IInterface
{
public static class Default implements com.ags.myservice.IMyAidlInterface
{
//...
@Override
public android.os.IBinder asBinder() {
return null;
}
}
public static abstract class Stub extends android.os.Binder implements com.ags.myservice.IMyAidlInterface
{
private static final java.lang.String DESCRIPTOR = "com.ags.myservice.IMyAidlInterface";
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
public static com.ags.myservice.IMyAidlInterface asInterface(android.os.IBinder obj)
{
//...
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
//...
}
private static class Proxy implements com.ags.myservice.IMyAidlInterface
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
//...
public static com.ags.myservice.IMyAidlInterface sDefaultImpl;
}
static final int TRANSACTION_testMethod1 = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_testMethod2 = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
//...
public static com.ags.myservice.IMyAidlInterface getDefaultImpl() {
return Stub.Proxy.sDefaultImpl;
}
}
public void testMethod1(java.lang.String str) throws android.os.RemoteException;
public void testMethod2(int id) throws android.os.RemoteException;
}
有了 IMyAidlInterface这类,我们创建一个Service,实现aidl中的方法,如下所示:
public class TestAIDLService extends Service {
private static String TAG = "TestAIDLService";
//实例化AIDL的Stub类(Binder子类),实现aidl中的方法
IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub(){
@Override
public void testMethod1(String str) throws RemoteException {
Log.d(TAG, "service Impl:testMethod1:exec");
}
@Override
public void testMethod2(int id) throws RemoteException {
Log.d(TAG, "service Impl:testMethod1:exec");
}
};
//life cycle functions
@Override
public void onCreate() {
Log.d(TAG, "onCreate: exec");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand: exec");
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind: exec");
//返回继承自Binder的Stub类型的Binder
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "onUnbind: exec");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy: exec");
super.onDestroy();
}
}
在AndroidMainfest.xml中注册服务 & 声明为远程服务,配置为:
<service
android:name=".TestAIDLService"
android:process=":remote"
android:exported="true">
<intent-filter>
<action android:name="com.ags.myservice.IMyAidlInterface"/>
</intent-filter>
</service>
注意:
- 这里remote表示将本地服务设置成远程服务。
- 此处Intent的action必须写成“服务器端包名.aidl文件名”。
@2 客户端MainActivity:
将服务端的AIDL文件所在的包复制到客户端目录下($Project/app/src/main),并编译。然后编写代码,如下所示:
public class MainActivity extends AppCompatActivity {
private static String TAG = "MainActivity";
private Button btn_start;
private IMyAidlInterface aidlService;
private ServiceConnection connection = new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
aidlService = IMyAidlInterface.Stub.asInterface(service);
try {
aidlService.testMethod1("testString");
Log.d(TAG, "onServiceConnected");
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "onServiceDisconnected");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_start = findViewById(R.id.btn_start);
btn_start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//这里参数与服务器端的action一致,为"服务器包名.aidl接口文件名"
Intent intent = new Intent("com.ags.myservice.IMyAidlInterface");
//注意:Android5.0后只通过显式Intent绑定远程Service
intent.setPackage("com.ags.myservice");//指定包名
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
});
}
}
整个过程中横跨两个应用,调用者是客户端,被调用者是服务端。至此AIDL 通信案例完成。
关于AIDL更多内容可查看:Android 开发者之Android 接口定义语言 (AIDL)
7 获取系统Service
这里主要解读getSystemService方法,如果让安卓应用能够发短信、来电处理、接收陀螺仪数据等。。。那么获取系统服务就必不可少,同时 getSystemService是Android很重要的一个API,它是Activity的一个方法,根据传入的NAME来取得对应的Object,进而获得系统服务。使用如下所示:
public class MainActivity extends AppCompatActivity {
private static String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TelecomManager telecomManager = (TelecomManager) getSystemService(Context.TELECOM_SERVICE);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
}
}
获取了系统服务,接下来就可以根据每个不同的服务来获取需要的方法了。更多关于getSystemService的内容可以查看文档:Android activity关键方法getSystemService详解
8 官方文档索引
关于service 更多内容查看文档:Android组件之Service组件
总结
- 了解service基本概念、生命周期、AndroidManifest配置、service启动(两种方式差别)、IntentService、aidl原理以及aidlservice编写。
- 熟练编写相关代码:service启动/停止、service绑定与通信、IntentService、aidl以及aidlservice、获取系统服务与使用系统服务(比如Telephony/Alarm/Power等等)。