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





下面我们就来编码。



先在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.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;
}
}

}

更多相关文章

  1. 解决 android 在sd卡新建文件后需要重启才能找到
  2. android 高德amap开发一(地图创建)
  3. okhttp3 访问服务器失败 onFailure 提示CLEARTEXT communication
  4. android 创建 删除桌面快捷方式
  5. Android如何使用Notification进行通知
  6. Android(安卓)端如何添加自定义表情
  7. Android使用SQLite数据库的示例
  8. 如何制作Jar包并在android中调用jar包
  9. Android开发系列(三)

随机推荐

  1. 手动编译android项目
  2. Android中Launcher对于AppWidget处理的分
  3. Android之UI学习篇十:使用TabHost实现微博
  4. 关于Android中传递对象发现问题随笔
  5. android 获取uri的正确文件路径的办法
  6. Android 数字签名
  7. Android(安卓)Studio各种情况下导入libra
  8. Fragment使用总结
  9. Android init.rc的property触发机制
  10. 聊聊Android 热修复Nuwa有哪些坑