Service(服务)是能够在后台执行长时间运行的操作,并且不提供用户界面的应用程序组件。其他应用程序能启动服务并且切换到另一个应用程序,服务还是可以在后台运行。此外,组件能绑定到服务并与之交互,甚至执行进程间通信(ipc)。
1.Service的分类
2.Service类中的重要方法
3.Service的声明
<service android:enable=["true"|"false"]
android:exported=["true"|"false"]
android:icon="drawable resource"
android:label="string resource"
android:name="string"
android:permission="string"
android:process="string">
</service>
android:enabled
服务运行的进程名称。通常,应用程序的全部组件运行于应用程序创建的默认进程。它与应用程序的包名相同。<applicatoin>标签的process属性能为全部组件设置一个不同的默认值。但是组件能用自己的process属性重写默认值,从而允许应用程序跨越多个进程。
4.创建Started Service
Service和Thread的区别
我们拿服务来进行一个后台长时间的动作,为了不阻塞线程,然而,Thread就可以达到这个效果,为什么我们不直接使用Thread去代替服务呢?(这个问题摘抄至网上,原文地址不是是哪个,所以没写上)
这里提下,
1). Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。
2). Service:Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如:onCreate,onStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。因此请不要把 Service 理解成线程,它跟线程半毛钱的关系都没有!
既然这样,那么我们为什么要用 Service 呢?其实这跟 android 的系统机制有关,我们先拿 Thread 来说。Thread 的运行是独立于 Activity 的,也就是说当一个 Activity 被 finish 之后,如果你没有主动停止 Thread 或者 Thread 里的 run 方法没有执行完毕的话,Thread 也会一直执行。因此这里会出现一个问题:当 Activity 被 finish 之后,你不再持有该 Thread 的引用。另一方面,你没有办法在不同的 Activity 中对同一 Thread 进行控制。
举个例子:如果你的 Thread 需要不停地隔一段时间就要连接服务器做某种同步的话,该 Thread 需要在 Activity 没有start的时候也在运行。这个时候当你 start 一个 Activity 就没有办法在该 Activity 里面控制之前创建的 Thread。因此你便需要创建并启动一个 Service ,在 Service 里面创建、运行并控制该 Thread,这样便解决了该问题(因为任何 Activity 都可以控制同一 Service,而系统也只会创建一个对应 Service 的实例)。
因此你可以把 Service 想象成一种消息服务,而你可以在任何有 Context 的地方调用 Context.startService、Context.stopService、Context.bindService,Context.unbindService,来控制它,你也可以在 Service 里注册 BroadcastReceiver,在其他地方通过发送 broadcast 来控制它,当然这些都是 Thread 做不到的。
4.1 继承IntentService类
public class HelloIntentService extends IntentService {
public HelloIntentService() {
super("HelloIntentService");
// TODO Auto-generated constructor stub
}
@Override
protected void onHandleIntent(Intent intent) {
// TODO Auto-generated method stub
Bundle bundle = intent.getExtras();
String hello = bundle.getString("hello");
Log.v("hello", hello);
}
}
这就是实现IntentService类必须的全部操作,没有参数的构造方法和onHandleIntent()方法。
4.2继承Service类
public class CommonService 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
Bundle bundle = intent.getExtras();
String hello = bundle.getString("hello");
Log.v("hello", hello);
return START_STICKY;
}
}
onStartCommand()方法必须返回一个整数,该值用来描述系统停止服务后如何继续服务(如前所述,IntentService默认实现已经处理了这些,开发人员也可以进行修改)。onStartCommand()方法返回值必须是下面常量之一:
START_NOT_STICKY
如果系统在onStartCommand()方法返回之后杀死这个服务,那么直到接受到新的Intent对象,这个服务才会被重新创建。这是最安全的选项,用来避免在不需要的时候运行你的服务。
START_STICKY
如果系统在onStartCommand()返回后杀死了这个服务,系统就会重新创建这个服务并且调用onStartCommand()方法,但是它不会重新传递最后的Intent对象,系统会用一个null的Intent对象来调用onStartCommand()方法,在这个情况下,除非有一些被发送的Intent对象在等待启动服务。这适用于不执行命令的媒体播放器(或类似的服务),它只是无限期的运行着并等待工作的到来。
START_REDELIVER_INTENT
如果系统在onStartCommand()方法返回后,系统就会重新创建了这个服务,并且用发送给这个服务的最后的Intent对象调用了onStartCommand()方法。任意等待中的Intent对象会依次被发送。这适用于那些应该立即恢复正在执行的工作的服务,如下载文件。
4.3启动服务
Intent intent = new Intent(this,CommonService.class);
Bundle bundle = new Bundle();
bundle.putString("hello", "This is a IntentService");
intent.putExtras(bundle);
startService(intent);
startService方法立即返回,然后Android系统调用服务的onStartCommand方法。如果服务还没有运行,系统首先调用onCreate()方法,接着调用onStartCommand()方法。
protected void onHandleIntent(Intent intent) {
// TODO Auto-generated method stub
Bundle bundle = intent.getExtras();
String hello = bundle.getString("hello");
Log.v("hello", hello);
Intent intent1 = new Intent();
Bundle bundle1 = new Bundle();
bundle1.putString("text", "IntentService");
intent1.putExtras(bundle1);
intent1.setAction("IntentService");
sendBroadcast(intent1);
}
在Activity中注册广播接收器即可:
private BroadcastReceiver receiver = new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Bundle bundle = intent.getExtras();
String text = bundle.getString("text");
tv.setText(text);
}
};
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction("IntentService");
registerReceiver(receiver, filter);
}
4.4停止服务
5.创建BoundService
5.1继承Binder类
public class LocalService extends Service {
private final IBinder binder = new LocalBinder();
private final Random generator = new Random();
public class LocalBinder extends Binder{
LocalService getService(){
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return binder;
}
public int getRandomNumber(){
return generator.nextInt(100);
}
}
下面Activity绑定到LocalService:
public class MainActivity extends Activity {
private LocalService localService;
boolean bound =false;
private Button btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button)findViewById(R.id.button1);
btn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(bound){
int num = localService.getRandomNumber();
Toast.makeText(getApplicationContext(), "获得随机数:"+num, Toast.LENGTH_LONG).show();
}
}
});
}
@Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
Intent intent = new Intent(this,LocalService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
if(bound){
unbindService(connection);
bound = false;
}
}
private ServiceConnection connection = new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
LocalBinder binder = (LocalBinder) service;
localService = binder.getService();
bound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
bound = false;
}
};
}
5.2使用Messenger类
public class MessageService extends Service {
class IncomingHandler extends Handler{
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
switch(msg.what){
case 1 :
Toast.makeText(getApplicationContext(), "Hello World", Toast.LENGTH_LONG).show();
break;
}
}
}
final Messenger messenger = new Messenger(new IncomingHandler());
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "Binding", Toast.LENGTH_LONG).show();
return messenger.getBinder();
}
}
Handler中的handleMessage()方法时服务接收Message对象的地方,并且根据Message类的what成员比那辆决定如何操作。
public class MainActivity extends Activity {
Messenger messenger = null;
boolean bound;
private Button btn;
private ServiceConnection connection = new ServiceConnection(){
@Override
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;
}
};
public void sayHello(){
if(!bound)
return;
Message msg = Message.obtain(null, 1, 0, 0);
try {
messenger.send(msg);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.button1);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
sayHello();
}
});
}
@Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
bindService(new Intent(this,MessageService.class), connection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
if(bound){
unbindService(connection);
bound=false;
}
}
}
5.3绑定到服务
应用程序组件(客户端)能调用bindService()方法绑定到服务。Android系统接下来调用服务的onBind()方法,它返回IBinder来与服务通信。
绑定是异步的。bindService()方法立即返回并且不返回IBinder到客户端。为了接受IBinder,客户端必须创建ServiceConnection实例,然后将其传递给bindService()方法。ServiceConnection包含系统调用发送IBinder的回调方法。
只有Activity,Service和ContentProvider能绑定到服务,BroadcastReceiver不能绑定到服务。
如果需要从客户端绑定服务,需要完成以下操作:
1.实现ServiceConnection,这需要重写onServiceConnected()和onServiceDisconnected()两个回调方法。
2.调用bindService()方法,传递ServiceConnection实现。
3.当系统调用onServiceConnected()回调方法时,就可以使用接口定义的方法调用服务,
4.调用unbindService()方法解绑。
当客户端销毁时,会将其从服务商解绑,但是当与服务完成交互或者Activity暂停时,最好解绑以便系统能计时停止不用的服务。