一个服务是一个应用程序组合,在后台运行,可以执行一个长时间的操作,但是并不提供用户界面。
应用程序终止,Service也不会终止。。。。每个Service必须在manifest中 通过<service>来声明。可以通过contect.startservice和contect.bindserverice来启动。。 Service和其他的应用组件一样,运行在进程的主线程中。这就是说如果service需要很多耗时或者阻塞的操作,需要在其子线程中实现。
service的两种模式(startService()/bindService()不是完全分离的):
本地服务 Local Service 用于应用程序内部。
它可以启动并运行,直至有人停止了它或它自己停止。在这种方式下,它以调用Context.startService()启动,而以调用Context.stopService()结束。它可以调用Service.stopSelf() 或 Service.stopSelfResult()来自己停止。不论调用了多少次startService()方法,你只需要调用一次stopService()来停止服。用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。
远程服务 Remote Service 用于android系统内部的应用程序之间。
它可以通过自己定义并暴露出来的接口进行程序操作。客户端建立一个到服务对象的连接,并通过那个连接来调用服务。连接以调用Context.bindService()方法建立,以调用 Context.unbindService()关闭。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。
两种Service方式启动服务的主要区别
1、startService()方式启动。
使用startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。
如果打算采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onStart()方法(在2.0之后已经改变onStartCommond()方法)。
如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次创建服务,但会导致多次调用onStart()方法。
采用startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。或者自己停止。
2、bindService()方式启动;(异步)
调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。
onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用
采用Context.bindService()方法启动服务时只能调用onUnbind()方法解除调用者与服务解除,服务结束时会调用onDestroy()方法
Service生命周期:(如图,不做介绍)
拥有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等运行在相同的进程中,那么将会增加该进程的重要性。
分析onStartCommand方法参数的作用和返回值的作用:
1、根据这个方法的返回值不同可以有两种启动模式START_NOT_STICKY,START_STICKY,(当进行被杀死的时候,是否重新启动。如果是参数:START_REDELIVER_INTENT表示当服务所在进程被杀死后,重新启动,并且重新传递Intent内容,其它两个参数不会重新传递intent,都为null)
2、返回START_REDELIVER_INTENT的时候,如果不论启动多少次,当重新启动的时候,也会启动多少次。
3、是当前服务的标记
4、第三个参数startId表示当前启动的Service的次数。
下面看一下测试源码:
HelloSerivce.java
public class HelloService extends Service {
Handler handler = new Handler();
private final IBinder mBinder = new HelloBinder();
@Override
public void onCreate() {
Log.v("verbose", "onCreate");
super.onCreate();
}
/**
* 用这种方式 ,从Activity启动服务之后,在后台运行的,之后就没有与Activity联系了 如果有bind方法
* ,在整个过程中与Activity进行通信
*
* 根据这个方法的返回值不同可以有两种启动模式START_NOT_STICKY,START_STICKY,
* START_REDELIVER_INTENT服务被系统杀死后是否自动重启,和是否重新传递intent。
* 如果被杀死之后重新启动服务,会重新调用onCreate,和onStartCommand方法
* ,但是重新调用onStartCommand的时候,不会再次传递参数。。
* 返回START_REDELIVER_INTENT的时候,如果不论启动多少次,当重新启动的时候,也会启动多少次。
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v("verbose", "onStartComand");
handler.post(new Runnable() {// 用通常用Handler线程跟UI线程打交到
@Override
public void run() {
Toast.makeText(getApplicationContext(), "启动服务",
Toast.LENGTH_LONG).show();
}
});
// return super.onStartCommand(intent, flags, startId);
return START_REDELIVER_INTENT;
}
@Override
public void onDestroy() {
Log.v("verbose", "onDestory");
handler.post(new Runnable() {// 用通常用Handler线程跟UI线程打交到
@Override
public void run() {
Toast.makeText(getApplicationContext(), "停止服务",
Toast.LENGTH_LONG).show();
}
});
super.onDestroy();
}
/**
* 这个方法是必须执行的,当用bind方法启动Service的时候,是有用的。
*/
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return mBinder;
}
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class HelloBinder extends Binder {
HelloService getService() {
return HelloService.this;
}
}
public void showNumber(){
new Thread(new Runnable() {
int i=1;
@Override
public void run() {
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i++);
}
}
}).start();
}
}
HelloServiceActivity.java
package hb.android.service;
import hb.android.service.HelloService.HelloBinder;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
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.TextView;
public class HelloServiceActivity extends Activity {
Intent intent;
boolean flag = true;
HelloService mService;;
boolean mBound = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
intent = new Intent();
initMyWidget();
setMyWidgetListener();
}
public void setMyWidgetListener() {
MyWidget.btn_bind.setOnClickListener(new WidgetOnClickListener());
MyWidget.btn_start.setOnClickListener(new WidgetOnClickListener());
MyWidget.btn_stop.setOnClickListener(new WidgetOnClickListener());
MyWidget.btn_unbind.setOnClickListener(new WidgetOnClickListener());
MyWidget.btn_kill.setOnClickListener(new WidgetOnClickListener());
}
class WidgetOnClickListener implements OnClickListener {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_start:
intent.setClass(getApplicationContext(), HelloService.class);
intent.putExtra("test", "start");
startService(intent);
flag = true;
MyWidget.btn_stop.setEnabled(flag);
break;
case R.id.btn_stop:
intent.putExtra("test", "stop");
stopService(intent);
flag = false;
MyWidget.btn_stop.setEnabled(flag);
break;
case R.id.btn_kill:
android.os.Process.killProcess(android.os.Process.myPid());
break;
case R.id.btn_bind:
Intent intent = new Intent(getApplicationContext(), HelloService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);//自动调用Service里的onCreate方法
System.out.println("bind:"+mService);
opeService();
break;
case R.id.btn_unbind:
if (mBound) {
unbindService(mConnection);//自动调用Service的onDestory方法
mBound = false;
}
break;
default:
break;
}
}
public void opeService() {
System.out.println("opeService:"+mService);
// mService.showNumber();
}
}
public void initMyWidget() {
MyWidget.btn_bind = (Button) findViewById(R.id.btn_bind);
MyWidget.btn_start = (Button) findViewById(R.id.btn_start);
MyWidget.btn_stop = (Button) findViewById(R.id.btn_stop);
MyWidget.btn_unbind = (Button) findViewById(R.id.btn_unbind);
MyWidget.tv_test = (TextView) findViewById(R.id.tv_test);
MyWidget.btn_kill = (Button) findViewById(R.id.btn_kill);
}
private static class MyWidget {
static Button btn_start;
static Button btn_stop;
static Button btn_bind;
static Button btn_unbind;
static Button btn_kill;
@SuppressWarnings("unused")
static TextView tv_test;
}
@Override
protected void onDestroy() {
super.onDestroy();
stopService(intent);
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
HelloBinder binder = (HelloBinder) service;
mService = binder.getService();
System.out.println("ServiceConnection:"+mService);
mBound = true;
mService.showNumber();
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
@Override
protected void onStop() {
super.onStop();
if (mBound) {
unbindService(mConnection);
mBound = false;
}
};
}
注意:当服务创建之后由,onServiceConnected 这个方法负责建立与Servicer的连接
意思当Activit用BindService启动服务之后,由:
public ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
System.out.println("onServiceConnected");
mBound = false;
}
/**
* 服务创建之后收些方法建立Serivce与Activity的连接
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
System.out.println("onServiceDisconnected");
mBound = true;
LocalBinder myBinder = (LocalBinder) service;
myService = myBinder.getService(); //在下面就可以对service进行操作了。
myService.showNumber();
}
};
对所绑定的Service进行控制(连接与销毁)