一、服务的概念
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 直接启动服务的例子:音乐播放器
五、直接启动服务的缺陷
6.1 绑定服务的步骤
1. 定义服务
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 [混合开启服务]
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 [混合开启服务]