专栏首页刘晓杰Android四大组件之一Service

Android四大组件之一Service

Service是能够在后台长期运行并且不提供用户界面的应用程序组件。

Service可以分为以下两种类型:

  1. Started(启动):当Activity通过startService()方法启动服务时,服务处于started状态。一旦启动,就算组件被销毁也不会停止。只有自身调用stopSelf()或者其他组件调用stopService()才停止
  2. Bound(绑定):当Activity通过bindService()方法启动服务时,服务处于bound状态。一个Service可以被多个服务绑定,当它们都解绑时,服务被销毁

Service类中的重要方法

  • onStartCommand():当组件调用startService()时,系统调用该方法。如果开发人员实现该方法,需要调用stopSelf()或stopService()来停止服务
  • onBind():当组件调用bindService()时,系统调用该方法。在该方法的实现中,开发人员必须返回IBinder提供客户端与服务通信的接口,该方法必须实现
  • onCreate():服务第一次创建时调用。在onStartCommand()或onBind()之前
  • onDestory():当服务不再使用时销毁

一、Started Service

1.继承IntentService类

IntentService可以实现如下任务:

  1. 创建区别于主线程的线程来执行发送到onStartCommand()方法的全部Intent
  2. 创建工作队列,每次传递一个Intent到onHandleIntent()
  3. 所有请求处理完毕后停止服务,不必调用stopSelf()
  4. 提供onBind()方法默认实现,返回null
  5. 提供onStartCommand()默认实现,它先发送Intent到工作队列,然后到onHandleIntent()方法实现
public class HelloIntentService extends IntentService {

	public HelloIntentService() {
		super("HelloIntentService");
		// TODO Auto-generated constructor stub
	}

	@Override
	protected void onHandleIntent(Intent arg0) {
		// TODO Auto-generated method stub
		// do something
	}
}

以上就是实现IntentService类所需要的全部操作:无参构造方法和onHandleIntent()方法

如果一定要重写其他回调方法,必须返回默认实现。也就是自动生成的return语句不能改

2.继承Service类

使用IntentService将简化启动服务的实现,但如果要处理多线程,则可以继承Service来处理各个Intent

对于每次启动的请求,它使用工作线程来执行任务,并且每次处理一个请求

public class HelloService extends Service {

	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// TODO Auto-generated method stub
		return START_STICKY;
	}
}

onStartCommand()必须返回一个整数。该值用来描述系统停止服务以后如何继续服务。返回值必须是下列值之一:

  1. START_NO_STICKY:停止服务,不再创建服务
  2. START_STICKY:停止服务,重新创建服务并调用onStartCommand(),但是不重新发送最后的Intent。使用空Intent调用onStartCommand()
  3. START_REDELIVER_INTENT:停止服务,重新创建服务并使用最后的Intent调用onStartCommand()

二、Bound Service

绑定服务是允许其他应用进程绑定并且与之交互的Service类实现类。为了提供绑定,开发人员必须实现onBind()回调方法。该方法返回IBinder对象,它定义了客户端与服务的交互接口

在实现绑定服务时,最重要的是定义onBind()回调方法返回的接口

(1)继承Binder类:继承Binder类创建接口,从onBind()返回一个实例。仅用于私有应用程序

(2)使用Messenger:它是执行IPC最简单的方式

(3)使用AIDL:不推荐。会导致更加复杂的实现

1.继承Binder类

如果服务仅用于本地应用程序并且不必跨进程工作,那么可以实现自己的Binder类来为客户端提供访问的方式

实现步骤如下

  • (1)在服务中创建Binder类实例来完成下列操作之一
    1. 包含客户端能调用的公共方法
    2. 返回当前Service实例,其中包含客户端能调用的方法
    3. 返回服务管理的其他类的实例
  • (2)从onBind()回调方法中返回Binder实例
  • (3)在客户端,从onServiceConnected()接受Binder实例,并且使用提供的方法调用绑定服务

下面举个例子来说明:

CurrentTimeService.java

package com.example.bindertime;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.text.format.Time;

public class CurrentTimeService extends Service {
	public class LocalBinder extends Binder {
		CurrentTimeService getService(){		//返回当前Service实例
			return CurrentTimeService.this;
		}
	}

	private final IBinder binder = new LocalBinder();

	@Override
	public IBinder onBind(Intent intent) {			//返回binder实例,自动生成的
		// TODO Auto-generated method stub
		return binder;
	}

	public String getCurrentTime(){
		Time time = new Time();
		time.setToNow();
		String currentTime = time.format("%Y-%m-%d %H:%M:%S");
		return currentTime;
	}
}

CurrentTimeActivity.java

调用bindService()方法,传递ServiceConnection实现
package com.example.bindertime;

import com.example.bindertime.CurrentTimeService.LocalBinder;
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;
import android.widget.Toast;

public class CurrentTimeActivity extends Activity {
	CurrentTimeService cts;
	boolean bound;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

	@Override
	protected void onStart() {
		// TODO Auto-generated method stub
		super.onStart();
		Button button = (Button)findViewById(R.id.current);
		button.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				Intent intent = new Intent(CurrentTimeActivity.this, CurrentTimeService.class);
				bindService(intent, sc, BIND_AUTO_CREATE);		//调用bindService()方法,传递ServiceConnection实现
				if(bound){
					Toast.makeText(CurrentTimeActivity.this, cts.getCurrentTime(), 
							Toast.LENGTH_SHORT).show();
				}
			}
		});
	}

	@Override
	protected void onStop() {
		// TODO Auto-generated method stub
		super.onStop();
		if(bound){
			bound = false;
			unbindService(sc);
		}
	}
	//实现ServiceConnection,这需要重写onServiceConnected()和onServiceDisconnected()两个回调函数
	private ServiceConnection sc = new ServiceConnection(){
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {		//接受Binder实例
			// TODO Auto-generated method stub
			LocalBinder binder = (LocalBinder)service;
			cts = binder.getService();
			bound = true;
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			// TODO Auto-generated method stub
			bound = false;
		}	
	};
}

2.使用Messenger类

如果需要和远程进程通信,可以使用Messenger来为服务提供接口。

使用Messenger要注意:

  1. 实现Handler的服务因为每次从客户端调用而收到回调
  2. Handler用于创建Messenger对象
  3. Messenger创建IBinder,服务从onBind()方法返回到客户端
  4. 客户端使用IBinder来实例化Messenger,然后使用它来发送Message对象到服务
  5. 服务在Handler的handleMessage()方法接受message

CurrentTimeService.java

package com.example.messengertime;

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.text.format.Time;
import android.widget.Toast;

public class CurrentTimeService extends Service {
	public class IncomingHandler extends Handler {
		@Override
		public void handleMessage(Message msg) {	//服务在Handler的handleMessage()方法接受message
			// TODO Auto-generated method stub
			if(msg.what == CURRENT_TIME){
				Time time = new Time();
				time.setToNow();
				String currentTime = time.format("%Y-%m-%d %H:%M:%S");
				Toast.makeText(CurrentTimeService.this, currentTime, Toast.LENGTH_SHORT).show();
			}else{
				super.handleMessage(msg);
			}
		}
	}

	public static final int CURRENT_TIME = 0;

	@Override //Messenger创建IBinder,服务从onBind()方法返回到客户端
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		Messenger messenger = new Messenger(new IncomingHandler());//Handler用于创建Messenger对象
		return messenger.getBinder();
	}
}

CurrentTimeActivity.java

package com.example.messengertime;

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.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.view.View;
import android.widget.Button;

public class CurrentTimeActivity extends Activity {
	Messenger messenger;
	boolean bound;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

	@Override
	protected void onStart() {
		// TODO Auto-generated method stub
		super.onStart();
		
		Button button = (Button)findViewById(R.id.current);
		button.setOnClickListener(new View.OnClickListener(){
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				Intent intent = new Intent(CurrentTimeActivity.this, CurrentTimeService.class);
				bindService(intent, connection, BIND_AUTO_CREATE);
				if(bound){
					Message message = Message.obtain(null, CurrentTimeService.CURRENT_TIME, 0, 0);
					try {
						messenger.send(message);
					} catch (RemoteException e) {
						e.printStackTrace();
					}
				}
			}
		});
	}

	@Override
	protected void onStop() {
		// TODO Auto-generated method stub
		super.onStop();
		if(bound){
			bound = false;
			unbindService(connection);
		}
	}
	
	private ServiceConnection connection = new ServiceConnection(){
		@Override //客户端使用IBinder来实例化Messenger,然后使用它来发送Message对象到服务
		public void onServiceConnected(ComponentName name, IBinder service) {
			// TODO Auto-generated method stub
			messenger = new Messenger(service);
			bound = true;
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			// TODO Auto-generated method stub
			messenger = null;
			bound = false;
		}
	};
}

3.绑定到服务

如果需要从客户端绑定服务,需要完成如下操作:

  1. 实现ServiceConnection,这需要重写onServiceConnected()和onServiceDisconnected()两个回调函数
  2. 调用bindService()方法,传递ServiceConnection实现
  3. 当系统调用ServiceConnection时,可以使用接口定义的方法回调服务
  4. 调用unbindService()方法解除绑定

三、Service生命周期

可参考这篇文章:service生命周期

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • ContentProvider将程序中的数据暴露给其他程序访问

    之前写过一篇文章,这里写链接内容讲的是如何运用ContentProvider。这次我将来演示一遍如何将程序中的数据暴露给其他程序访问。 就用我之前写过的Ac...

    提莫队长
  • 通过GET方式传递数据给服务器

    自动生成的ServerGET.java中有 @WebServlet(“/ServerGET”) 所以web.xml就不需要配置了

    提莫队长
  • 手把手教你写《雷神》游戏(四)

    游戏排名界面就一个listview 同时我为每个item自定义了view ranklist.xml

    提莫队长
  • [android] 手机卫士接收打电话广播显示号码归属地

    新建一个类OutCallReceiver继承系统的BroadcastReceiver

    陶士涵
  • Android Dependency Injection Libraries

    本文总结并对比了三种Android依赖注入库:Butter Knife、RoboGuice、Android Annotations的使用

    宅男潇涧
  • Android服务之AIDL

    在android开发过程中,为了让其他的应用程序,也可以访问本应用程序的服务,android系统采用远程过程调用来实现。android通过接口来公开定义的服务。...

    水击三千
  • 通过GET方式传递数据给服务器

    自动生成的ServerGET.java中有 @WebServlet(“/ServerGET”) 所以web.xml就不需要配置了

    提莫队长
  • [006]匿名共享内存(Ashmem)的使用

    我们在使用Binder在进程间传递数据的时候,有时候会抛出TransactionTooLargeException这个异常,这个异常的产生是因为Binder驱动...

    王小二
  • Android中ContentProvider的用法

    在Android中,如果要将一个程序的数据共享给另一个程序,在之前的Android版本,我们可以设置Android文件和SharedPreferences操作的...

    指点
  • 『高级篇』docker之开发课程EdgeService(16)

    PS:微服务跟之前说的一样就是互相通过RPC的方式进行通信,之间有自己的数据库,只是RPC暴露接口的方式来获取其他的微服务之间的数据。

    IT故事会

扫码关注云+社区

领取腾讯云代金券