Android 四大组件之Service
什么是Service?
Service是能够在后台执行长时间运行操作并且不提供用户界面的应用程序组件。(简单来说,Service就是提供服务的代码,这些代码最终体现为一个个的接口函数。所以,Service就是实现一组函数的对象,通常也称为组件。)它跟Activity的级别差不多,但是他不能自己运行,需要通过某一个Activity或者其他Context对象来调用, Context.startService() 和Context.bindService()。
为什么要用Service?
启动方法 | Activity与Service | 是否返回值 | 何时被动终止 | 手动关闭 |
startService | 没有关系 | 否 | Activity退出,仍运行 | stopService或stopSelf(只有intent执行完才行停止掉) |
bindService | 可以有多个Acyivity绑定 | 是,可以IPC通信 | 所有绑定Activity退出,才退出??? | 同上 |
要想正确使用Service,必须熟知Service的启动流程,具体如下:
context.startService() 启动流程:
context.startService() -> onCreate() -> onStart() -> Service running -> context.stopService() -> onDestroy() -> Service stop
如果Service还没有运行,则android先调用onCreate(),然后调用onStart();
如果Service已经运行,则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次。
如果stopService的时候会直接onDestroy,如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行,该Service的调用者再启动起来后可以通过stopService关闭Service。
所以调用startService的生命周期为:onCreate --> onStart (可多次调用) --> onDestroy
context.bindService()启动流程:
context.bindService() -> onCreate() -> onBind() -> Service running -> onUnbind() -> onDestroy() -> Service stop
onBind()将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service的实例、运行状态或其他操作。这个时候把调用者(Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用onUnbind->onDestroy相应退出。
所以调用bindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory。
在Service每一次的开启关闭过程中,只有onStart可被多次调用(通过多次startService调用),其他onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。
PS: onStart() 虽仍能使用,但它已被抛弃,被onStartCommand所取代。
下面我们用图的形式来了解Service的生命周期:
这里要说明一下的是如果你在Service的onCreate或者onStart做一些很耗时间的事情,最好在Service里启动一个线程来完成,因为Service是跑在主线程中,会影响到你的UI操作或者阻塞主线程中的其他事情。
下面,我们分别用不同方式启动的Service举一个例子:
先用context.startService() 这种方式做一个背景音乐,在界面上有两个button,控制背景音乐的开关:
创建一个MusicService.java继承Service。
public class MusicService extends Service { private static MediaPlayer mediaPlayer; @Override public void onStart(Intent intent, int startId) { // TODO Auto-generated method stub super.onStart(intent, startId); System.out.println("onStart"); // 设置音乐循环 mediaPlayer.setLooping(true); if (!mediaPlayer.isPlaying()) mediaPlayer.start(); } @Override public void onCreate() { System.out.println("onCreate"); mediaPlayer = MediaPlayer.create(this, R.raw.begin_music); super.onCreate(); } @Override public void onDestroy() { System.out.println("onDestroy"); super.onDestroy(); mediaPlayer.stop(); } @Override public IBinder onBind(Intent intent) { System.out.println("onBind"); return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { System.out.println("onStartCommand"); return super.onStartCommand(intent, flags, startId); } }
在MainActivity中的代码为:
public class MainActivity extends Activity { final int RIGHT = 0; final int LEFT = 1; private GestureDetector gestureDetector; private Intent intent; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); intent = new Intent("com.topcsa.test.music"); startService(intent); Button btn_close=(Button) findViewById(R.id.btn_close); Button btn_start=(Button) findViewById(R.id.btn_start); btn_close.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { stopService(new Intent(MainActivity.this,MusicService.class)); } }); btn_start.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { startService(new Intent(MainActivity.this,MusicService.class)); } }); } @Override protected void onDestroy() { stopService(new Intent(MainActivity.this,MusicService.class)); super.onDestroy(); } }
记住在Activity的onDestroy中停止服务,否则即使退出当前应用,Service依然在后台执行并播放音乐。(这种方式中,Activity启动服务后就与Service几乎没有关系了,所以必须要手动关闭Service)
注意:一定不要忘记注册Service
<service android:name="com.example.test_android.MusicService"> <intent-filter > <action android:name="com.topcsa.test.music"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </service>
该程序的运行结果为:
刚打开应用时的结果为(此时,音乐已开始播放):
第一次点击打开背景音乐的button时,结果为(音乐正常播放,无停顿、异常):
此时未运行onCreate方法,但执行了onStartCommand()、onStart()方法。
接下来,第一次点击关闭背景音乐的button,结果为(音乐被关闭):
此时执行了onDestroy()方法。
接下来,我们再点击打开背景音乐的button,结果为(音乐再次打开):
此时,执行了onCreate()方法。
下面我们通过一个例子来了解了解context.bindService()的使用:
main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" > <Button android:id="@+id/start" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="启动服务"/> <Button android:id="@+id/stop" android:layout_width="wrap_content" android:layout_below="@id/start" android:layout_height="wrap_content" android:text="停止服务"/> <Button android:id="@+id/bind" android:layout_below="@id/stop" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="绑定服务"/> <Button android:id="@+id/unbind" android:layout_below="@id/bind" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="解除绑定服务"/> </RelativeLayout>
MusicService.java
public class MusicService extends Service { private static MediaPlayer mediaPlayer, mediaPlayer2; Intent intent; private IBinder myBinder = new IBinder() { @Override public String getInterfaceDescriptor() throws RemoteException { return "My Service class"; } @Override public boolean pingBinder() { // TODO Auto-generated method stub return false; } @Override public boolean isBinderAlive() { // TODO Auto-generated method stub return false; } @Override public IInterface queryLocalInterface(String descriptor) { // TODO Auto-generated method stub return null; } @Override public void dump(FileDescriptor fd, String[] args) throws RemoteException { // TODO Auto-generated method stub } @Override public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException { // TODO Auto-generated method stub } @Override public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { // TODO Auto-generated method stub return false; } @Override public void linkToDeath(DeathRecipient recipient, int flags) throws RemoteException { // TODO Auto-generated method stub } @Override public boolean unlinkToDeath(DeathRecipient recipient, int flags) { // TODO Auto-generated method stub return false; } }; @Override public void onStart(Intent intent, int startId) { // TODO Auto-generated method stub super.onStart(intent, startId); System.out.println("onStart"); } @Override public void onCreate() { System.out.println("onCreate"); mediaPlayer = MediaPlayer.create(this, R.raw.begin_music); super.onCreate(); } @Override public void onDestroy() { System.out.println("onDestroy"); super.onDestroy(); mediaPlayer.stop(); } @Override public IBinder onBind(Intent intent) { System.out.println("onBind"); return null; } @Override public boolean onUnbind(Intent intent) { System.out.println("onUnbind"); return super.onUnbind(intent); } @Override public void onRebind(Intent intent) { System.out.println("onRebind"); super.onRebind(intent); } @Override public int onStartCommand(Intent intent, int flags, int startId) { System.out.println("onStartCommand"); if (!mediaPlayer.isPlaying()) mediaPlayer.start(); mediaPlayer.setLooping(true);// 设置音乐循环 return Service.START_CONTINUATION_MASK; } }
MainActivity.java:
public class MainActivity extends Activity { final int RIGHT = 0; final int LEFT = 1; private GestureDetector gestureDetector; private Intent intent; boolean tag=false; private ServiceConnection sercon = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { System.out.println("onServiceDisconnected"); } @Override public void onServiceConnected(ComponentName name, IBinder service) { try { System.out.println("onServiceConnected service=" + service.getInterfaceDescriptor()); } catch (RemoteException e) { e.printStackTrace(); } } }; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); startService(new Intent(MainActivity.this, MusicService.class)); Button btn_close = (Button) findViewById(R.id.stop); Button btn_start = (Button) findViewById(R.id.start); Button btn_bind = (Button) findViewById(R.id.bind); Button btn_unbind = (Button) findViewById(R.id.unbind); btn_close.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { stopService(new Intent(MainActivity.this, MusicService.class)); } }); btn_start.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { startService(new Intent(MainActivity.this, MusicService.class)); } }); btn_bind.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { tag=true; bindService(new Intent(MainActivity.this, MusicService.class), MainActivity.this.sercon, Context.BIND_AUTO_CREATE); } }); btn_unbind.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if(tag) unbindService(MainActivity.this.sercon); tag=false; } }); } }
运行程序可知:
程序启动时:onCreate、onStartCommand
点击第一个启动服务按钮:onStartCommand
点击第二个停止服务按钮:onDestroy
点击第三个绑定服务按钮:onCreate、onBind
点击第三个解除绑定服务时:onUnbind、onDestroy
推荐文献:http://blog.csdn.net/androiddevelop/article/details/14498193 http://www.cnblogs.com/allin/archive/2010/05/15/1736458.html
文章出处:http://www.cnblogs.com/scetopcsa/
欢迎关注微信公众号:yilu_yiyou(一路一游),一个不仅仅是代码的世界!
如果文中有什么错误,欢迎指出。以免更多的人被误导。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。