Android中的Service组件(二)

一、服务的概念
windows:长期运行在后台,并且运行在独立的一个进程中,没有界面
android:长期运行在后台,运行与当前应用程序的进程中 ,没有界面

二、服务的应用场景
1. 轮询有没有新的设备接入
2. 在后台不断的间隔时间去请求数据
3. 在后台播放音乐
注意:服务虽然长期运行在后台,但是它是运行于主线程的,里面不允许执行太多耗时的操作。

三、进程的优先级别
Foreground process--前台进程:当前与用户进行交互的应用所处的进程
Visible process --可视进程:当前应用能看到,但是没办法与用户进行交互所处的进程
Service process --服务进程:该进程里面运行着服务代码
Background process --后台进程:应用程序被最小化了(home)
Empty process --空进程:应用程序里面没有任何的组件在运行(activity \service)

前台进程  > 可视进程  > 服务进程  > 后台进程  > 空进程

四、startService启动服务
4.1 服务的生命周期
完整的生命周期:onCreate【创建】---onStartCommand(onStart已经过时了)【启动】---onDestory【销毁】
多次启动服务:多次启动服务并不会调用多次onCreate方法,但是会执行多次onStartCommand方法
多次停止服务:服务一旦被停止,再次停止服务将不会有任何效果.
4.2 直接启动服务的例子:音乐播放器
//定义一个继承Service的服务类
public class MusicService extends Service {
	MediaPlayer mediaPlayer;
	public static String PATH = "";
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}
	
	@Override
	public void onCreate() {
		super.onCreate();
		
		try {
			//1.创建一个多媒体播放器
			mediaPlayer = new MediaPlayer();
			//2. 设置播放的资源路径
			mediaPlayer.setDataSource(PATH);
			//3. 缓冲一下
			mediaPlayer.prepare();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		int code = intent.getIntExtra("code", 1);
		switch (code) {
		case 1: //开始播放
			//如果当前不是在播放,那么久让其播放
			if(!mediaPlayer.isPlaying()){
				mediaPlayer.start();//播放音乐
			}
			
			
			break;
		case 2://暂停动作
			
			if(mediaPlayer.isPlaying()){
				mediaPlayer.pause(); //如果当前正在播放,那么现在就应该暂停了
			}
			break;
		case 3: //停止播放
			
			if(mediaPlayer.isPlaying()){
				mediaPlayer.stop();
				mediaPlayer.reset();//重置资源
			}
			break;
		}
		return super.onStartCommand(intent, flags, startId);
	}
	@Override
	public void onDestroy() {
		super.onDestroy();


		if(mediaPlayer !=null){
			mediaPlayer.release();
			mediaPlayer = null;
		}
	}


}
<! 在清单文件中注册服务 !>
<service android:name="com.heima.player.MusicService"></service>
//在界面中使用服务
public class MainActivity extends Activity {


	EditText et_path;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        et_path = (EditText) findViewById(R.id.et_path);
    }


    public void play(View v) {
    	String path = et_path.getText().toString().trim();
    	if(TextUtils.isEmpty(path)) {
    		Toast.makeText(this, "路径不能为空", 0).show();
			return;
    	}
    	
    	File file = new File(path);
    	if(!file.exists()) {
    		Toast.makeText(this, "非法的文件路径。", 0).show();
			return ;
    	}
    	
    	//播放音乐..----Service去播放
    	MusicService.PATH = path;
    	Intent service = new Intent(this, MusicService.class);
    	service.putExtra("code", 1);
    	startService(service);
    }
    
    public void pause(View v) {
		Intent service = new Intent(this ,MusicService.class);
		service.putExtra("code", 2);
		startService(service);
    }
    
    public void stop(View v) {
		Intent service = new Intent(this ,MusicService.class);
		service.putExtra("code", 3);
		startService(service);
   }
    
    @Override
    public void onBackPressed() {
    	AlertDialog.Builder dialog = new AlertDialog.Builder(this);
    	dialog.setTitle("提示:");
    	dialog.setMessage("是否继续播放音乐?");
    	dialog.setPositiveButton("是", new OnClickListener() {
			public void onClick(DialogInterface dialog, int which) {
				// TODO Auto-generated method stub
				finish();
			}
		});
    	dialog.setNegativeButton("否", new OnClickListener() {
			public void onClick(DialogInterface dialog, int which) {
				// TODO Auto-generated method stub
				stopService(new Intent(MainActivity.this,MusicService.class));
				finish();
			}
		});
    	
    	dialog.show();
    }
}

五、直接启动服务的缺陷

无法与服务进行通讯 ,没办法调用服务中的方法

六、bindService启动服务
6.1 绑定服务的步骤
1. 定义服务
	public class ServcieDemo extends Service {}
2. 注册服务
	<service android:name="com.itheima.bind.ServcieDemo"></service>
3. 编写服务的方法
/**
	 * 录取通知书 
	 * 服务中的内部方法
	 */
	public void methodInService(String name , int money){
		if(money <= 100000){
			Toast.makeText(this, name+",你的钱不够.", 0).show();
		}else{
			Toast.makeText(this,name+"先生,您的中国人民大学本科录取通知书已经办妥了..", 0).show();
		}
	}
4. 定义一个内部类
/**
	 * 内部招生老师,内部代理对象
	 */
	class MyBinder extends Binder{
		/**
		 * 内部人员中固有的方法,它的作用就让别人来访问它,然后它自己去访问服务中的方法。
		 * 通过迂回的手段达到从外部类调用服务中的方法效果。
		 * @param name
		 * @param money
		 */
		 public void callMethodInService(String name , int money){
			 methodInService(name , money);
		 }
	}
5. 服务绑定后返回内部代理对象
/**
	 * 如果服务成功绑定上了,那么就返回一个通讯频道,
	 * 返回一个内部人员,内部代理对象
	 */
	@Override
	public IBinder onBind(Intent intent) {
		System.out.println("onBind");
		//返回内部代理对象
		return new MyBinder();
	}
6. 在activity绑定服务
//绑定服务
	public void bind(View v) {
		Intent service = new Intent(this , ServcieDemo.class);
		/**
		 * 第一个参数:intent对象
		 * 第二个参数:servcieConnection  用于监听服务当前的状态
		 * 第三个参数:BIND_AUTO_CREATE 服务自动创建,然后绑定。
		 */
		bindService(service, new MyConn(),  BIND_AUTO_CREATE);
	}
7. 在onServcieConnected方法中获取到内部代理对象
/**
	 * 监听服务的状态,服务是启动还是停止都会收到信息。
	 */
	class MyConn implements ServiceConnection{
		/**
		 * 如果服务能够成功绑定上,那么这个方法将会调用,启动的参数service就是服务返回的内部对象 MyBinder
		 */
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			//获取到服务内部返回的代理对象 ,用binder承接起来
			binder = (MyBinder) service;
			
		}
		@Override
		public void onServiceDisconnected(ComponentName name) {}
	}
8. 在其他地方调用内部对象中的方法
	//调用服务的方法
	public void call(View v) {
		//通过内部代理对象,调用内部 类中的方法,实际上是调用了服务中的方法
		binder.callMethodInService("张三丰", 1000000);
	}
6.2 绑定服务的例子
public class ServiceDemo extends Service {
	/**
	 * 内部招生老师,内部代理对象
	 */
	class MyBinder extends Binder {
		/**
		 * 内部人员中固有的方法,它的作用就让别人来访问它,然后它自己去访问服务中的方法。 通过迂回的手段达到从外部类调用服务中的方法效果。
		 * 
		 * @param name
		 * @param money
		 */
		public void callMethodInService(String name, int money) {
			methodInService(name, money);
		}
	}
	/**
	 * 如果服务成功绑定上了,那么就返回一个通讯频道, 返回一个内部人员,内部代理对象
	 */
	@Override
	public IBinder onBind(Intent intent) {
		System.out.println("onBind");
		// 返回内部代理对象
		return new MyBinder();
	}
	
	@Override
	public void onCreate() {
		super.onCreate();
		System.out.println("onCreate---");
	}
	
	@Override
	public void onDestroy() {
		super.onDestroy();
		System.out.println("onDestroy---");
	}
	
	/**
	 * 录取通知书 服务中的内部方法
	 */
	public void methodInService(String name, int money) {
		if (money <= 100000) {
			Toast.makeText(this, name + ",你的钱不够.", 0).show();
		} else {
			Toast.makeText(this, name + "先生,您的中国人民大学本科录取通知书已经办妥了.2222.", 0).show();
		}
	}


}
<service android:name="com.heima.bindService.ServiceDemo"></service>
public class MainActivity extends Activity {
	MyBinder binder;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
   	/**
	 * 监听服务的状态,服务是启动还是停止都会收到信息。
	 */
    class Myconn implements ServiceConnection {
    	/**
		 * 如果服务能够成功绑定上,那么这个方法将会调用,启动的参数service就是服务返回的内部对象 MyBinder
		 */
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			binder = (MyBinder) service;
		}


		@Override
		public void onServiceDisconnected(ComponentName name) {
			
		}
    	
    }
    //绑定服务
    public void bind(View v) {
    	Intent service = new Intent(this, ServiceDemo.class);
    	/**
		 * 第一个参数:intent对象
		 * 第二个参数:servcieConnection  用于监听服务当前的状态
		 * 第三个参数:BIND_AUTO_CREATE 服务自动创建,然后绑定。
		 */
    	bindService(service, new Myconn(), BIND_AUTO_CREATE);
    }
    
    //调用服务的方法
    public void call(View v) {
    	//binder.博士招生("张三丰", 1000000);
    	//通过内部代理对象,调用内部 类中的方法,实际上是调用了服务中的方法
    	binder.callMethodInService("张三丰", 100000);
    }
    
    //解除绑定服务
    public void unbind(View v) {
    	
    }
}

6.3 绑定服务的生命周期
完整的生命周期:onCreate【创建】---onBind【绑定】 --onUnBind【解除绑定】--onDesotry【销毁】
多次绑定服务:不会调用任何服务中生命周期方法
多次解绑:将会抛出服务没有注册的异常,因为服务的绑定和解绑是根据conn对象来解析的。
多次绑定,一次解绑:将会抛出服务没有注册的异常
建议:服务绑定一次,解绑一次。
七、两种启动服务的区别
* startService
生命周期: onCreate---onStartCommand---onDestory
与服务的通讯: 无法与服务进行直接通讯
与开启者的关系: 服务一旦开启与开启者(activity)将没有什么联系了,就算开启者销毁了,服务依然存活。
在设置界面中有显示
* binderSerivce
生命周期: onCreate--onBind--onUnBind--onDestory
与服务通讯: 通过内部代理对象间接调用服务的方法
与开启者的关系: 一旦开启者销毁了,那么服务也将随之销毁。
在设置界面无显示
能不能让服务长期运行在后台,并且还能与服务进行通讯
startService : 让服务长期运行在后台,但是无法与服务进行通讯
bindServcie :  可以与服务进行通讯,但是无法长期运行在后台


八、混合开启服务
1. startService 启动服务
2. bindService 绑定服务
3. 调用服务的方法
4. unBindService 解除绑定服务
5. stopService 停止服务
注意:一定按流程进行,否则容易出事
##练习-使用混合开启服务去优化音乐播放器
1. 使用绑定服务的方式去播放音乐
2. 让音乐在后台运行,并且还能操作next -- pre [混合开启服务]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值