Android四大组件之Service

今天我们来说Service。正如书中所说Service组件也是可执行程序,他有自己的声明周期。创建,配置Service与创建配置Activity的过程基本相似。

这里我们总结一下:

1). 被启动的服务的生命周期:如果一个Service被某个Activity 调用 Context.startService 方法启动,那么不管是否有Activity使用bindService绑定或unbindService解除绑定到该Service,该Service都在后台运行。如果一个Service被startService 方法多次启动,那么onCreate方法只会调用一次,onStart将会被调用多次(对应调用startService的次数),并且系统只会创建Service的一个实例(因此你应该知道只需要一次stopService调用)。该Service将会一直在后台运行,而不管对应程序的Activity是否在运行,直到被调用stopService,或自身的stopSelf方法。当然如果系统资源不足,android系统也可能结束服务。

2). 被绑定的服务的生命周期:如果一个Service被某个Activity 调用 Context.bindService 方法绑定启动,不管调用 bindService 调用几次,onCreate方法都只会调用一次,同时onStart方法始终不会被调用。当连接建立之后,Service将会一直运行,除非调用Context.unbindService 断开连接或者之前调用bindService 的 Context 不存在了(如Activity被finish的时候),系统将会自动停止Service,对应onDestroy将被调用。

3). 被启动又被绑定的服务的生命周期:如果一个Service又被启动又被绑定,则该Service将会一直在后台运行。并且不管如何调用,onCreate始终只会调用一次,对应startService调用多少次,Service的onStart便会调用多少次。调用unbindService将不会停止Service,而必须调用 stopService 或 Service的 stopSelf 来停止服务。

4). 当服务被停止时清除服务:当一个Service被终止(1、调用stopService;2、调用stopSelf;3、不再有绑定的连接(没有被启动))时,onDestroy方法将会被调用,在这里你应当做一些清除工作,如停止在Service中创建并运行的线程。

特别注意:

1、你应当知道在调用 bindService 绑定到Service的时候,你就应当保证在某处调用 unbindService 解除绑定(尽管 Activity 被 finish 的时候绑定会自动解除,并且Service会自动停止);

2、你应当注意 使用 startService 启动服务之后,一定要使用 stopService停止服务,不管你是否使用bindService;

3、同时使用 startService 与 bindService 要注意到,Service 的终止,需要unbindService与stopService同时调用,才能终止 Service,不管 startService 与 bindService 的调用顺序,如果先调用 unbindService 此时服务不会自动终止,再调用 stopService 之后服务才会停止,如果先调用 stopService 此时服务也不会终止,而再调用 unbindService 或者 之前调用 bindService 的 Context 不存在了(如Activity 被 finish 的时候)之后服务才会自动停止;

4、当在旋转手机屏幕的时候,当手机屏幕在“横”“竖”变换时,此时如果你的 Activity 如果会自动旋转的话,旋转其实是 Activity 的重新创建,因此旋转之前的使用 bindService 建立的连接便会断开(Context 不存在了),对应服务的生命周期与上述相同。

5、在 sdk 2.0 及其以后的版本中,对应的 onStart 已经被否决变为了 onStartCommand,不过之前的 onStart 任然有效。这意味着,如果你开发的应用程序用的 sdk 为 2.0 及其以后的版本,那么你应当使用 onStartCommand 而不是 onStart。

生命周期方法说明

onStartCommand()
当另一个组件(如 Activity)通过调用 startService() 请求启动服务时,系统将调用此方法。一旦执行此方法,服务即会启动并可在后台无限期运行。 如果您实现此方法,则在服务工作完成后,需要由您通过调用 stopSelf() 或 stopService() 来停止服务。(如果您只想提供绑定,则无需实现此方法。)

onBind()
当另一个组件想通过调用 bindService() 与服务绑定(例如执行 RPC)时,系统将调用此方法。在此方法的实现中,您必须通过返回 IBinder 提供一个接口,供客户端用来与服务进行通信。请务必实现此方法,但如果您并不希望允许绑定,则应返回 null。

onCreate()
首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或 onBind() 之前)。如果服务已在运行,则不会调用此方法。

onDestroy()
当服务不再使用且将被销毁时,系统将调用此方法。服务应该实现此方法来清理所有资源,如线程、注册的侦听器、接收器等。 这是服务接收的最后一个调用。

下面我们来详细介绍Android Service的开发。

开发步骤:

                1:定义一个Service的子类。

                2:在AndroidManifest.xml文件配置该Service。

Service组件生命周期方法:

                1:IBinder onBind(Intent intent):该方法是Service子类必须实现的方法。该方法返回一个IBinder对象,应用程序可通过该对象与Service组件通信。

                2:void onCreate():当该Service第一次被创建后将立即回调该方法。

                3:void onDestroy():当该Service被关闭之前将会回调该方法。

                4:void onStartCommand(Intent intent ,int flags, int startId):该方法的早期版本是void onStart(Intent intent,int startId),每次客户端调用startService(Intent)方法启动该Service时都会回调该方法。

                5:boolean onUnbind(Intent intent):当该Service上绑定的所有客户端都断开连接时将会回调该方法。

                举例:定义一个Service组件

                           

public class MService extends Service{

	//必须实现的方法
	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}
	//Service被创建时回调该方法
	@Override
	public void onCreate() {
		super.onCreate();
		System.out.println("Service is createed!");
	}
	//Service被启动时回调该方法
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		System.out.println("Service is started!");
		return START_STICKY;
	}
	//Service被关闭之前回调
	@Override
	public void onDestroy() {
		super.onDestroy();
		System.out.println("Service is destroyed!");
	}

}

以上 代码就是Service组件的框架,若希望该Service做些什么可以在onCreate()或onStartCommand()方法中定义相关代码。

 

下面我们还要在AndroidManifest.xml中配置该Service:

 

        <service android:name=".MService" >
            <intent-filter>
                <!-- 为该Service组件的intent-filter配置action -->
                <action android:name="com.xiyou.service.M_SERVICE" />
            </intent-filter>
        </service>

Service已经开发完了,下面我们要做的就是如何在Android中启动Service:

 

                   1:通过Context的startService()方法:使用该方法启动Service,访问者与Service之间没有关联,及时访问者退出了,Service仍然运行。

                   2:通过Content的bindService()方法:使用该方法启动Service,访问者与Service绑定在一起,访问者一旦退出,Service也就停止了。

下面我们开发一个启动Service的类:

 

public class MainActivity extends Activity {

	private Button start, stop;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		start = (Button) findViewById(R.id.button1);
		stop = (Button) findViewById(R.id.button2);
		final Intent intent = new Intent();
		intent.setAction("com.xiyou.service.M_SERVICE");//为Intent设置Action属性
		start.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				startService(intent);//启动指定Service

			}
		});
		stop.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				stopService(intent);//停止指定Service

			}
		});
	}

}

LogCat输出:

 


由此可看出每次Service创建都会调用onCreate()方法,每次Service被启动都会调用onStartCommand()方法,但是多次启动Service却不会每次都调用onCreate()方法。

 

绑定本地Service并与之通信:

使用startService()和stopService()启动,关闭Service时,Service不能与访问者进行通信,数据交换。

而如果使用bindService()和unbindService()方法启动,关闭Service,Service就可以和访问者之间进行方法调用和数据交换。

Context的bindService()方法的完整方法签名为:bindService(Intent service,ServiceConnection conn,int flags);

                1:service:该方法通过Intent指定要启动的Service。

                2:conn:该参数是一个ServiceConnection对象,该对象用于监听访问者与Service对象之间的连接情况。当访问者与Service之间连接成功时将回调该   ServiceConnection对象的onServiceConnection(ComponentName name,IBinder service)方法,当Service所在的宿主进程由于异常中断或由于其它           原因终止,导致该Service与访问者之间断开连接时回调该ServiceConnection对象的onServiceDisconnected(ComponentName name)方法。

                3:flags:指定绑定时是否自动创建Service(如果Service还未创建)。该参数可指定为0(不自动创建)或BIND_AUTO_CREATE(自动创建)。

注:ServiceConnection对象的onServiceConnection方法中有一个IBinder对象,该对象即可实现与被绑定Service之间的通信。

注:当调用者主动通过unBindService()方法断开与Service的连接时,ServiceConnection对象的onServiceDisconnected(ComponentName name)方法并不会被调用。

 

public class BindService extends Service {

	private int count;
	private boolean quit;

	// 定义onBinder方法所返回的对象
	private MyBinder binder = new MyBinder();

	// 通过继承Binder来实现IBinder类。
	public class MyBinder extends Binder {
		public int getCount() {
			// 获取Service的运行状态:count
			return count;
		}
	}

	@Override
	public IBinder onBind(Intent intent) {
		System.out.println("Service is Binded");
		// 返回IBinder对象
		return binder;
	}

	// Service被创建时回调该方法
	@Override
	public void onCreate() {
		super.onCreate();
		System.out.println("Service is created");
		// 启动一条线程,动态的修改count状态值
		new Thread() {
			public void run() {
				while (!quit) {
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					count++;
				}
			};
		}.start();
	}

	// Service被断开连接时回调该方法
	@Override
	public boolean onUnbind(Intent intent) {

		System.out.println("Service is unbinded");
		return true;
	}

	// Service被关闭之前回调该方法
	@Override
	public void onDestroy() {

		this.quit = true;
		System.out.println("Service is destroyed");

	}

}


再写一个Activity用于绑定Service:

 

 

public class BindServiceTest extends Activity {

	Button bind, unbind, getServiceStatus;
	// 保持所启动的Service的IBinder对象
	BindService.MyBinder binder;
	// 定义一个ServiceConnection对象
	private ServiceConnection conn = new ServiceConnection() {
		// 当Activity与service断开连接时回调该方法
		@Override
		public void onServiceDisconnected(ComponentName name) {

			System.out.println("service disconnected");
		}

		// 当Activity与service连接成功时回调该方法
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			// TODO Auto-generated method stub

			System.out.println("service connected");
			binder = (MyBinder) service;

		}
	};

	public void onCreate(android.os.Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		bind = (Button) findViewById(R.id.button1);
		unbind = (Button) findViewById(R.id.button2);
		getServiceStatus = (Button) findViewById(R.id.button3);
		final Intent intent = new Intent();
		intent.setAction("com.xiyou.service.BIND_SERVICE");
		bind.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				// 绑定指定service
				bindService(intent, conn, Service.BIND_AUTO_CREATE);

			}
		});
		unbind.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				// 解除绑定指定service

				unbindService(conn);
			}
		});
		getServiceStatus.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				// 获取并显示,service的count值
				Toast.makeText(BindServiceTest.this,
						"Service的count值为:" + binder.getCount(),
						Toast.LENGTH_LONG).show();
				System.out.println("Service的count值为:" + binder.getCount());
			}
		});
	};
}

运行结果:

 

注:不论点击多少次 bind都只会绑定一次,回调一次onBind()方法。

 

下面我们再来介绍一种可以在其中处理耗时任务的Service:IntentService。

IntentService的特性:

                           1:IntentService使用队列来管理请求中的Intent,每当客户端通过Intent启动IntentService,都将这个Intent放到队列中;

                           2:IntentService创建单独的线程来处理所有的Intent。

                           3:IntentService创建单独的线程来处理onHandleIntent()方法实现的代码。

                           4:当所有Intent请求处理完毕,IntentService会自动停止,所以不用调用stop。

                           5:IntentService中的onBind()方法提供了默认实现,默认return null;

                           6:IntentService中的onStartCommand()方法提供了默认实现,该实现会将Intent添加到队列中。

                           

public class MyIntentService extends IntentService {

	public MyIntentService(String name) {
		super(name);
	}

	// IntentService会使用单独的线程来执行该方法的代码。
	@Override
	protected void onHandleIntent(Intent intent) {
		// 该方法内可以进行耗时任务
		long endTime = System.currentTimeMillis() + 20 * 1000;
		System.out.println("on Start");
		while (System.currentTimeMillis() < endTime) {
			synchronized (this) {
				try {
					wait(endTime - System.currentTimeMillis());
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		System.out.println("耗时任务完成。");
	}

}

 

跨进程调用Service(AIDL Service):

                        功能:用于实现Android中跨进程通信,数据交换。

                        区别:本地Service是将onBind()返回的IBinder本身传递给客户端的ServiceConnection的onServiceConnection()的第二个参数,但是远程Service是将onBind()返回的IBinder对象的代理传给客户端ServiceConnection的onServiceConnection()的第二个参数。

 

实现AIDLService需要定义远程接口,客户端通过这个接口进行数据交换:

 

 interface ICat{
 
    String getColor();
    double getWeight();
 }

注:AIDL定义的接口源代码后缀是.aidl。如图

 

注:gen文件夹中的ICat.java是ADT自动生成的,在Android SDK安装目录下的platform-tools子目录下的aidl.exe为该接口提供实现。
 

Service类代码:

public class AidlService extends Service{

	private String color;
	private double weight;
	private CatBinder  catBinder;
	Timer timer = new Timer();
	String[] colors  = new String[]{"red","black","yellow"};
	double[] weights = new double[]{2.5,5.7,4.5};
	
	
	//继承实现ICat接口,并实现IBinder接口
	public class CatBinder extends Stub{

		@Override
		public String getColor() throws RemoteException {
			return color;
		}

		@Override
		public double getWeight() throws RemoteException {
			return weight;
		}
		
	}
	@Override
	public void onCreate() {
		super.onCreate();
		catBinder = new CatBinder();
		timer.schedule(new TimerTask() {
			
			@Override
			public void run() {
				// 随机改变color和weight
				int rand = (int)(Math.random()*3);
				color = colors[rand];
				weight = weights[rand];
			}
		}, 0, 600);
	}
	@Override
	public IBinder onBind(Intent intent) {
		/**
		 * 返回catBinder对象,即IBinder对象,因为Stub实现了IBinder接口
		 * 
		 */
		return catBinder;
	}
	@Override
	public void onDestroy() {
		super.onDestroy();
		timer.cancel();
	}

}

 

  客户端访问AIDLService:                       

 

public class AidlServiceTest extends Activity {

	private ICat catService;
	private Button get;
	public ServiceConnection serviceConnection = new ServiceConnection() {

		@Override
		public void onServiceDisconnected(ComponentName name) {
			catService = null;
		}

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {

			//实现接收service传过来的对象的代理。
			catService = ICat.Stub.asInterface(service);
		}
	};

	public void onCreate(android.os.Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		get = (Button) findViewById(R.id.button1);
		Intent intent = new Intent();
		intent.setAction("com.example.aidlservice.AIDL_SERVICE");
		bindService(intent, serviceConnection, BIND_AUTO_CREATE);
		get.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
			try {
				System.out.println("color:"+catService.getColor());
				System.out.println("weight:"+catService.getWeight());
			} catch (RemoteException e) {
				e.printStackTrace();
			}	
			}
		});

	};
	@Override
	protected void onDestroy() {
		super.onDestroy();
		this.unbindService(serviceConnection);
	}

}

文件夹结构,在客户端的代码中也需要ICat.aidl文件接口。

 

注:客户端ICat.aidl的文件夹要和Service端的ICat.aidl的文件夹名字一样。否则报

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值