欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android实现在ServiceManager中加入自定义服务的方法详解

程序员文章站 2023-12-10 15:11:58
本文实例讲述了android实现在servicemanager中加入自定义服务的方法。分享给大家供大家参考,具体如下: 当我们要使用android的系统服务时,一般都是使...

本文实例讲述了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

Android实现在ServiceManager中加入自定义服务的方法详解

3. 点击order and export,将framework.jar 置顶

Android实现在ServiceManager中加入自定义服务的方法详解

4. 现在,我们就可以使用audiomanager中的isstreammute(int streamtype)方法了

Android实现在ServiceManager中加入自定义服务的方法详解

更多关于android相关内容感兴趣的读者可查看本站专题:《android基本组件用法总结》、《android视图view技巧总结》、《android资源操作技巧汇总》、《android操作json格式数据技巧总结》、《android开发入门与进阶教程》、《android编程之activity操作技巧总结》及《android控件用法总结

希望本文所述对大家android程序设计有所帮助。