Android实现在ServiceManager中加入自定义服务的方法详解
本文实例讲述了android实现在servicemanager中加入自定义服务的方法。分享给大家供大家参考,具体如下:
当我们要使用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包,添加方式可参考在eclipse中使用sdk中@hide函数的方法附加说明。另外,添加服务,需要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.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; } } }
附:在eclipse中使用sdk中@hide函数的方法
我们使用eclipse进行android开发时,使用的是adt中提供的sdk,里面是不包含@hide函数和变量的。因为android为了兼容、安全等原因,在提供sdk时,把这些函数给隐藏了。但是,很多时候,我们又需要使用这些函数,因此我们需要手动添加android sdk。例如,当我们使用audiomanager时,当需要看某种streamtype是否mute时,可以调用isstreammute(int streamtype)
这个方法,但是因为它是@hide的,所以我们就需要引入自己的sdk,才能编译通过。
1. android系统编译时,当编译“include $(build_java_library)”时,会在$android_source_base/out/target/common/obj/java_libraries生成中间文件,当我们需要使用某些类库时,可以从这里面找。
isstreammute(int streamtype)在framework.jar中,我们从out/target/common/obj/java_libraries/framework_intermediates中,将classes.jar拷贝到本地,并重命名为framework.jar。
2. 在eclipse中右键工程->properties->java build path->libraries->add external jar
3. 点击order and export,将framework.jar 置顶
4. 现在,我们就可以使用audiomanager中的isstreammute(int streamtype)方法了
更多关于android相关内容感兴趣的读者可查看本站专题:《android基本组件用法总结》、《android视图view技巧总结》、《android资源操作技巧汇总》、《android操作json格式数据技巧总结》、《android开发入门与进阶教程》、《android编程之activity操作技巧总结》及《android控件用法总结》
希望本文所述对大家android程序设计有所帮助。