您的位置:华清远见教育科技集团 >> Android资料 >> 详解Android Service组件  
 
详解Android Service组件
分享到:

上文我们介绍的是Android应用组件Activity,Activity是与用户直接交互UI组件,今天给大家介绍的服务(Services)组件则通常运行在后台,对用户而言不具有可视性,守护进程和硬件服务、原生服务等多是服务组件。

与其他组件一样,服务组件通常运行在应用的主线程中,如果服务组件对时间片等资源消耗较大,通常会将服务组件放置在一个单独的线程中运行,以防阻塞UI线程即主线程,影响用户体验。

通过Context.startService()方法可以启动服务,通过Context.bindService()方法可以绑定服务。通过Context.stopService()方法可以停止服务。另外服务本身也可以通过Context.stopSelf()方法自行终止。在实际实现中,为了绑定服务,必须指定一个服务连接(ServiceConnection),具体如下:

public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        ……
        getApplicationContext().bindService(new Intent(this,PowerManagerService.class), mConnection, BIND_AUTO_CREATE);
        …….
    }

其中mConnection即是ServiceConnection的一个实例,BIND_AUTO_CREATE指明了连接的类型,表明如果服务没有创建,自动创建服务。默认情况下,可以通过调用组件的上下文绑定或者解绑服务,但是在同一个应用中如果需多次绑定服务时,需要整体通过应用上下文(getApplicationContext())的方式实现。

在调用组件被销毁时,服务必须解绑,否则会造成引用计数上的错误,造成服务泄漏,解绑服务的实现如下:

protected void onDestroy()
    {
        getApplicationContext().unbindService(mConnection);
        super.onDestroy();
    }

服务连接的实现如下:

private ServiceConnection mConnection = new ServiceConnection()
    {
        public void onServiceConnected(ComponentName name, IBinder service)
        {
            // TODO Auto-generated method stub
            Log.d(TAG, "===onServiceConnected==");
            mPowerManager = ((PowerManagerService.LocalBinder)service).getService();
            initLayout();
        }
        public void onServiceDisconnected(ComponentName name)
        {
            // TODO Auto-generated method stub
            mPowerManager = null;
        }
    };

需要说明的是,由于服务的连接是异构的,必须保证服务的实例在服务绑定成功后使用。如果在bindService()执行后立即使用,会引发NullPointerException异常。

通过在AndroidManifest.xml文件中声明“service”元素,应用程序可以全权接入相应的服务。当该服务允许被外部应用调用时,需要将服务的“android:exported”属性设为“true”。其默认值为“false”。如果希望在设置应用中查看服务时,多看到的服务图标与定义该服务的应用图标有所区别,则应设置服务的“android:icon”属性。否则看到的服务图标即定义该服务的应用图标。服务的声明如下:

< service android:name=".MiscService"
        android:label="Playground Service"
        android:exported="true"
        android:process=":rpcperfservice" /> //运行在不同的进程中

为了接入对于被权限保护的服务,通过在AndroidManifest.xml文件中声明相应服务的权限,才可以启动、终止、绑定相应的服务。如为了改变网络状态,需要声明权限:

< uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>

系统级的权限在frameworks/base/core/res/AndroidManifest.xml中定义。

后,在服务的创建、启动、销毁阶段,服务驻留的进程会处于前台进程状态,以免服务出现不可预料的异常。需要说明的是,当系统内存严重紧张时,系统可能会重启甚至销毁服务。

服务根据驻留的对象不同可以分为本地服务(Local Services)和远程服务(Romate Services)。就笔者而言,一般将远程服务分为应用级远程服务和系统级远程服务两种。系统级的服务实现颇为复杂。除了定义服务本身外,还需要定义被上层应用调用的接口。一般通过AIDL调用。而应用级远程服务除了AIDL外,Android还提供了较为简单的Message方式的调用。但如果实现的服务希望被其他应用调用,则必须通过AIDL进行。

在具体的实现中,为了调用驻留在其他应用下的远程服务,需要将该远程服务的I*.java接口拷贝到调用的工程中,如对于com.miaozl.test.TestService服务,需要将com. miaozl.test.ITestService拷贝到调用远程服务的其他工程的“src”目录下,绑定的方法为:

Intent serviceIntent = new Intent();
    serviceIntent.setComponent(new ComponentName("com.lingpan.test","com.lingpan.test.TestService"));
    bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
    mConnection的实现如下:
    private ServiceConnection mConnection = new ServiceConnection()
    {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service)
        {
            // TODO Auto-generated method stub
            ITestService test = ITestService.Stub.asInterface(service);
            try {
                test.setTest(); //调用远程服务的方法
            } catch (RemoteException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        @Override
        public void onServiceDisconnected(ComponentName name)
        {
            // TODO Auto-generated method stub
        }
    };

至于本地服务和应用级的远程服务的具体实现,android的帮助文档和示例代码中已经有明确的说明,在本文中就不再详述。

至于系统级的远程服务,对于应用开发者而言,大可不必理会,只有在担任整个系统的架构任务时才会涉及,服务的实现可以参考UiModeManagerService.java来进行,服务对应用层的接口的实现可以参考UiModeManager.java来进行,为了通过getSystemService()方法调用自定义的方法,需要在ContextImpl.java中构建系统服务对应用层的接口的单子模式实例。

 更多相关文章

·Android应用组件Activity
·Android RPC管道文件系统
·Android RPC远程调用
·SMSM状态通信处理过程
·SMD 数据通信的实现