当我们要使用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遍历文件Listfile返回值为null问题解决方法适用Android8.
  3. 【记录】 Android 双卡手机获取两个IMEI等
  4. Ue4.20 安卓开发配置及Android Studio 调试ue安卓工程
  5. Android上传文件至PHP服务器
  6. Gradle 修改生成apk时的文件名
  7. Android 实现apk文件下载并自动安装
  8. Android客户端上传文件到服务器端
  9. android上下文 判断两个context是否相同

随机推荐

  1. Android对emoji表情的处理
  2. 从零开始学Android之XML
  3. 把Android原生模拟器秒成渣的神器——Gen
  4. 【Android(安卓)开发教程】使用Intent-Fi
  5. 开发规范:《阿里巴巴Android开发手册》之
  6. android 系统架构简介
  7. Android支付封装(微信+支付宝)
  8. ABI:第二季度Android应用下载量超过苹果iO
  9. 《Android开发艺术探索》第十章重点笔记
  10. Android 4.0用户界面设计和元素-ICS简介