Android 添加服务 —— java层服务

Android中的服务比较多,可以说整个Android都是基于C-S架构来工作的,搞清楚每一个服务的核心,如何添加服务,就能快速理解Android的工作机制。

Android的服务主要分为Java Service和Native Service,其中Java Servcie又可以分为 应用层的Service和framework层的service


先说应用层的Service的添加

如果service的客户端和服务端在同一个进程中,那非常简单,在同一个apk中实现一个继承于Service的类,然后在主线程中用startservcie()调用这个service即可。注意,service必须注册在AndroidManifest.xml中

如果servcie的客户端和服务端不在同一个进程中,就稍微复杂一些,需要用到aidl技术

下面有一个简单的例子

客户端进程提供两个数字给服务端,服务端进程负责计算出两个数字之和,并返回给客户端。


先看服务端

服务端中要自己创建一个ICalcServcie.aidl文件,内容如下,该文件中声明的函数,都是后面即将暴露给客户端的函数,aidl写完保存以后,eclipse会自动编译出一个ICalcService.java文件

package com.example.aidldemoservice;
interface ICalcService { 

    int add(int value1, int value2);
}

ICalcServcie.aidl文件中定义的接口的具体实现在CalcService.java中,该类实现了函数的具体逻辑,并且重写了onBind,把mBinder作为返回值。实际上,在客户端调用该服务时,返回给它的就是这个mBinder

package com.example.aidldemoservice;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

public class CalcService extends Service{

	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return mBinder;
	}
	
	private final ICalcService.Stub mBinder = new ICalcService.Stub() {       

		@Override
		public int add(int value1, int value2) throws RemoteException {
			// TODO Auto-generated method stub
			return value1 + value2;
		}  
    };

}

在AndroidMinifest.XML中注册Service

        <service 
            android:name=".CalcService">
            <intent-filter >
                <action android:name="com.example.aidldemoservice.service"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </service>

到此,服务端的任务就完成了,就等着客户端进程来调用了


客户端进程:

客户端代码要包含服务端中的ICalcService.aidl文件,而且包名也要和服务端一样,然后就是客户端的activity的编写了

主要过程如下:

package com.example.aiddemoclient;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.example.aidldemoservice.ICalcService;

public class MainActivity extends ActionBarActivity implements OnClickListener{

	private Button btCalc;
	private TextView tvResult;
	private EditText etValue1;
	private EditText etValue2;
	
	ICalcService mService;
	MyServiceConnection myServiceConnection;
	
	private final class MyServiceConnection implements ServiceConnection {

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			// TODO Auto-generated method stub
			mService = ICalcService.Stub.asInterface((IBinder)service);
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			// TODO Auto-generated method stub
			mService = null;
		}
		
	}
	
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		btCalc = (Button)findViewById(R.id.buttonCalc);
		tvResult = (TextView)findViewById(R.id.result);
		etValue1 = (EditText)findViewById(R.id.value1);
		etValue2 = (EditText)findViewById(R.id.value2);

		btCalc.setOnClickListener(this);
		
		myServiceConnection = new MyServiceConnection();
        Intent intent = new Intent("com.example.aidldemoservice.service");  
        bindService(intent,myServiceConnection,Context.BIND_AUTO_CREATE);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		int v1, v2, res = -1;
        v1 = Integer.parseInt(etValue1.getText().toString());
        v2 = Integer.parseInt(etValue2.getText().toString());                     
                    
        try {
			res = mService.add(v1,v2);
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
                                                                                                                                 
        tvResult.setText(Integer.valueOf(res).toString());
	}
}

重点是要自己实现一个接口ServiceConnection,在这个接口中复写onServiceConnected和onServiceDisconnected,在onServiceConnected中,

mService = ICalcService.Stub.asInterface((IBinder)service);

这句话非常关键,正是它获得了远端的service的bindier,然后,mService才可以调用远端的add方法

res = mService.add(v1,v2);


接着是系统层的service

其实和应用层类似,我们以WindowManagerService(WMS)和PackageManagerService(PMS)为例来分析一下

/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
    static final String TAG = "WindowManager";
    static final boolean DEBUG = false;
    static final boolean DEBUG_ADD_REMOVE = false;
    static final boolean DEBUG_FOCUS = false;
    static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || false;
    static final boolean DEBUG_ANIM = false;
    static final boolean DEBUG_KEYGUARD = false;

/**
 * Keep track of all those .apks everywhere.
 * 
 * This is very central to the platform's security; please run the unit
 * tests whenever making modifications here:
 * 
mmm frameworks/base/tests/AndroidTests
adb install -r -f out/target/product/passion/data/app/AndroidTests.apk
adb shell am instrument -w -e class com.android.unit_tests.PackageManagerTests com.android.unit_tests/android.test.InstrumentationTestRunner
 * 
 * {@hide}
 */
public class PackageManagerService extends IPackageManager.Stub {
    static final String TAG = "PackageManager";
    static final boolean DEBUG_SETTINGS = false;
    static final boolean DEBUG_PREFERRED = false;
    static final boolean DEBUG_UPGRADE = false;
    private static final boolean DEBUG_INSTALL = false;
    private static final boolean DEBUG_REMOVE = false;
    private static final boolean DEBUG_BROADCASTS = false;

可以看出WMS和PMS都是继承与XX.stub类,这个和应用层服务有点儿类似,对了,这里也是用了aidl文件。WMS对应的文间是IWindowManager.aidl,PMS对应的文件是IPackageManager.aidl,作用前面讲过,规定了哪些接口可以暴露给其他进程,WMS和PMS实现了这些接口。

SystemServer.java中

ServiceManager.addService(Context.WINDOW_SERVICE, wm);
PMS.java中

ServiceManager.addService("package", m);
系统的服务通常都是先放到ServiceManager(SMgr)中统一管理的

当其他进程需要使用时,
WindowManagerGlobal.java

    public static IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowManagerService == null) {
                sWindowManagerService = IWindowManager.Stub.asInterface(
                        ServiceManager.getService("window"));
                try {
                    sWindowManagerService = getWindowManagerService();
                    ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
                } catch (RemoteException e) {
                    Log.e(TAG, "Failed to get WindowManagerService, cannot set animator scale", e);
                }
            }
            return sWindowManagerService;
        }
    }

得到WMS远端的binder,传给客户进程使用


ActivityThread.java

    public static IPackageManager getPackageManager() {
        if (sPackageManager != null) {
            //Slog.v("PackageManager", "returning cur default = " + sPackageManager);
            return sPackageManager;
        }
        IBinder b = ServiceManager.getService("package");
        //Slog.v("PackageManager", "default service binder = " + b);
        sPackageManager = IPackageManager.Stub.asInterface(b);
        //Slog.v("PackageManager", "default service = " + sPackageManager);
        return sPackageManager;
    }
得到PMS的binder,传给客户进程使用


客户进程得到对应服务的binder后,就可以使用aidl文件中定义的函数了。


关于Native Service,下篇再说


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值