Service组件用法

Service组件是android系统四大组件之一,通常用来处理一些后台数据交互、逻辑处理等工作,和Activity一个很大的不同在于Service没有自己的交互界面。

对Service的调用是通过intent进行的:

private void startMyService() {
		Intent intent = new Intent(this, MyService.class);
		startService(intent);
	}

上面的代码是通过startService()方法启用服务,还有一种启动服务的方法是bindService(),两种方法启动的服务的生命周期也不同,以下图作简单说明:



startService()会触发Service的onStartCommand()回调函数,android2.0以前回调的是onStart(),为了向下兼容,onStart()被封装在了onStartCommand()方法内。在外部多次调用startService()会多次触发onStartCommand(),直到调用一次stopService()为止,才会结束Service的生命周期。即使在调用stopService()前调用者就退出了,但Service依然会运行下去。


bindService()会触发Service的onBind()回调函数,该函数返回一个IBinder类型的对象给ServiceConnection对象,调用者后续可通过该IBinder对象调用服务提供的接口。绑定的服务会随着调用者的退出而终止。


下面用代码来阐释Service的具体用法:

定义MyService类继承Service:

public class MyService extends Service {
	static final String TAG = "MyService";
	
	public class MyBinder extends Binder {
		public MyBinder() {
			Log.i(TAG, "in customBinder constuctor");
		}
		
		public void myBinderFunc() {
			Log.i(TAG, "MyBinderFunc");
		}
	}
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// TODO Auto-generated method stub
		Log.i(TAG, "onStartCommand");
		return super.onStartCommand(intent, flags, startId);
		
	}

	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		Log.i(TAG, "onBind");
		return new MyBinder();
	}

	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		Log.i(TAG, "on Destroy");
		super.onDestroy();
	}
}

MyService复写了onStartCommand(), onBind(), onDestroy()三种方法,并且定义了MyBinder类,实现了myBinderFunc()方法。

在Activity中启动MyService:

public class MainActivity extends Activity {
	static final String TAG = "MyActivity";
	

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		Button btn = (Button)findViewById(R.id.btn);
		btn.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				bindMyService();				
			}
		});
	}
	
	private void bindMyService() {
		Intent intent = new Intent(this, MyService.class);
		startService(intent);
		
		//bindService(intent, conn, Context.BIND_AUTO_CREATE);
	}
}

运行工程后,可以看到Logcat输出“onStartCommand"提示,说明onStartCommand()函数被调用。通常我们会在该方法中开始数据的处理,但需要注意的是,service是运行在主线程之中的,直接执行耗时的操作会阻塞主线程,因此如果要进行数据下载、大量计算等工作,应该在Service中另起线程进行操作,或者在manifest.xml中指定service组件的process属性,让其属于单独的进程。

如果需要在服务运行的过程中对其施加控制,可以多次调用startService(),在onStartCommand()方法中,对intent中的Bundle对象进行解析来执行相应的操作。但这种方法会使得onStartService()变得臃肿,逻辑和功能代码重叠严重。

解决的办法是通过bindService启动服务,调用者的代码如下:

public class MainActivity extends Activity {
	static final String TAG = "MyActivity";
	

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		Button btn = (Button)findViewById(R.id.btn);
		btn.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				bindMyService();
				
				
			}
		});
	}
	

	MyBinder myBinder;
	private ServiceConnection conn = new ServiceConnection() {

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			// TODO Auto-generated method stub
			
			iService = IStockQuoteService.Stub.asInterface(service);
			myBinder = (MyBinder)service;
			
			myBinder.MyBinderFunc();	
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			// TODO Auto-generated method stub
			Log.i(TAG, "release service");
		}
		
	};

	private void bindMyService() {
		Intent intent = new Intent(this, MyService.class);
		//startService(intent);
		
		bindService(intent, conn, Context.BIND_AUTO_CREATE);
	}
}


这里调用bindService()方法而非startService()方法,传入的参数包括intent,服务连接对象conn和flag。这将导致Service的onBind()方法被调用,一旦onBind()返回,将触发conn的onServiceConnected()方法,方法中的IBinder参数就是onBind()的返回值。在我们的MyService中,返回的是一个MyBinder对象。

conn的onServiceConnected()方法回调后,把IBinder对象保存到本地的MyBinder变量里,调用者之后就可以通过该变量控制服务的运行。


这里的细节在于,Service必须自己定义Binder子类,并且实现相关方法,再由onBind()方法回传。调用者需要在ServiceConnection.onServiceConnected()方法中获取Binder,然后进行相关处理。细心的人可能已经发现,我们定义的是Binder的子类,而onBind()返回值以及onServiceConnected()参数的类型都是IBinder,到底是Binder还是IBinder?事实上,IBinder只是一个接口,具体实现则是在Binder中,因此我们定义的是包含具体实现的Binder子类,否则我们需要自己再把IBinder的所有接口都再实现一遍……至于回传的是IBinder类型的参数,则是android系统设计如此,因为java基础不是很好,不太清楚interface和class在传递上的区别,就不作分析了。不过还是猜想一下,可能跟跨进程调用的实现有关。


提到了跨进程调用,本来想再记述一下有关AIDL的理解,但查阅了相关资料发现先前的理解还是太浅薄,改日再专门写AIDL吧。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值