当我们要使用android的系统服务时,一般都是使用Context.getSystemService方法。例如我们要获取AudioManager,我们可以:

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

    获取的服务,其实是在ServiceManager中注册的Binder服务,然后进行封装后,提供给用户。

    可以看ContextImpl.java中的实现:

   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中的代码:

  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中建3个测试工程:

    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:用于测试上面两个工程。

下面我们就来编码。

  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;
        }
    }
}
你可能感兴趣的内容
0条评论

dexcoder

这家伙太懒了 <( ̄ ﹌  ̄)>
Owner