Android中的Service组件(二)

来源:互联网 发布:酷家乐软件好用吗 编辑:程序博客网 时间:2024/06/05 16:19
一、服务的概念
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 = "";@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn null;}@Overridepublic void onCreate() {super.onCreate();try {//1.创建一个多媒体播放器mediaPlayer = new MediaPlayer();//2. 设置播放的资源路径mediaPlayer.setDataSource(PATH);//3. 缓冲一下mediaPlayer.prepare();} catch (Exception e) {// TODO: handle exceptione.printStackTrace();}}@Overridepublic 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);}@Overridepublic 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 stubfinish();}});    dialog.setNegativeButton("否", new OnClickListener() {public void onClick(DialogInterface dialog, int which) {// TODO Auto-generated method stubstopService(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. 服务绑定后返回内部代理对象
/** * 如果服务成功绑定上了,那么就返回一个通讯频道, * 返回一个内部人员,内部代理对象 */@Overridepublic 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 */@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {//获取到服务内部返回的代理对象 ,用binder承接起来binder = (MyBinder) service;}@Overridepublic 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);}}/** * 如果服务成功绑定上了,那么就返回一个通讯频道, 返回一个内部人员,内部代理对象 */@Overridepublic IBinder onBind(Intent intent) {System.out.println("onBind");// 返回内部代理对象return new MyBinder();}@Overridepublic void onCreate() {super.onCreate();System.out.println("onCreate---");}@Overridepublic 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 */@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {binder = (MyBinder) service;}@Overridepublic 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 [混合开启服务]
原创粉丝点击