1.Service概述
Service服务是一个没有用户界面的在后台运行执行操作的应用组件,其它组件可以通过Intent意图启动这个Service去完成特定的功能,比如通过Service可以完成播放音乐等后台操作,且每个Service必须在manifest中 通过<service>来声明配置。每个service运行在宿主线程上,因此,访问网络读取Sdcard等耗时操作需要放在工作线程中!Android系统有五种进程Foreground
Process(比如Activity处于resumed状态),Visible Process(比如activity处于paused状态),Service Process,Background Process(比如activity处于stopped状态),Empty Process,service处于第三级,后台的Activiy处于第四等级,后台运行的进程被杀死的概率比service大。
2.Service的启动方式
(1).startService()
// 1.startService开启 public void start(View view) { //显示意图或者使用隐式意图找到Service对象 Intent intent = new Intent(this, TestService.class); startService(intent); }
(2).bindService()绑定服务
// 2.bindService绑定服务 public void bind(View view) { Intent intent = new Intent(this, TestService.class); conn = new MyServiceConn(); bindService(intent, conn, Context.BIND_AUTO_CREATE); } class MyServiceConn implements ServiceConnection { /* * Service服务返回一个IBinder对象,该onServiceConnected函数将接受该IBinder对象 */ @Override public void onServiceConnected(ComponentName name, IBinder service) { System.out.println("得到binder对象"); binder = (IMyBinder) service; } /* * 一般不会被调用, 只有在Service被破坏了或者被杀死的时候调用. * 例如, 系统资源不足, 要关闭一些Services, 刚好连接绑定的 Service 是被关闭者之一, 这个时候onServiceDisconnected() 就会被调用。 */ @Override public void onServiceDisconnected(ComponentName name) { } }
(3).两种启动方式的区别
可以多次启动同一服务,但只能一次终止该服务。两种启动方式对应服务的生命周期不调,bindService可以得到Binder代理对象。
通过startService方式启动的服务,在退出当前activity时,service服务仍然存在,但无法操作服务内部方法;
通过bindService可以得到Binder对象,间接调用服务内部方法,但在用户退出当前该Activity时,服务终止。
结合以上两种优点,结论:
Activity使用startService启动服务(延长该服务的生命周期),再使用bindService()(服务已存在,但为得到Binder代理对象),再定义一个接口用于暴露MyBinder代理对象的方法,自定义MyBinder类(继承Binder实现接口),在服务的onBind()中返回MyBinder的实例化对象,Activity中ServiceConnection子类实例化对象的onServiceConnected()接收该Binder对象,再将该Binder对象强转为接口类型。通过调用Binder对象方法,达到在Binder对象内部操作服务方法。
更多Activity调用服务方法,请看下面源代码!
3.Service的生命周期
(1).startService启动方式的生命周期
1).context.startService() 当前activity调用startService()方法
2).service.onCreate() 当前服务如果首次创建,会执行服务的onCreate方法,执行一次
3).service.onStart() 每次activity调用startService()都会执行该方法
4).context.stopService() 停止当前服务
5).service.onDestroy() 调用了服务onDestroy方法(2).bindService启动方式的生命周期
1).context.bindService()绑定服务,可以指定服务标签,比如服务不存在可以自动创建
2). service.onCreate() 服务如果首次创建,会执行服务的onCreate方法,执行一次
3). service.onBind() 每次绑定都会执行该方法,并返回一个Binder对象,通过该Binder对象,可以间接执行服务中的方法
4).context.onUnbind() 解除绑定,如果当前服务是在绑定时候创建的,则销毁该服务
5). service.onDestroy() 销毁服务,Service调用onDestroy()(3).混合启动方式的生命周期(***)
1).context.startService() activity调用startService()方法
2). service.onCreate() 服务首次创建,会执行服务的onCreate方法,执行一次
3). service.onStart() 每次startService()都会执行该方法
4).context.bindService() 操作同一服务,以得到Binder代理对象
5). service.onBind(); 返回Binder对象
6).在activity中操作binder对象,从而调用服务中方法
7).context.unbindService()可以在当前Activity销毁时,即在Activity的onDestroy解除绑定,用try语句,如果没有绑定服务可能出现异常
8).context.stopService() activity停止服务
9). service.onDestroy() 服务销毁
4.IntentService
public abstract class IntentService extends Service { private volatile Looper mServiceLooper; private volatile ServiceHandler mServiceHandler; private String mName; private boolean mRedelivery; private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { onHandleIntent((Intent)msg.obj); stopSelf(msg.arg1); } } @Override public void onCreate() { super.onCreate(); HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); /* * 在thread.start(); 对应执行的run方法中,执行了 * Looper.prepare(); * Looper.loop(); * 操作,然后将生成的looper作为参数,传递到handler中,虽然该handler在主线程中创建, * 但是由于为其制定了looper,故工作线程在阻塞掉用Loop.loop(),调用依然在工作线程中, * 耗时操作可以方法onHandleIntent中,可以处理接收到intent对象 */ mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); } @Override public void onStart(Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); } protected abstract void onHandleIntent(Intent intent); }
可查看Android_Thread多线程_Handler,Message,Looper,MessageQueue多线程和特殊UI更新一文
5.粘性Service和非粘性Service
只有在系统内存很低时,才有可能强制杀死Service来回收系统资源。如果该Service绑定在有用户焦点的Activity上,很少可能被杀死;如果在foreground中定义,几乎不可能被杀死。onStartCommand()必须返回一个整数,该返回值描述了服务被杀死后如何再处理该服务,下面接受3种类型!
(1).START_NOT_STICKY
If the system kills the service
after onStartCommand() returns, do not recreate the service, unless there are pending intents to deliver. This is the safest option
to avoid running your service when not necessary and when your application can simply restart any unfinished jobs.(2).START_STICKY
If the system kills the service
after onStartCommand() returns, recreate the service and call onStartCommand(),but do not redeliver the last intent. Instead, the
system callsonStartCommand() with a
null intent, unless there were pending intents to start the service, in which case, those intents are delivered. This is suitable for media players (or similar services) that are not executing commands, but running indefinitely and waiting
for a job.(3).START_REDELIVER_INTENT
If the system kills the service
after onStartCommand() returns, recreate the service and call onStartCommand() withthe last intent that was delivered to the service.
Any pending intents are delivered in turn. This is suitable for services that are actively performing a job that should be immediately resumed, such as downloading a file.
6.Service完成UI的更新
public class MainActivity extends Activity { private ProgressBar bar; private IMyBinder mBinder; private Handler handler = new Handler(){ public void handleMessage(Message msg) { bar.setProgress(Integer.parseInt(msg.obj.toString())); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bar = (ProgressBar) findViewById(R.id.progressBar1); startService(new Intent(this, MyService.class)); bindService(new Intent(this, MyService.class), conn, Context.BIND_AUTO_CREATE); } public void click(View view){ mBinder.doLongWork(); } private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { } @Override public void onServiceConnected(ComponentName name, IBinder service) { mBinder = (IMyBinder) service; //得到binder对象,为其设定handler对象 mBinder.setHandler(handler); }; }; }
public class MyService extends Service { private Handler mHandler; private Mybinder binder; @Override public void onCreate() { super.onCreate(); binder = new Mybinder(); } @Override public IBinder onBind(Intent intent) { return binder; } class Mybinder extends Binder implements IMyBinder{ @Override public void setHandler(Handler handler) { //用于接收handler对象,完成ui的更新 mHandler = handler; } @Override public void doLongWork() { //开启线程,完成耗时操作 new Thread(){ public void run() { for(int i=0; i<11; i++){ try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("i = "+i); Message msg = mHandler.obtainMessage(); msg.obj = i*10; mHandler.sendMessage(msg); } } }.start(); } } }
/** * 提供一个公共接口 * @author Administrator * */ public interface IMyBinder { public void setHandler(Handler handler); public void doLongWork(); }
7.服务类型分类
(1).本地服务
服务依附在主进程上而不是独立的进程,服务通信很方便。主进程终止后,服务也会终止,音乐播放等后台操作大多是这种类型。
服务通信,一种方式是通过绑定服务,根据返回Binder对象调用;另一种是在服务类别声明一个广播接收者内部类,其它应用通过发送一个广播,来达到通信目的。通信过程请看后面介绍。
(2).远程服务
该服务是独立的进程,这种Service是常驻的,如果想其它应用与该service通信,必须满足一定机制要求。达到远程服务通信,除了发送一个广播,还可以根据aidl(安卓接口定义语言)。
8.服务通信
(1).通用型(本地/远程)
1).广播接收者
/** * TestService.java * 允许第三方应用,启动该服务完成计算的功能,第三方广播的intent设置需要计算的参数, * 在内部类广播接收者中获得该参数信息,并调用服务的方法,完成计算功能 * @author Administrator */ public class TestService extends Service { private MyReceiver receiver; @Override public void onCreate() { /* * 服务开启的时候注册一个广播接收者,广播接收者注册不用再清单文件中配置 * 其action为com.baidu.caluservice2 */ receiver = new MyReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction("com.baidu.caluservice2"); registerReceiver(receiver, filter); //注册接收者 super.onCreate(); } //内部类的广播接收者 class MyReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { //得到传递的参数信息 int m = intent.getIntExtra("m", 0); int n = intent.getIntExtra("n", 0); // 调用服务的计算功能 int result = methodService(m, n); Toast.makeText(getApplicationContext(), m+"+"+n+"="+result, Toast.LENGTH_SHORT).show(); } } //服务计算功能 public int methodService(int m, int n){ int result = m*n; return result; } @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } // 对于注册的广播接收者,在服务销毁时,应该解除广播的注册 @Override public void onDestroy() { unregisterReceiver(receiver); super.onDestroy(); } }
<!-- AndroidManifest.xml --> <service android:name="com.baidu.calu.TestService"> <intent-filter> <action android:name="com.baidu.caluservice"/> </intent-filter> </service>
/** * TestService.java * 第三方应用发送一个携带传递参数的广播,通过其它应用的服务,完成计算的功能 * @author Administrator * */ public class MainActivity extends Activity { private EditText textm; private EditText textn; private Intent intent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textm = (EditText) this.findViewById(R.id.textm); textn = (EditText) this.findViewById(R.id.textn); //首先应该启动第三方服务,完成广播接收者注册初始化 intent = new Intent(); intent.setAction("com.baidu.caluservice"); startService(intent); } public void start(View view){ //发送一个广播,并未intent设置需要传递的参数信息 Intent intent2 = new Intent(); intent2.setAction("com.baidu.caluservice2"); //设置需要传递 的参数信息 intent2.putExtra("m", Integer.parseInt(textm.getText().toString())); intent2.putExtra("n", Integer.parseInt(textn.getText().toString())); sendBroadcast(intent2); } @Override protected void onDestroy() { stopService(intent); super.onDestroy(); } }
2).Parcel
private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { } @Override public void onServiceConnected(ComponentName name, IBinder service) { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInt(10); data.writeInt(20); try { /* * transact(),将包含数据的data,调用binder对象的onTransact()方法, * 接收onTransact()写入的数据reply,通过reply得到执行结果 * 实际上,service中的binder的onTransact()方法在主线程中调用,不能执行耗时操作 * 可以在执行service.transact(100, data, reply, 0);时使用多线程 */ service.transact(100, data, reply, 0); int result = reply.readInt(); //得到结果 } catch (RemoteException e) { e.printStackTrace(); } data.recycle(); reply.recycle(); }; };
public class MyService extends Service { private Mybinder binder; @Override public void onCreate() { super.onCreate(); binder = new Mybinder(); } @Override public IBinder onBind(Intent intent) { return binder; } class Mybinder extends Binder{ @Override protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { /* * Parcel data activity写入的数据 * Parcel reply 执行完成之后写入的数据 */ int x = data.readInt(); int y = data.readInt(); reply.writeInt(x+y); return super.onTransact(code, data, reply, flags); } } }
(2).代理通信
1).本地Binder通信
/** * MainActivity.java * @author Administrator * */ public class MainActivity extends Activity { private EditText textm; private EditText textn; private IMyBinder binder; //Binder对象 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textm = (EditText) this.findViewById(R.id.textm); textn = (EditText) this.findViewById(R.id.textn); } public void start(View view){ Intent intent = new Intent(this, CalService.class); // 绑定服务 bindService(intent, new MyServiceConn(), Context.BIND_AUTO_CREATE); } class MyServiceConn implements ServiceConnection{ @Override public void onServiceConnected(ComponentName name, IBinder service) { //service返回Binderdialing对象,由于代理对象私有,只能强转为其实现的接口类型 binder = (IMyBinder) service; String m = textm.getText().toString(); String n = textn.getText().toString(); try { //调用binder的方法,从而调用service内部计算方法,并得到计算的返回值 int result = binder.method(Integer.parseInt(m), Integer.parseInt(n)); Toast.makeText(MainActivity.this, m+"+"+n+"="+result, Toast.LENGTH_SHORT).show(); } catch (Exception e) { e.printStackTrace(); } } //服务异常退出或者终止时才调用该方法 @Override public void onServiceDisconnected(ComponentName name) { } } }
/** * IMyBinder.java * 供代理类继承,并暴露代理类的方法,供调用者使用 * @author Administrator * */ interface IMyBinder { int method(int m, int n); }
/** * CalService.java * 计算服务 * @author Administrator * */ public class CalService extends Service { private MyBinder binder; @Override public void onCreate() { binder = new MyBinder(); super.onCreate(); } //每次绑定会调用该方法 @Override public IBinder onBind(Intent intent) { return binder; } //内部代理类,该类应该设置为私有的,只向外暴露继承接口的方法 private class MyBinder extends Binder implements IMyBinder { @Override public int method(int m, int n) { //调用服务内部方法 int result = methodService(m, n); return result; } } // 服务计算功能 public int methodService(int m, int n) { int result = m + n; return result; } }
2) .远程aidl通信
/** * TestService.java * 允许第三方应用,启动该服务完成计算的功能,第三方广播的intent设置需要计算的参数, * 在内部类广播接收者中获得该参数信息,并调用服务的方法,完成计算功能 * @author Administrator * */ public class TestService extends Service { private MyBinder binder; @Override public void onCreate() { System.out.println("onCreate"); binder = new MyBinder(); super.onCreate(); } //返回Binder对象 @Override public IBinder onBind(Intent intent) { System.out.println("onBind"); return binder; } //直接继承IMyBinder的Stub内部类,由于该类已经继承了Binder private class MyBinder extends IMyBinder.Stub{ @Override public int method(int m, int n) throws RemoteException { //调用service方法 int result = methodService(m, n); return result; } } //计算中心 public int methodService(int m, int n){ int result = m*n; return result; } }
/** * 服务下的IMyBinder.aidl文件 * aidl文件,该文件定义不能使用public使用权限,由于接口已经默认为public,该文件会自动编译 * 调用该服务的应用也应该声明同样的IMyBinder.aidl文件,注意包名也应该一致 * @author Administrator * */ interface IMyBinder { int method(int m, int n); }
/** * MainActivity.java * 第三方应用发送一个携带传递参数的广播,通过其它应用的服务,完成计算的功能 * @author Administrator * */ public class MainActivity extends Activity { private EditText textm; private EditText textn; private IMyBinder binder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textm = (EditText) this.findViewById(R.id.textm); textn = (EditText) this.findViewById(R.id.textn); } public void start(View view){ //绑定服务 Intent intent = new Intent(); intent.setAction("com.baidu.caluservice"); bindService(intent, new MyServiceConn(), Context.BIND_AUTO_CREATE); } class MyServiceConn implements ServiceConnection{ @Override public void onServiceConnected(ComponentName name, IBinder service) { //得到服务onBind返回的Binder对象 binder = IMyBinder.Stub.asInterface(service); //使用该方式得到返回的接口对象 String m = textm.getText().toString(); String n = textn.getText().toString(); try { //调用binder方法,并得到返回值 int result = binder.method(Integer.parseInt(m), Integer.parseInt(n)); Toast.makeText(MainActivity.this, m+"+"+n+"="+result, Toast.LENGTH_SHORT).show(); } catch (Exception e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } } }
/** * 第三方应用的IMyBinder.aidl文件 * 注意包名应该与服务的包名一致 * @author Administrator * */ interface IMyBinder { int method(int m, int n); }