Service是android 系统中的一种组件,它跟Activity的级别差不多,但是他不能自己运行,只能后台运行,并且可以和其他组件进行交互。Service的启动有两种方式:context.startService() 和 context.bindService()。
(1)使用context.startService()
启动Service时会经历:
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
(2)使用context.bindService()
启动Service会经历:
context.bindService()->onCreate()->onBind()->Service running
onUnbind() -> onDestroy() ->Service stop
onBind将返回给客户端一个IBinder接口实例,IBinder允许客户端回调服务的方法(AIDL),比如得到Service运行的状态或其他操作。这个时候把调用者(Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用onUnbind->onDestroy相应退出。
所以调用bindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory。
(3)举一个播放器实例说明service的第一种方式。运行界面如下:
A,主activity代码:
public class MainActivity extends Activity{
int op = -1; //intent带的参数
Bundle bundle = new Bundle(); //intent带参数需要Bundle
Intent intent = new Intent("org.allin.android.musicService"); //A,发广播名字的intent
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button playBtn = (Button)findViewById(R.id.play);
Button stopBtn = (Button)findViewById(R.id.stop);
Button pauseBtn = (Button)findViewById(R.id.pause);
Button closeBtn = (Button)findViewById(R.id.close);
Button exitBtn = (Button)findViewById(R.id.exit); //关联按钮
playBtn.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v){
op = 1; //操作码
bundle.putInt("op", op);
intent.putExtras(bundle);
startService(intent); //onStart满足不同功能可多次调用
}
});
stopBtn.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v){
op = 2;
bundle.putInt("op", op);
intent.putExtras(bundle);
startService(intent);
}
});
pauseBtn.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v){
op = 3;
bundle.putInt("op", op);
intent.putExtras(bundle);
startService(intent);
}
});
closeBtn.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v){
MainActivity.this.finish(); //退出activity,service并没有停止,歌曲照常播放
}
});
exitBtn.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v){
//op = 4;
//bundle.putInt("op", op);
//intent.putExtras(bundle);
stopService(intent);
MainActivity.this.finish(); //先退出service并释放资源,再关activity
}
});
}
}
B,AndroidManifest.xml内容
<service android:enabled="true" //使能该服务
android:name=".MusicService" //service的类名
android:exported="false">
<intent-filter>
<action android:name="org.allin.android.musicService" /> //service的过滤器
<category android:name="android.intent.category.default" />
</intent-filter>
</service>
C,service的类实现文件。该例演示了用intent对象传递额外数据的用法
public class MusicService extends Service {
private MediaPlayer mediaPlayer;
public IBinder onBind(Intent arg0) //重写onBind
{
Log.i(TAG,"onBind run");
return null;
}
public void onCreate(){ //service启动时创建,只会执行一次。除非服务退出之后再运行app才会执行
if(mediaPlayer == null){
mediaPlayer = MediaPlayer.create(this, R.raw.test);
mediaPlayer.setLooping(false);
}
}
public void onDestroy(){ //服务停止时执行
if(mediaPlayer != null){
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
}
public void onStart(Intent intent, int startId){ //service可以接收的操作,通过不同参数分别处理
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 != null){
mediaPlayer.start();
}
}
public void stop(){
if(mediaPlayer != null){
mediaPlayer.stop();
try{
mediaPlayer.prepare();
}catch(IOException e){
e.printStackTrace();
}
}
}
public void pause(){
if(mediaPlayer != null && mediaPlayer.isPlaying()){
mediaPlayer.pause();
}
}
}
当调用了startService后服务会先调用onCreate,我们在里面对MediaPlayer进行初始化。接着会调用onStart,可以看到传递给startService()的Intent对象会传递给onStart()方法,这样我们就可以得到intent里面的操作码。
close只是调用finish()退出当前的Activity,但是Service并没有关掉,音乐会继续播放。而exit就是调用了stopService(intent);来停止服务,Service会调用onDestroy()方法来对mediaPlayer进行停止和释放资源。
(4)关于“Exported service does not require permission”的警告
在一个涉及到service的应用的manifest中,提示了如上的警告。解决方法:在如下位置添加android:exported="false",这种方法是限制外部访问,只能本应用访问。
<service android:name=".MusicService"
android:exported="false">
==================service 的开机自启动======================================
服务的开机自启动在很多场合都是有必要的,也就是不用上述的运行APP的方式调用服务,而是开机后就启动服务中的OnCreate函数,这个可以通过在OnCreate加TARCE确认。步骤如下:
(1)在服务包中的XML中添加开机启动的权限属性
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission>
(2)在服务包中的XML中添加receiver的相关信息
<receiver android:name=".BootBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
(3)在pakage中新建BootBroadcastReceiver文件,源码如下:
package com.example.servicestart;
import android.content.BroadcastReceiver; //receiver的基类
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class BootBroadcastReceiver extends BroadcastReceiver { //receiver的名字要与XML中定义的相同
private static final String TAG = "MyService";
static final String ACTION = "android.intent.action.BOOT_COMPLETED"; //与XML中定义的要相同
@Override
public void onReceive(Context arg0, Intent arg1) { //重写onReceive
Log.d(TAG, "Boot completed");
if (arg1.getAction().equals(ACTION)) { //Intent filter的ACTION要相同
Intent myintent = new Intent(arg0, MusicService.class); //B指定服务类的intent做法,可与第一个例子A对比
//myintent.setAction("org.allin.android.musicService"); //C指定服务action的名字,区别于receiver的Intent action,此时用sendbroadcast
arg0.startService(myintent);
}
}
}
之后编译整个APK,将他安装到系统中并重启手机。在开机TRACE中即可出现:Boot completed 。。。。MyService onCreate,onStart等消息(无界面)。需要注意的是:有的服务通过deploy进去之后重启手机并不能自启动,通过将app push到/system/app下再重启才可以自启动。
========================service被杀死后自启动=================================
要想保证一个service被杀死后能够自己重新启动(重生),只需要在onDestroy函数中加上一些代码即可。以上面的例子来说明:
public void onDestroy(){
Log.i(TAG,"onDestroy");
.................
Intent localIntent = new Intent();
localIntent.setClass(this, MusicService.class); // D销毁时重新启动Service,与上面的
setAction比对 this.startService(localIntent);
}
如果想让服务不被杀死(也即无动作不改变),在XML的<application段后面加上 android:persistent="true"就行了。
================service中动态定义receiver===============================
注册BroadcastReceiver两种方式:方式一,静态的在AndroidManifest.xml中用<receiver>标签声明注册,并在标签内用<intent- filter>标签设置过滤器,如上的开机自启动方式。方式二,动态地在代码中先定义并设置好一个 IntentFilter对象,然后在需要注册的地方调 Context.registerReceiver()方法,如果取消时就调用Context.unregisterReceiver()方法。如果用动态方式注册的BroadcastReceiver的Context对象被销毁时,BroadcastReceiver也就自动取消注册了。
方法二的实例:在一个服务中,监听LCD唤醒(系统唤醒或者其他)做对应的处理,步骤如下:
(1)导入类:
import android.content.BroadcastReceiver;
import android.content.IntentFilter;
(2)在service的onCreate中定义IntentFilter及注册receiver
IntentFilter ScreenFilter = new IntentFilter();
ScreenFilter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(mScreenFilterReceiver, ScreenFilter);
(3)定义receiver
private BroadcastReceiver mScreenFilterReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
freshDetect(); //做要求的处理
}
}
};
(4)onDestroy中要反注册这个receiver。
unregisterReceiver(mScreenFilterReceiver);
注意:第(2)步如果有现成的静态receicer文件,把新的IntentFilter加到已有的receiver文件中也可以。一起处理。比如:
ScreenOn_filter.addAction("android.intent.action.SCREEN_ON");
registerReceiver(new BootBroadcastReceiver(), ScreenOn_filter);
参考原文:http://www.cnblogs.com/allin/archive/2010/05/15/1736458.html
参考原文:http://blog.csdn.net/zxf20063033/article/details/7702779