Android的Service && service 的开机自启动 && service被杀死后自启动 && service中动态定义receiver

         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

参考原文:http://blog.csdn.net/u0fly/article/details/5909477 

参考原文:http://www.eoeandroid.com/thread-117126-1-1.html

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值