在ServiceManager中加入自定義的服務

    當咱們要使用android的系統服務時,通常都是使用Context.getSystemService方法。例如咱們要獲取AudioManager,咱們能夠:java

AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

    獲取的服務,實際上是在ServiceManager中註冊的Binder服務,而後進行封裝後,提供給用戶。
android

    能夠看ContextImpl.java中的實現:app

   static {
        ......
        // 將AudioManager加入SYSTEM_SERVICE_MAP中,調用getSystemService時,
        // 就會從SYSTEM_SERVICE_MAP獲得AudioManager
        registerService(AUDIO_SERVICE, new ServiceFetcher() {
                public Object createService(ContextImpl ctx) {
                    return new AudioManager(ctx);
                }});
        ......
    }

    AudioManager是對IAudioService的封裝,實際操做都是使用IAudioService進行的,看AudioManager中的代碼:dom

  private static IAudioService getService()
    {
        if (sService != null) {
            return sService;
        }
        // 從ServiceManager中獲取Binder
        IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
        // 將Binder轉化成IAudioService,方便調用
        sService = IAudioService.Stub.asInterface(b);
        return sService;
    }

    上面是android系統的使用方式。若是咱們添加本身的服務,要如何作呢?eclipse

    

    咱們在eclipse中建3個測試工程:
ide

    1)MyServiceLib:這是個lib工程,須要在eclipse中勾選Is Library。後面的兩個工程,都須要將MyServiceLib添加到Library中。工具

    2) MyService: 用於在android開機時註冊自定義服務進ServiceManager。由於ServiceManager被@hide隱藏了,因此要使用它須要本身手動添加sdk包,添加方式可參考http://my.oschina.net/u/262208/blog/379548。另外,添加服務,須要System用戶,因此manifest文件中須要加上android:sharedUserId="android.uid.system", 而且要使用platform簽名簽名apk。測試

    3)MyServiceTest:用於測試上面兩個工程。
ui



下面咱們就來編碼。this


  1. 先在MyServiceLib工程中建立一個aidl文件,android編譯工具會幫咱們生成相應的java類,aidl文件以下

package com.test.lib;
interface IMyService {
    void setValue(int val);
    int getValue();
}

定義了兩個接口用於測試,setValue和getValue。

android編譯工具會幫咱們在gen目錄下生成一個IMyService的java類。

    2. 在MyService工程中建立MyService類, 這個類繼承自IMyService.Stub,實現了setValue和getValue接口,這就是一個Service。

package com.test.myservice;
 
import android.os.RemoteException;
import com.test.lib.IMyService;
 
public class MyService extends IMyService.Stub {
 
    private int value;
     
    @Override
    public void setValue(int val) throws RemoteException {
        this.value = val;
    }
 
    @Override
    public int getValue() throws RemoteException {
        return value;
    }
 
}

下面咱們將把它加入至ServiceManager中。

3. 在MyService工程中建立MyServiceApplication類

package com.test.myservice;
 
import android.app.Application;
import android.os.ServiceManager;
 
public class MyServiceApplication extends Application{
 
    @Override
    public void onCreate() {
        super.onCreate();
        ServiceManager.addService("MYSERVICE", new MyService());
    }
     
}

這是一個Application,咱們但願android系統啓動時,就建立這個Application,在onCreate方法中,建立MyService類,並加入到ServiceManager中。所以,我須要修改下manifest文件

 

  <application
        android:name=".MyServiceApplication"   //指定Application爲咱們建立的MyServiceApplication
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:persistent="true"             // 加上persistent=ture,ActivityManager建立的時候,就會建立該應用的進程,並調用MyServiceApplication的onCreate方法
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

注意,這個應用須要system用戶,並簽名纔可運行。

這樣,服務端就行了,而且開機時,咱們的服務就已經在ServiceManager中了。

4. 下面咱們提供一個Manager類方便客戶端使用。在MyServiceLib中建立MyManager類:

package com.test.lib;
 
import android.os.RemoteException;
import android.os.ServiceManager;
 
public class MyManager {
 
    private static MyManager instance;
    private IMyService myservice;
 
    public static MyManager getInstance() {
        if (instance == null) {
            instance = new MyManager();
        }
        return instance;
    }
 
    private MyManager() {
        // 從ServiceManager中獲取服務
        myservice = IMyService.Stub.asInterface(ServiceManager.getService("MYSERVICE"));
    }
 
    public void setValue(int value) throws RemoteException {
        myservice.setValue(value);
    }
 
    public int getValue() throws RemoteException {
        return myservice.getValue();
    }
 
}


5. 在MyServiceTest工程中進行測試

    經過MyManager.getInstance()能夠很方便的獲取服務的Manager,對遠程服務進行調用。咱們建立一個Activity來使用MyManager

package com.test.client;
 
import java.util.Random;
 
import android.app.Activity;
import android.content.Context;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.RemoteException;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
 
import com.test.binder.client.R;
import com.test.lib.MyManager;
 
public class MainActivity extends Activity implements OnClickListener {
 
    MyManager myManager;
     
    Button btnSetValue;
    Button btnGetValue;
    TextView tvValue;
     
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        setContentView(R.layout.activity_main);
        btnSetValue = (Button) findViewById(R.id.btn_set_value);
        btnGetValue = (Button) findViewById(R.id.btn_get_value);
        tvValue = (TextView) findViewById(R.id.tv_value);
         
        // 獲取MyManager
        myManager = MyManager.getInstance();
    }
 
    @Override
    public void onClick(View view) {
        switch (view.getId()) {
        case R.id.btn_set_value:
            int value = new Random().nextInt();
            try {
                myManager.setValue(value);
                Toast.makeText(this, "set value to "+value+ " success!", 0).show();
            } catch (RemoteException e) {
                e.printStackTrace();
                Toast.makeText(this, "set value fail!", 0).show();
            }
            break;
        case R.id.btn_get_value:
            try {
                tvValue.setText("value:"+myManager.getValue());
            } catch (RemoteException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            break;
        default:
            break;
        }
    }
     
}
相關文章
相關標籤/搜索