Android中的service基本知识

在学习安卓的时候我们必不可少的要知道四大组件中的Service。
  service可以在和多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务嘛,总是藏在后头的。
Service是在一段不定的时间运行在后台,不和用户交互应用组件。每个Service必须在manifest中 通过<service>来声明。可以通过contect.startservice和contect.bindserverice来启动。Service和其他的应用组件一样,运行在进程的主线程中。这就是说如果service需要很多耗时或者阻塞的操作,需要在其子线程中实现。service的两种模式(startService()/bindService()不是完全分离的)¬

 它可以启动并运行,直至有人停止了它或它自己停止。在这种方式下,它以调用Context.startService()启动,而以调用Context.stopService()结束。它可以调用Service.stopSelf() 或Service.stopSelfResult()来自己停止。不论调用了多少次startService()方法,你只需要调用一次stopService()来停止服务。用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。远程服务Remote Service 用于android系统内部的应用程序之间。
  它可以通过自己定义并暴露出来的接口进行程序操作。客户端建立一个到服务对象的连接,并通过那个连接来调用服务。连接以调用Context.bindService()方法建立,以调用Context.unbindService()关闭。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。生命周期:   
   使用context.startService() 启动Service是会会经历:
  context.startService()->onCreate()- >onStart()->Service running
  context.stopService() | ->onDestroy() ->Service stop

  如果Service还没有运行,则android先调用onCreate()然后调用onStart();如果Service已经运行,则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次。
可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。
stopService的时候直接onDestroy,如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行。该Service的调用者再启动起来后可以通过stopService关闭Service。
  所以调用startService的生命周期为:onCreate --> onStart(可多次调用) --> onDestroy
  使用使用context.bindService()启动Service会经历:
  context.bindService()->onCreate()->onBind()->Servicerunning


  onUnbind() -> onDestroy() ->Service stop

  onBind将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service运行的状态或其他操作。这个时候把调用者(Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用onUnbind->onDestroy相应退出。
  所以调用bindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory。
  在Service每一次的开启关闭过程中,只有onStart可被多次调用(通过多次startService调用),其他onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。
而启动service,根据onStartCommand的返回值不同,有两个附加的模式:
  1. START_STICKY 用于显示启动和停止service。
  2. START_NOT_STICKY或START_REDELIVER_INTENT用于有命令需要处理时才运行的模式。

  服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可以启动Service,但是它们的使用场合有所不同。
1. 使用startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。
  如果打算采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onStart()方法。
  如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次创建服务,但会导致多次调用onStart()方法。
  采用startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。
  2. 使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。
  onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用。
  采用Context.bindService()方法启动服务时只能调用onUnbind()方法解除调用者与服务解除,服务结束时会调用onDestroy()方法。

    官方文档告诉我们,一个service可以同时start并且bind,在这样的情况,系统会一直保持service的运行状态如果service已经start了或者BIND_AUTO_CREATE标志被设置。如果没有一个条件满足,那么系统将会调用onDestory方法来终止service.所有的清理工作(终止线程,反注册接收器)都在onDestory中完成。拥有service的进程具有较高的优先级

  官方文档告诉我们,Android系统会尽量保持拥有service的进程运行,只要在该service已经被启动(start)或者客户端连接(bindService)到它。当内存不足时,需要保持,拥有service的进程具有较高的优先级。
  1.如果service正在调用onCreate,onStartCommand或者onDestory方法,那么用于当前service的进程则变为前台进程以避免被killed。
  2. 如果当前service已经被启动(start),拥有它的进程则比那些用户可见的进程优先级低一些,但是比那些不可见的进程更重要,这就意味着service一般不会被killed.
  3. 如果客户端已经连接到service (bindService),那么拥有Service的进程则拥有最高的优先级,可以认为service是可见的。
  4. 如果service可以使用startForeground(int,Notification)方法来将service设置为前台状态,那么系统就认为是对用户可见的,并不会在内存不足时killed。
  如果有其他的应用组件作为Service,Activity等运行在相同的进程中,那么将会增加该进程的重要性。
   那么下面我们就通过具体的例子来看看究竟Service是怎么运行的:

目录结构如下:


第一步:编写XML文件如下所示:

本XML文件中采用线性布局有四个按钮,作用分别为:开启服务、关闭服务、绑定服务、解绑定服务

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/btn_start"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="开启服务" />

    <Button
        android:id="@+id/btn_stop"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="关闭服务" />

    <Button
        android:id="@+id/btn_bind"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="绑定服务" />

    <Button
        android:id="@+id/btn_unbind"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="解除绑定服务" />

</LinearLayout>
Java代码如下所示:
第二步:创建一个接口,用于提供获取信息的方法方便服务中的类进行私有化
package com.brucecheng.service;

public interface IService {
	//抽象方法获取系统信息
	public void getApps();
	//抽象方法上传至互联网上
	public void send2Net();
}
第三步:自定义一个服务名字叫MyService
//自定义的服务中重写了生命周期的方法,onCreate()、onStart()、onStartCommand()、onBind()、onUnbind()、onDestory()等方法
package com.brucecheng.service;

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

public class MyServices extends Service {
	//重写Services中的生命周期方法
	@Override
	public void onCreate() {
		System.out.println("Oncreate--------已启动");
		getApp();
		send();
		super.onCreate();
	}
	@Override
	public void onDestroy() {
		System.out.println("OnDestory--------已启动");
		super.onDestroy();
	}
	@SuppressWarnings("deprecation")
	@Override
	public void onStart(Intent intent, int startId) {
		System.out.println("onStart--------已启动");
		super.onStart(intent, startId);
	}
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		System.out.println("onStartCommand--------已启动");
		return super.onStartCommand(intent, flags, startId);
	}
	@Override
	public boolean onUnbind(Intent intent) {
		System.out.println("onUnbind--------已启动");
		return super.onUnbind(intent);
	}
	@Override
	public IBinder onBind(Intent intent) {
		System.out.println("onBind--------已启动");
		return new MyServiceBinder();
	}
	//自定义几个方法
	private void getApp(){
		System.out.println("正在获取系统的信息");
	}
	private void send(){
		System.out.println("正在向互联网上传信息");
	}

	private class MyServiceBinder extends Binder implements IService {
		//本类之所以实现接口IServices是希望本类可以私有化。而不被发现
		//实现接口中的方法,为方便测试,我们只打印一句话
		@Override
		public void getApps() {
			getApp();
		}
		@Override
		public void send2Net() {
			send();
		}
	}
}
第四步:编写MainActivity的方法

package com.brucecheng.service;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener{
	//寻找控件,这四个按钮分别用于开启服务、关闭服务、绑定服务、解绑定服务
	Button btn_start,btn_stop,btn_bind,btn_unbind;
	private MyServiceConnection conn;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		//调用方法进行初始化
		init();
	}
	//自定义一个方法来加载这些控件
	public void init(){
		btn_start=(Button) findViewById(R.id.btn_start);
		btn_stop=(Button) findViewById(R.id.btn_stop);
		btn_bind=(Button) findViewById(R.id.btn_bind);
		btn_unbind=(Button) findViewById(R.id.btn_unbind);
	}
	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		//开启服务
		case R.id.btn_start:
			//开启服务仅执行onCreate onStartcommand onStart
			//多次启动 则执行onStartcommand onStart
			Intent intent=new Intent(this, MyServices.class);
			startService(intent);
			break;
		case R.id.btn_stop:
			Intent intent1 = new Intent(this, MyServices.class);
			stopService(intent1);// onDestroy 多次调用只会执行一次
			break;
		case R.id.btn_bind:
			Intent intent2= new Intent(this, MyServices.class);
			conn = new MyServiceConnection();
			bindService(intent2, conn, 1);//多次调用只执行一次
			break;
		case R.id.btn_unbind:
			try {
				unbindService(conn);
			} catch (Exception e) {
			}
			break;
		}
	}
	@Override
	protected void onDestroy() {
		//解除绑定
		try {
			unbindService(conn);			
		} catch (Exception e) {
		}
		super.onDestroy();
	}
	class MyServiceConnection implements ServiceConnection {

		public void onServiceConnected(ComponentName name, IBinder service) {
			IService binder=(IService)service;
			binder.getApps();
			binder.send2Net();
			System.out.println("服务被绑定了");
		}
		public void onServiceDisconnected(ComponentName name) {
			System.out.println("服务销毁了");
		}
	}
}
注意事项:因为Service也是安卓四大组件之一,毫无疑问。我们需要在在清单文件(Manifest)中进行注册。注册方法很简单:<service android:name=".MyServices"></service>这里name用.表示相对路径,也可以将包名些完整。这样一个完整的服务就创建好了。运行结果如下所示:


1.点击开启服务按钮:
12-06 13:40:49.667: I/System.out(401): Oncreate--------已启动
12-06 13:40:49.667: I/System.out(401): 正在获取系统的信息
12-06 13:40:49.679: I/System.out(401): 正在向互联网上传信息
12-06 13:40:49.679: I/System.out(401): onStartCommand--------已启动
12-06 13:40:49.679: I/System.out(401): onStart--------已启动

2.点击关闭服务按钮:
12-06 13:42:12.787: I/System.out(401): OnDestory--------已启动
3.点击绑定服务按钮:
12-06 13:43:09.317: I/System.out(401): onBind--------已启动
12-06 13:43:09.337: I/System.out(401): 正在获取系统的信息
12-06 13:43:09.337: I/System.out(401): 正在向互联网上传信息
12-06 13:43:09.337: I/System.out(401): 服务被绑定了

4.点击解绑定服务按钮:
12-06 13:44:31.316: I/System.out(401): onUnbind--------已启动
这里注意。当点击开启按钮时如上运行。当多次点击时就会不一样
5.在开启服务之后再次点击开启服务按钮:
12-06 13:47:02.147: I/System.out(401): onStartCommand--------已启动
12-06 13:47:02.147: I/System.out(401): onStart--------已启动
当再次点击时我们发现,不再执行onCreate()方法了

6.在开启服务之后点击绑定之后再次进行绑定:
12-06 13:56:33.127: I/System.out(401): 正在获取系统的信息
12-06 13:56:33.127: I/System.out(401): 正在向互联网上传信息
12-06 13:56:33.127: I/System.out(401): 服务被绑定了

从运行结果可以看到当多次绑定时onBind()方法只执行了一次
7.按下接触绑定之后多次点击接触绑定按钮:
会报错,
下面让我们来总结一下Service工作的基本情况:
当点击开启服务时执行oncreate()--->onstartCommand()----->onstart()
当再次点击开启服务时,执行onstartCommand()----->onstart()
当点击开启服务之后,点击绑定服务时,执行onBind()
再次点击绑定服务时,不再执行onBind(),但是会执行其他相应的代码
点击解绑时,会执行onUnbind()方法,多次点击时会提示错误是不能多次解绑,
注意:
当点击开启服务------>绑定服务------->解除绑定:执行最后会执行onUnbind()方法
当点击绑定服务------>解除绑定:最后会执行onUnbing(),onDestory()方法
这两种启动的方式区别在于,第一种启动方法当点击解除时服务会挂掉同时activity不会销毁,
而第二种方法启动,当点击解除时Activity会执行onDestory()也就是说使用第一种方法可以使activity与服务同步进行交互。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BruceCheng夏夏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值