一个服务是一个应用程序组合,在后台运行,可以执行一个长时间的操作,但是并不提供用户界面。
应用程序终止,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(); } }
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(); } };