Android中的Service分为两类,一类是本地Service,一类是远程Service,访问方式也有两种,一种是startService,一种是bindService。
startService和bindService的生命周期不同,如下图所示:
LocalService要求实现android.app.Service,可按调用方式实现相关方法,如若用startService调用,则实现onCreate、onStartCommand和onDestroy,若用bindService调用,则实现onCreate、onBind、onUnbind和onDestroy方法,当然,无论用什么方法调用,onBind方法是必须实现的,虽然可以在该方法中无任何操作。
阅读以下示例:
/**
*
* Dec 22, 2014 7:18:37 PM
* @Geloin
*
*/
package com.geloin.baseopera.service;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
/**
*
* Dec 22, 2014 7:18:37 PM
*
* @Geloin
*
*/
public class SyncService extends Service {
private IBinder binder;
@Override
public void onCreate() {
super.onCreate();
Intent intent = new Intent();
intent.setAction("SyncService");
intent.putExtra("message", "同步成功!");
sendBroadcast(intent);
Log.i("=================", "执行onCreate");
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}
public String sendMessage() {
return "成功清空!";
}
public class SyncBinder extends Binder {
public SyncService getService() {
return SyncService.this;
}
}
}
Service定义后,需要在AndroidManifest.xml文件中注册:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.geloin.baseopera"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="17"
android:targetSdkVersion="21" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".activity.BooksActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".service.SyncService"
android:exported="false" >
<intent-filter>
<action android:name="SyncService" />
</intent-filter>
</service>
</application>
</manifest>
接下来则是调用本地Service,在Activity中编写如下代码即可调用:
Intent syncIntent = new Intent(BooksActivity.this, SyncService.class);
startService(syncIntent);
定义一个Intent,重点是此Intent需要指定Context和Service,Context为当前Activity即可。
定义后startService即可。
也可以bindService方式调用:
Intent intent = new Intent(BooksActivity.this,
SyncService.class);
bindService(intent, conn, BIND_AUTO_CREATE);
与startService大同小异,主要是需要实现conn,conn为:
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "连接断开!");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
SyncService ss = ((SyncService.SyncBinder)service).getService();
String message = ss.sendMessage();
Toast.makeText(BooksActivity.this, message, Toast.LENGTH_LONG).show();
}
};
startService和bindService一个典型的区别,是bindService可以直接在ServiceConnection中获取到Service接口,获取到后即可调用本地Service定义的一些方法执行操作。
远程Service需要借助AIDL实现,下文是引用网友对AIDL的描述:
在Android平台,每个应用程序App都运行在自己的进程空间。通常一个进程不能访问另一个进程的内存空间(一个应用不能访问另一个应用),如果想沟通,需要将对象分解成操作系统可以理解的基本单元,Android提供了AIDL来处理。
AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参 数。换句比较浅显的话来说,就是我这个App应用的activity,需要调用其他App应用的Service.当然同一App应用的activity
与service也可以在不同进程间,这可以设置Service配置中,android:process=":remote"。
远程Service分为客户端与服务端,首先看服务端的实现。
第一步是在service包下定义一个aidl文件,后缀名为aidl,如“HelloService.aidl”,内容类似:
package com.geloin.baseopera.service;
interface HelloService {
/**
* 发送Hello给name
*/
String sayHello(String name);
}
此代码内容乍一看,是一个Java的Interface,但其实它与Interface还是有较大区别:
1. Java基本类型如int、long、char、boolean,以及String、CharSequence、List、Map不需要import导入;
2. 其他复杂类型,即使与aidl文件在同一个包下,也必须使用import导入;
3. 不要使用public关键字。
其他区别暂未发布,不过在编写此文件时IDE应有提示。
重点需要注意的是,aidl文件必须位于你想存放Service的包下,例如我的包为com.geloin.baseopera.service,那就必须把HelloService.aidl放在com.geloin.baseopera.service下,你把它当成一个Java文件处理就好了。
该文件编写好后,在gen下会生成com.geloin.baseopera.service.HelloService.java文件,只要它不报错,别管它,反正你也编写不了。
这一步是定义Service接口,接下来需要定义Service实现,如下所示:
/**
*
* Dec 23, 2014 9:28:43 AM
* @Geloin
*
*/
package com.geloin.baseopera.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
/**
*
* Dec 23, 2014 9:28:43 AM
* @Geloin
*
*/
public class HelloServer extends Service {
private class HelloServerImpl extends HelloService.Stub {
@Override
public String sayHello(String name) throws RemoteException {
return "Hello " + name;
}
}
@Override
public IBinder onBind(Intent intent) {
return new HelloServerImpl();
}
}
跟本地服务其实区别不大,主要在于内部类HelloServerImpl,该类继承aidl生成的HelloService.Stub,并具体实现sayHello方法。
定义实现后,需要在AndroidManifest.xml文件中定义Service:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.geloin.baseopera"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="17"
android:targetSdkVersion="21" />
<permission
android:name="com.geloin.permission.SayHello"
android:protectionLevel="normal" >
</permission>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".activity.BooksActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".service.HelloServer"
android:permission="com.geloin.permission.SayHello"
android:process=":remote" >
<intent-filter>
<action android:name="HelloServer" />
</intent-filter>
</service>
</application>
</manifest>
至此,服务端服务定义完毕。
远程客户端需要调用此服务时,只需要将上文定义的HelloService.aidl复制到客户端即可,同样会在gen中生成HelloService.java。
客户端调用Service的方式与本地Service并无差别,也可以使用startService或bindService,如下所示:
Intent intent = new Intent(BooksActivity.this,
HelloService.class);
bindService(intent, sayHelloConn, BIND_AUTO_CREATE);
ServiceConnection代码如下所示:
ServiceConnection sayHelloConn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "连接断开!");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
HelloService hs = HelloService.Stub.asInterface(service);
try {
String message = hs.sayHello("张三");
new AlertDialog.Builder(BooksActivity.this)
.setTitle("提示")
.setMessage(message)
.setPositiveButton("确定",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
unbindService(sayHelloConn);
}
}).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
};