一 、什么是Service?什么时候我们需要使用service?
service就是android系统中的服务,它有这么几个特点:它无法与用户直接进行交互、它必须由用户或者其他程序显式的启动、它的优先级比较高,它比处于前台的应用优先级低,但是比后台的其他应用优先级高,这就决定了当系统因为缺少内存而销毁某些没被利用的资源时,它被销毁的概率很小哦。
service是运行在后台的应用,对于用户来说失去了被关注的焦点。这就跟我们打开了音乐播放之后,便想去看看图片,这时候我们还不想音乐停止,这里就会用到service;又例如,我们打开了一个下载链接之后,我们肯定不想瞪着眼睛等他下载完再去做别的事情,对吧?这时候如果我们想手机一边在后台下载,一边可以让我去看看新闻啥的,就要用到service。
总言之:service用于处理后台任务
二、service分类
一般我们认为service分为两类,本地service和远程service。
本地service顾名思义,那就是和当前应用在同一个进程中的service,彼此之间拥有共同的内存区域,所以对于某些数据的共享特别的方便和简单;
远程service:主要牵扯到不同进程间的service访问。因为android的系统安全的原因导致了我们在不同的进程间无法使用一般的方式共享数据。在这里android为我们提供了一个AIDL工具,(android interface description language)android接口描述语言。在后边我们将会对其进行详细的介绍。
三、Service两种启动方式及生命周期
由上图知,Service有两种启动方式:
Unbounded模式下的startService();
Bounded模式下的bindService();
startService()
使用场景:通过startservice开启的服务.一旦服务开启, 这个服务和开启他的调用者之间就没有关系了.
调用者不可以访问 service里面的方法. 调用者如果被系统回收了或者调用了ondestroy方法, service还会继续存在
生命周期:
context.startService() -> onCreate() -> onStart() -> Service running -> context.stopService() -> onDestroy() -> Service stop
如果Service还没有运行,则android先调用onCreate(),然后调用onStart();
如果Service已经运行,则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次。
如果stopService的时候会直接onDestroy,如果是调用者自己直接退出(onPause)而没有调用stopService的话,Service会一直在后台运行,该Service的调用者再启动起来后可以通过stopService关闭Service。
可以通过Service.stopSelf()方法或者Service.stopSelfResult()方法来停止服务,只要调用一次stopService()方法便可以停止服务,无论调用了多少次的启动服务方法。
所以调用startService的生命周期为:onCreate --> onStart (可多次调用) --> onDestroy
bindService()
使用场景:通过bindService开启的服务,服务开启之后,调用者和服务之间 还存在着联系。
一旦调用者挂掉了.service也会跟着挂掉 .
生命周期:
context.bindService() -> onCreate() -> onBind() -> Service running -> onUnbind() -> onDestroy() -> Service stop
onBind()将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service的实例、运行状态或其他操作。这个时候把调用者(Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用onUnbind->onDestroy相应退出。
当其调用者退出(onPause)时或者调用unbindService(connection); (可以不用)可以停止服务。
所以调用bindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory
在Service每一次的开启关闭过程中,只有onStart可被多次调用(通过多次startService调用),其他onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。
四、实例
startService()
StartActivity.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package start_service; import com.huange.service_mp3.R; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class StartActivity extends Activity implements OnClickListener { private static final String TAG = "StartActivity"; private Button playBtn; private Button stopBtn; private Button pauseBtn; private Button exitBtn; private Button closeBtn; private Intent intent; private int op=0; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.start_service); findView(); bindButton(); } private void findView() { playBtn = (Button) findViewById(R.id.playButton); stopBtn = (Button) findViewById(R.id.stopButton ); pauseBtn = (Button) findViewById(R.id.pauseButton ); exitBtn = (Button) findViewById(R.id.exitButton ); closeBtn = (Button) findViewById(R.id.closeButton ); } private void bindButton() { playBtn.setOnClickListener(this); stopBtn.setOnClickListener(this); pauseBtn.setOnClickListener(this); exitBtn.setOnClickListener(this); closeBtn.setOnClickListener(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { // TODO Auto-generated method stub return super.onCreateOptionsMenu(menu); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.playButton: Log.d(TAG, "onClick------------------------------->playing music"); op = 1; tostartMusicService(); break; case R.id.stopButton: Log.d(TAG, "onClick------------------------------->stoping music"); op = 2; tostartMusicService(); break; case R.id.pauseButton : Log.d(TAG, "onClick------------------------------->pausing music"); op = 3; tostartMusicService(); break; case R.id.closeButton : Log.d(TAG, "onClick------------------------------->close"); this.finish(); break; case R.id.exitButton : Log.d(TAG, "onClick------------------------------->exit"); op = 4; intent = new Intent("android.startService"); stopService(intent); this.finish(); break; } } public void tostartMusicService(){ intent = new Intent("android.startService");//区分服务类型 Bundle bundle = new Bundle(); bundle.putInt("op", op); intent.putExtras(bundle); startService(intent); //此处也可以用 intent.setClass(this,StartMusicService.class); 这样intent=new Intent(); } }
StartMusicService.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package start_service; import java.io.IOException; import com.huange.service_mp3.R; import android.app.Service; import android.content.Intent; import android.media.MediaPlayer; import android.os.Bundle; import android.os.IBinder; import android.util.Log; public class StartMusicService extends Service { private static final String TAG = "StartMusicService"; private MediaPlayer mediaPlayer; @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return null; } @Override public void onCreate() { Log.v(TAG, "------------------------------------------->onCreate"); if (mediaPlayer == null) { mediaPlayer = MediaPlayer.create(this, R.raw.beijing_hutong); mediaPlayer.setLooping(false); } } @Override public void onStart(Intent intent, int startId) { Log.v(TAG, "------------------------------------------->onStart"); if (intent != null) { Bundle bundle = intent.getExtras(); if (bundle != null) { int op = bundle.getInt("op"); switch (op) { case 1: play(); break; case 2: stop(); break; case 3: pause(); break; } } } } public void play() { if (!mediaPlayer.isPlaying()) { System.out.println("------------------------------->play"); mediaPlayer.start(); } } public void pause() { if (mediaPlayer != null && mediaPlayer.isPlaying()) { System.out.println("------------------------------->pause"); mediaPlayer.pause(); } } public void stop() { if (mediaPlayer != null) { System.out.println("------------------------------->stop"); mediaPlayer.stop(); try { // 在调用stop后如果需要再次通过start进行播放,需要之前调用prepare函数 mediaPlayer.prepare(); } catch (IOException ex) { ex.printStackTrace(); } } } @Override public void onDestroy() { Log.v(TAG, "------------------------------------------->onDestroy"); if (mediaPlayer != null) { mediaPlayer.stop(); mediaPlayer.release(); } } }
AndroidManifest.xml
<service android:enabled="true" android:name="start_service.StartMusicService"> <intent-filter> <action android:name="android.startService" /> </intent-filter> </service>
运行结果:
04-24 16:00:54.922: D/StartActivity onClick------------------------------->playing music 04-24 16:00:54.922: V/StartMusicService(5784): ------------------------------------------->onCreate 04-24 16:00:54.967: V/StartMusicService(5784): ------------------------------------------->onStart 04-24 16:00:54.967: I/System.out(5784): ------------------------------->play 04-24 16:01:05.452: D/StartActivity(5784): onClick------------------------------->pausing music 04-24 16:01:05.457: V/StartMusicService(5784): ------------------------------------------->onStart 04-24 16:01:05.457: I/System.out(5784): ------------------------------->pause 04-24 16:01:11.512: D/StartActivity(5784): onClick------------------------------->stoping music 04-24 16:01:11.512: V/StartMusicService(5784): ------------------------------------------->onStart 04-24 16:01:11.512: I/System.out(5784): ------------------------------->stop 04-24 16:01:18.347: D/StartActivity(5784): onClick------------------------------->close 04-24 16:01:38.792: D/StartActivity(5784): onClick------------------------------->playing music 04-24 16:01:38.797: V/StartMusicService(5784): ------------------------------------------->onStart 04-24 16:01:38.797: I/System.out(5784): ------------------------------->play 04-24 16:01:44.517: D/StartActivity(5784): onClick------------------------------->exit 04-24 16:01:44.522: V/StartMusicService(5784): ------------------------------------------->onDestroy
bindService()
BindActivity.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package bind_service; 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.util.Log; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import com.huange.service_mp3.R; public class BindActivity extends Activity implements OnClickListener{ private static final String TAG = "PlayBindMusic"; private Button playBtn; private Button stopBtn; private Button pauseBtn; private Button exitBtn; private Button closeBtn; private BindMusicService musicService; /** Called when the activity is first created. */ @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.bind_service); findView(); bindButton(); connection(); } private void findView() { playBtn = (Button) findViewById(R.id.bplayButton); stopBtn = (Button) findViewById(R.id.bstopButton); pauseBtn = (Button) findViewById(R.id.bpauseButton); exitBtn = (Button) findViewById(R.id.bexitButton); closeBtn = (Button) findViewById(R.id.bcloseButton); } private void bindButton() { playBtn.setOnClickListener(this); stopBtn.setOnClickListener(this); pauseBtn.setOnClickListener(this); closeBtn.setOnClickListener(this); exitBtn.setOnClickListener(this); } private void connection(){ Log.d(TAG, "......connecting......"); Intent intent = new Intent("android.bindService"); //也可以:Intent intent = new Intent(MainActivity.this,BindMusicService.class); //Context.BIND_AUTO_CREATE :只要Activity和Service绑定了,就会自动创建Service bindService(intent, sc, Context.BIND_AUTO_CREATE); } @Override public boolean onCreateOptionsMenu(Menu menu) { // TODO Auto-generated method stub return super.onCreateOptionsMenu(menu); } @Override public void onClick(View v) { //可以调用Service方法 switch (v.getId()) { case R.id.bplayButton: Log.d(TAG, "onClick: playing service"); musicService.play(); break; case R.id.bstopButton : Log.d(TAG, "onClick: stoping service"); if(musicService != null){ musicService.stop(); } case R.id.bpauseButton : Log.d(TAG, "onClick: pausing service"); if(musicService != null){ musicService.pause(); } break; case R.id.bcloseButton : Log.d(TAG, "onClick: close"); this.finish(); break; case R.id.bexitButton : Log.d(TAG, "onClick: exit"); unbindService(sc); break; } } /** * 监视服务状态的接口,可以获得一个服务实例 */ private ServiceConnection sc = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) {//Activtiy和服务连接断开时调用 musicService = null; Log.d(TAG, "------------------------->in onServiceDisconnected"); } @Override public void onServiceConnected(ComponentName name, IBinder service) {//Activtiy和服务连接时调用 musicService = ((BindMusicService.MyBinder)(service)).getService();//获取一个服务实例 Log.d(TAG, "------------------------->in onServiceConnected"); } }; }
BindMusicService.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package bind_service; import java.io.IOException; import com.huange.service_mp3.R; import android.app.Service; import android.content.Intent; import android.media.MediaPlayer; import android.os.Binder; import android.os.IBinder; import android.util.Log; import android.widget.Toast; public class BindMusicService extends Service { private static final String TAG = "MyService"; private MediaPlayer mediaPlayer; private final IBinder binder = new MyBinder();//应用和Service间就依靠这个IBinder对象进行通信 public class MyBinder extends Binder {//此类用于client(此处Activity)获取BindMusicService对象 BindMusicService getService() { return BindMusicService.this; } } @Override public void onCreate() { super.onCreate(); Log.d(TAG, "---------------------------------------------->onCreate"); } @Override public IBinder onBind(Intent intent) { Log.d(TAG, "--------------------------------------------->onBind"); return binder; } @Override public void onDestroy() { super.onDestroy(); Log.d(TAG, "----------------------------------------------->onDestroy"); if(mediaPlayer != null){ mediaPlayer.stop(); mediaPlayer.release(); } } public void play() { System.out.println("------------------------------->play"); if (mediaPlayer == null) { mediaPlayer = MediaPlayer.create(this, R.raw.because_of_you); mediaPlayer.setLooping(false); } if (!mediaPlayer.isPlaying()) { mediaPlayer.start(); } } public void pause() { System.out.println("------------------------------->pause"); if (mediaPlayer != null && mediaPlayer.isPlaying()) { mediaPlayer.pause(); } } public void stop() { System.out.println("------------------------------->stop"); if (mediaPlayer != null) { mediaPlayer.stop(); try { mediaPlayer.prepare(); } catch (IOException ex) { ex.printStackTrace(); } } } }
AndroidManifest.xml
<service android:enabled="true" android:name="bind_service.BindMusicService"> <intent-filter> <action android:name="android.bindService" /> </intent-filter> </service>
运行结果:
04-25 11:26:46.348: D/PlayBindMusic(19297): ......connecting......
04-25 11:26:46.358: D/MyService(19297): ---------------------------------------------->onCreate
04-25 11:26:46.358: D/MyService(19297): --------------------------------------------->onBind
04-25 11:26:46.433: D/PlayBindMusic(19297): ------------------------->in onServiceConnected
04-25 11:27:10.988: D/PlayBindMusic(19297): onClick: playing service
04-25 11:27:10.993: I/System.out(19297): ------------------------------->play
04-25 11:27:34.588: D/PlayBindMusic(19297): onClick: exit
04-25 11:27:34.588: D/MyService(19297): ----------------------------------------------->onDestroy
04-25 11:28:37.323: D/PlayBindMusic(19588): onClick: close
04-25 11:28:37.818: E/ActivityThread(19588): Activity bind_service.BindActivity has leaked ServiceConnection bind_service.BindActivity$1@421c33b8 that was originally bound here
04-25 11:28:37.828: D/MyService(19588): ----------------------------------------------->onDestroy