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();
}
}
};