Android服务

android 的服务有点类似windows的服务,没有界面,在后台长时间运行,如果我们这种需求的话我们就可以使用服务来实现。

服务的典型应用场景: 播放音乐,下载等,如果要在一个广播接收者中执行一些耗时的操作,可以将此操作转交给服务来执行。

服务也有自己的生命周期,但是要是相对Activity要少了许多。

服务的生命周期

图片来自于官方文档

使用服务

如果你想要使用服务,那么必须要有一个来继承【Service 】类,并且在清单文件中配置他。

配置服务:在清单文件中对服务进行配置

  1. <!--配置一个服务,与Activity的配置基本相同,都可以具有Intent-Filter-->
  2. <service android:name=".MyService">
  3. <intent-filter>
  4. <action android:name="MyAction" />
  5. </intent-filter>
  6. </service>

建立服务类: 新建一个类继承自Service

  1. public class MyService extends Service {
  2. @Nullable
  3. @Override
  4. public IBinder onBind(Intent intent) {
  5. return null;
  6. }
  7. }

startService 的方式开始服务

  • 一旦开启就会长久的存在,就算是没有界面了那么也会在后台运行,没有界面的时候就会是一个服务进程,如果没有特殊的情况下次进程是不会被结束的,除非 用户手动停止或者调用onStop() 方法。
  • 可以多次开启,如果点击按钮开启服务多次点击按钮的话就会执行多次的onStartCommand方法,但是onCreate方法仅仅执行一次。
  • 用户可以再设置中查看通过此方式开启的服务
  1. public class MainActivity extends AppCompatActivity {
  2. private Intent intentService;
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_main);
  7. intentService = new Intent(this, PhoneListenerService.class);
  8. }
  9. //开启个服务
  10. public void click(View v) {
  11. this.startService(this.intentService);
  12. }
  13. //停止服务
  14. public void click2(View v) {
  15. this.stopService(this.intentService);
  16. }

bindService 的方式开启服务

  • 一般在Activity中开启,如果activity销毁了那么通过此方式绑定服务也会跟着销毁在activity销毁之前要先解绑服务
  • 这种方式开启的服务用户在设置中是无法看到的。
  1. public class Main1Activity extends AppCompatActivity {
  2. private Intent serviceIntent;
  3. private MyServiceConnection conn;
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.activity_main1);
  8. serviceIntent = new Intent(this, MyService.class);
  9. conn = new MyServiceConnection();
  10. }
  11. //绑定一个服务
  12. public void click3(View v) {
  13. this.bindService(this.serviceIntent, this.conn, BIND_AUTO_CREATE);
  14. }
  15. @Override
  16. protected void onDestroy() {
  17. super.onDestroy();
  18. unbindService(this.conn);
  19. }
  20. }
  21. class MyServiceConnection implements ServiceConnection {
  22. //当服务连接成功后会调用此方法
  23. @Override
  24. public void onServiceConnected(ComponentName name, IBinder service) {
  25. LogHelper.Logi("连接到服务");
  26. }
  27. //当失去连接的时候回调用此方法
  28. @Override
  29. public void onServiceDisconnected(ComponentName name) {
  30. LogHelper.Logi("取消连接");
  31. }
  32. }
为什么要有Bind方式开启服务

下面我们有这么个需求,我要调用服务里面的方法。

正常的调用方式

服务代码

  1. public class MyService extends Service {
  2. @Nullable
  3. @Override
  4. public IBinder onBind(Intent intent) {
  5. LogHelper.LogI("onBind");
  6. return null;
  7. }
  8. @Override
  9. public void onCreate() {
  10. super.onCreate();
  11. LogHelper.LogI("onCreate");
  12. }
  13. @Override
  14. public int onStartCommand(Intent intent, int flags, int startId) {
  15. LogHelper.LogI("onStartCommand");
  16. return super.onStartCommand(intent, flags, startId);
  17. }
  18. @Override
  19. public void onDestroy() {
  20. super.onDestroy();
  21. LogHelper.LogI("onDestory");
  22. }
  23. //我想在activity中调用的方法
  24. public void showToast() {
  25. Toast.makeText(this.getApplicationContext(), "Toast", Toast.LENGTH_SHORT).show();
  26. }
  27. }

调用代码

  1. public class Main1Activity extends AppCompatActivity {
  2. private Intent serviceIntent;
  3. private MyServiceConnection conn;
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.activity_main1);
  8. serviceIntent = new Intent(this, MyService.class);
  9. conn = new MyServiceConnection();
  10. //绑定服务
  11. bindService(this.serviceIntent, conn, BIND_AUTO_CREATE);
  12. }
  13. /*
  14. * 直接通过new出来对象的方式来调用服务中的方法
  15. * */
  16. public void click(View v) {
  17. new MyService().showToast();
  18. }
  19. @Override
  20. protected void onDestroy() {
  21. super.onDestroy();
  22. unbindService(this.conn);
  23. }
  24. }
  25. class MyServiceConnection implements ServiceConnection {
  26. @Override
  27. public void onServiceConnected(ComponentName name, IBinder service) {
  28. }
  29. @Override
  30. public void onServiceDisconnected(ComponentName name) {
  31. }
  32. }
总结

这样的方式调用service中的方法,就会直接挂掉.....,因为如果这样直接new出来的服务类的话,系统就会将他当成一个普通的java类来处理,在普通的java类中是不能获得上下文对象的,所以就不能弹出吐司,如果没有涉及的上下文的方法,那么这样是可以执行的。

解决办法

通过一个中间人来调用我们想要调用的方法

服务端代码

  1. public class MyService extends Service {
  2. /*
  3. * 通过bind方式开启服务 会执行onCreate()->onBind()方法
  4. * 此方法返回我们需要的中间人,来调用服务中的方法
  5. * */
  6. @Nullable
  7. @Override
  8. public IBinder onBind(Intent intent) {
  9. LogHelper.LogI("onBind");
  10. return new MyBinder();
  11. }
  12. @Override
  13. public void onCreate() {
  14. super.onCreate();
  15. LogHelper.LogI("onCreate");
  16. }
  17. @Override
  18. public int onStartCommand(Intent intent, int flags, int startId) {
  19. LogHelper.LogI("onStartCommand");
  20. return super.onStartCommand(intent, flags, startId);
  21. }
  22. @Override
  23. public void onDestroy() {
  24. super.onDestroy();
  25. LogHelper.LogI("onDestory");
  26. }
  27. //我们想要调用的方法
  28. public void showToast() {
  29. Toast.makeText(this.getApplicationContext(), "Toast", Toast.LENGTH_SHORT).show();
  30. }
  31. /*
  32. * 定义中间人
  33. * 间接的调用我们想要调用的方法
  34. * */
  35. public class MyBinder extends Binder {
  36. public void callShowToast() {
  37. showToast();
  38. }
  39. }
  40. }

Activity代码

  1. public class Main1Activity extends AppCompatActivity {
  2. private Intent serviceIntent;
  3. private MyServiceConnection conn;
  4. private MyService.MyBinder callBinder;
  5. @Override
  6. protected void onCreate(Bundle savedInstanceState) {
  7. super.onCreate(savedInstanceState);
  8. setContentView(R.layout.activity_main1);
  9. serviceIntent = new Intent(this, MyService.class);
  10. conn = new MyServiceConnection();
  11. //绑定服务
  12. bindService(this.serviceIntent, conn, BIND_AUTO_CREATE);
  13. }
  14. /*
  15. * 通过定义的中间人来调用方法
  16. * */
  17. public void click(View v) {
  18. this.callBinder.callShowToast();
  19. }
  20. @Override
  21. protected void onDestroy() {
  22. super.onDestroy();
  23. unbindService(this.conn);
  24. }
  25. public class MyServiceConnection implements ServiceConnection {
  26. /*
  27. * 当连接到服务的时候就会执行此方法,在这个方法拿到我们的中间人用来调用我们想要调用的方法
  28. * service参数就是我们想要的中间人
  29. * */
  30. @Override
  31. public void onServiceConnected(ComponentName name, IBinder service) {
  32. callBinder = (MyService.MyBinder) service;
  33. }
  34. @Override
  35. public void onServiceDisconnected(ComponentName name) {
  36. }
  37. }
  38. }

混合方式绑定服务

现在有一种情况,如果我要做一个音乐盒的功能那么我必须在所有界面都退出了还能播放那么这时候,我们一定是要有一个startService方式开启的服务来一直播放音乐, 但是我得需要调用服务中的方法来控制音乐的播放和暂停等,这就需要混合方式开启服务了。

混合方式开启服务的步骤

  • startService()
  • bindService()
  • unbiasedServices()
  • stopService()
Demo 音乐播放器 案例

服务的代码

  1. public class MusicService extends Service {
  2. private boolean isPlay = true;
  3. private boolean isDestroy = false;
  4. public MusicService() {
  5. }
  6. @Override
  7. public IBinder onBind(Intent intent) {
  8. LogHelper.LogI("onBind");
  9. return new MyBinder();
  10. }
  11. @Override
  12. public void onCreate() {
  13. LogHelper.LogI("onCreate!");
  14. super.onCreate();
  15. }
  16. @Override
  17. public int onStartCommand(Intent intent, int flags, int startId) {
  18. LogHelper.LogI("onStart");
  19. playMusic();
  20. return super.onStartCommand(intent, flags, startId);
  21. }
  22. //在服务被销毁的时候,结束线程
  23. @Override
  24. public void onDestroy() {
  25. LogHelper.LogI("onDestory");
  26. this.isDestroy = true;
  27. super.onDestroy();
  28. }
  29. //开启线程不停的播放音乐
  30. public void playMusic() {
  31. new Thread(new Runnable() {
  32. @Override
  33. public void run() {
  34. while (!isDestroy)
  35. if (isPlay) {
  36. LogHelper.LogI("Play Music!");
  37. SystemClock.sleep(1000);
  38. }
  39. }
  40. }).start();
  41. }
  42. //暂停音乐播放
  43. public void stopMusic() {
  44. this.isPlay = false;
  45. LogHelper.LogI("暂停播放音乐!");
  46. }
  47. //继续播放音乐
  48. public void continueMusic() {
  49. this.isPlay = true;
  50. LogHelper.LogI("继续播放音乐!");
  51. }
  52. //用来调用服务的方法的中间人
  53. private class MyBinder extends Binder implements IMusicControlAble {
  54. @Override
  55. public void callStopMusic() {
  56. stopMusic();
  57. }
  58. @Override
  59. public void callContinueMusic() {
  60. continueMusic();
  61. }
  62. }
  63. }

IMusicControlAble接口代码

  1. public interface IMusicControlAble {
  2. //暂停音乐播放
  3. public void callStopMusic();
  4. //继续播放音乐
  5. public void callContinueMusic();
  6. }

MainActivity的代码

  1. public class Main1Activity extends AppCompatActivity {
  2. private Intent intentMusicService;
  3. private MyServiceConnection connMusicService;
  4. private IMusicControlAble musicControl;
  5. @Override
  6. protected void onCreate(Bundle savedInstanceState) {
  7. super.onCreate(savedInstanceState);
  8. setContentView(R.layout.activity_main1);
  9. intentMusicService = new Intent(this, MusicService.class);
  10. connMusicService = new MyServiceConnection();
  11. this.bindService(this.intentMusicService, this.connMusicService, BIND_AUTO_CREATE);
  12. this.startService(this.intentMusicService);
  13. }
  14. public void click(View v) {
  15. Button btn = (Button) v;
  16. switch (btn.getText().toString()) {
  17. case "暂停":
  18. this.musicControl.callStopMusic();
  19. btn.setText("播放");
  20. break;
  21. case "播放":
  22. this.musicControl.callContinueMusic();
  23. btn.setText("暂停");
  24. break;
  25. }
  26. }
  27. //接触对服务的绑定
  28. @Override
  29. protected void onDestroy() {
  30. this.unbindService(this.connMusicService);
  31. super.onDestroy();
  32. }
  33. public class MyServiceConnection implements ServiceConnection {
  34. //拿到用来控制音乐状态的接口
  35. @Override
  36. public void onServiceConnected(ComponentName name, IBinder service) {
  37. musicControl = (IMusicControlAble) service;
  38. }
  39. @Override
  40. public void onServiceDisconnected(ComponentName name) {
  41. }
  42. }
  43. }

Android四大组件-服务的更多相关文章

  1. 入职小白随笔之Android四大组件——服务(Service)

    Service Android多线程编程 当我们在程序中执行一些耗时操作时,比如发起一条网络请求,考虑到网速等原因,服务器未必会立刻响应我们的请求,此时我们就需要将这些操作放在子线程中去运行,以防止主 ...

  2. Android四大组件--服务(Service)

    1. startService和bindService的区别 1. startService: 生命周期: onCreate---onStartCommand---onDestory 与服务的通讯: ...

  3. Android四大组件之一“广播”

    前言 Android四大组件重要性已经不言而喻了,今天谈谈的是Android中的广播机制.在我们上学的时候,每个班级的教室里都会装有一个喇叭,这些喇叭都是接入到学校的广播室的,一旦有什么重要的通知,就 ...

  4. Android 四大组件 与 MVC 架构模式

    作为一个刚从JAVA转过来的Android程序员总会思考android MVC是什么样的? 首先,我们必须得说Android追寻着MVC架构,那就得先说一下MVC是个啥东西! 总体而来说MVC不能说是 ...

  5. android四大组件(简单总结)

    activity 一个Activity通常就是一个单独的屏幕(窗口) Activity之间通过Intent进行通信 android应用中每一个Activity都必须要在AndroidManifest. ...

  6. Android 四大组件之再论service

    service常见的有2种方式,本地service以及remote service. 这2种的生命周期,同activity的通信方式等,都不相同. 关于这2种service如何使用,这里不做介绍,只是 ...

  7. Android四大组件及activity的四大启动模式

    Android四大组件 1. 广播接收者的两种类型: (1)系统广播接收者,就是继承BroadcastReceiver这个类,然后还要在清单文件中注册,注册之后给他一个action.当系统发生了这个a ...

  8. Android成长日记-Android四大组件之Service组件的学习

    1.什么是Service? Service是Android四大组件中与Activity最相似的组件,它们都代表可执行的程序,Service与Activity的区别在于:Service一直在后台运行,它 ...

  9. Android四大组件之Service

    Android四大组件之Service Android支持服务的概念,服务是在后台运行的组件,没有用户界面,Android服务可用有与活动独立的生命周期.Android支持两种类型的服务: 本地服务: ...

随机推荐

  1. c++模板函数作为参数的疑惑

    为什么22行只能传一个模板函数作为参数,而非模板却编译失败,求解释.

  2. 20145202马超 2016-2017-2 《Java程序设计》第5周学习总结

    20145202马超 2016-2017-2 <Java程序设计>第5周学习总结 教材学习内容总结 异常:程序在运行的时候出现不正正常的情况 由来:问题也是可以通过java对不正常情况进行 ...

  3. Ubuntu下hadoop环境的搭建(伪分布模式)

    Ubuntu下hadoop环境的搭建(伪分布模式) 一.必要资源的下载 1.Java jdk(jdk-8u25-linux-x64.tar.gz)的下载 具体链接为: http://www.oracl ...

  4. APScheduler API -- apscheduler.triggers.date

    apscheduler.triggers.date API Trigger alias for add_job(): date class apscheduler.triggers.date.Date ...

  5. C# Java 加密解密

    C# AES加密解密 public static string Encrypt(string key, string clearText) { byte[] clearBytes = Encoding ...

  6. USB descriptor【转】

    struct usb_device_descriptor { __u8 bLength;//设备描述符的字节数大小,为0x12 __u8 bDescriptorType;//描述符类型编号,为0x01 ...

  7. nginx自定义500,502,504错误页面无法跳转【转】

    1.自定一个页面,这个页面是一个链接地址可以直接访问的. 以下是nginx的配置: location / {            proxy_pass http://tomcat_app108;   ...

  8. 10 The Go Programming Language Specification go语言规范 重点

    The Go Programming Language Specification go语言规范 Version of May 9, 2018 Introduction 介绍 Notation 符号 ...

  9. 数据库-mysql事务

    MySQL 事务 MySQL 事务主要用于处理操作量大,复杂度高的数据.比如说,在人员管理系统中,你删除一个人员,你即需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数 ...

  10. TF-搞不懂的TF矩阵加法

    看谷歌的demo mnist,卷积后加偏执量的代码 h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)h_pool1 = max_pool ...