Android中的Service

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


發佈了208 篇原創文章 · 獲贊 119 · 訪問量 133萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章