基础总结篇:Service完全解析

  1. }

  2. };

  3. /**

  4. * 绑定服务

  5. * @param view

  6. */

  7. public void bind(View view) {

  8. Intent intent = new Intent(this, MyService.class);

  9. bindService(intent, conn, Context.BIND_AUTO_CREATE);

  10. }

  11. /**

  12. * 解除绑定

  13. * @param view

  14. */

  15. public void unbind(View view) {

  16. unbindService(conn);

  17. }

private ServiceConnection conn = new ServiceConnection() {

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

//connected

Log.i(TAG, “onServiceConnected called.”);

}

/**

  • Called when a connection to the Service has been lost.

  • This typically happens when the process hosting the service has crashed or been killed.

  • This does not remove the ServiceConnection itself.

  • this binding to the service will remain active,

  • and you will receive a call to onServiceConnected when the Service is next running.

*/

@Override

public void onServiceDisconnected(ComponentName name) {

}

};

/**

  • 绑定服务

  • @param view

*/

public void bind(View view) {

Intent intent = new Intent(this, MyService.class);

bindService(intent, conn, Context.BIND_AUTO_CREATE);

}

/**

  • 解除绑定

  • @param view

*/

public void unbind(View view) {

unbindService(conn);

}

在使用bindService绑定服务时,我们需要一个ServiceConnection代表与服务的连接,它只有两个方法,onServiceConnected和onServiceDisconnected,前者是在操作者在连接一个服务成功时被调用,而后者是在服务崩溃或被杀死导致的连接中断时被调用,而如果我们自己解除绑定时则不会被调用,所以我们这里只研究onServiceConnected这个方法。

看样子是可以去绑定一个服务了,其实还不行,因为我们前面服务中的onBind方法返回值为null,这样是不行的,要想实现绑定操作,必须返回一个实现了IBinder接口类型的实例,该接口描述了与远程对象进行交互的抽象协议,有了它我们才能与服务进行交互。我们于是有了这样的代码:

[java] view plain copy print ?

  1. @Override

  2. public IBinder onBind(Intent intent) {

  3. Log.i(TAG, “onBind called.”);

  4. return new Binder() {};

  5. }

@Override

public IBinder onBind(Intent intent) {

Log.i(TAG, “onBind called.”);

return new Binder() {};

}

我们返回了一个Binder的实例,而这个Binder恰恰是实现了IBinder接口,所以这样就可以实现绑定服务的操作了,一起来演示一下。

先点击一下绑定按钮,我们会发现在MainActivity中打印日志如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

似的,onServiceConnected方法被调用了,看来绑定连接已经成功了,看看MyService如何:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

onCreate方法和onBind方法被调用了,此时服务已进入运行阶段,如果再次点击绑定按钮,onCreate和onBinder并不会再次被调用,这个过程中它们仅被调用一次。

然后点击解除绑定按钮,我们会发现MyService打印如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

可以看到onUnbind方法和onDestroy方法被调用了,此时MyService已被销毁,整个生命周期结束。

另一方面,当我们退出MainActivity时,服务也会随之而结束,从这一点上看,MyService可以说是誓死追随着MainActivity。

需要注意的是,在连接中断状态再去做解除绑定操作会引起一个异常,在MainActivity销毁之前没有进行解除绑定也会导致后台出现异常信息,此时我们就要想办法确保不会出现此类情况,可以这样做:

[java] view plain copy print ?

  1. private boolean binded;

  2. @Override

  3. public void onServiceConnected(ComponentName name, IBinder service) {

  4. binded = true;

  5. }

  6. /**

  7. * 解除绑定

  8. * @param view

  9. */

  10. public void unbind(View view) {

  11. unbindService();

  12. }

  13. @Override

  14. protected void onDestroy() {

  15. super.onDestroy();

  16. unbindService();

  17. }

  18. /**

  19. * 解除服务绑定

  20. */

  21. private void unbindService() {

  22. if (binded) {

  23. unbindService(conn);

  24. binded = false;

  25. }

  26. }

private boolean binded;

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

binded = true;

}

/**

  • 解除绑定

  • @param view

*/

public void unbind(View view) {

unbindService();

}

@Override

protected void onDestroy() {

super.onDestroy();

unbindService();

}

/**

  • 解除服务绑定

*/

private void unbindService() {

if (binded) {

unbindService(conn);

binded = false;

}

}

以上就是bindService的生命周期,正如我们上面讲的一样,使用bindService启动服务后调用者和服务绑定到了一起,当调用者被销毁,服务也立即结终止。

通常情况下是这样的,不过也有特殊情况。当startService和bindService在同一场合下使用时,就会出现稍微不同的现象。

如果我们先以startService方式启动服务,然后再用bindService绑定到这个服务,之后使用unbindService解除绑定,此时服务并不会因此而终止,而是继续运行,直到我们使用stopService来停止这个服务。下面我们再修改一下代码以验证这个过程。MyService保持不变,我们只需修改一下MainActivity。MainActivity最新代码如下:

[java] view plain copy print ?

  1. package com.scott.service;

  2. import android.app.Activity;

  3. import android.content.ComponentName;

  4. import android.content.Context;

  5. import android.content.Intent;

  6. import android.content.ServiceConnection;

  7. import android.os.Bundle;

  8. import android.os.IBinder;

  9. import android.util.Log;

  10. import android.view.View;

  11. public class MainActivity extends Activity {

  12. private static final String TAG = “MainActivity”;

  13. @Override

  14. public void onCreate(Bundle savedInstanceState) {

  15. super.onCreate(savedInstanceState);

  16. setContentView(R.layout.main);

  17. }

  18. private ServiceConnection conn = new ServiceConnection() {

  19. @Override

  20. public void onServiceConnected(ComponentName name, IBinder service) {

  21. Log.i(TAG, “onServiceConnected called.”);

  22. }

  23. @Override

  24. public void onServiceDisconnected(ComponentName name) {

  25. }

  26. };

  27. /**

  28. * 启动服务

  29. * @param view

  30. */

  31. public void start(View view) {

  32. Intent intent = new Intent(this, MyService.class);

  33. startService(intent);

  34. }

  35. /**

  36. * 绑定服务

  37. * @param view

  38. */

  39. public void bind(View view) {

  40. Intent intent = new Intent(this, MyService.class);

  41. bindService(intent, conn, Context.BIND_AUTO_CREATE);

  42. }

  43. /**

  44. * 解除绑定

  45. * @param view

  46. */

  47. public void unbind(View view) {

  48. unbindService(conn);

  49. }

  50. /**

  51. * 停止服务

  52. * @param view

  53. */

  54. public void stop(View view) {

  55. Intent intent = new Intent(this, MyService.class);

  56. stopService(intent);

  57. }

  58. }

package com.scott.service;

import android.app.Activity;

import android.content.ComponentName;

import android.content.Context;

import android.content.Intent;

import android.content.ServiceConnection;

import android.os.Bundle;

import android.os.IBinder;

import android.util.Log;

import android.view.View;

public class MainActivity extends Activity {

private static final String TAG = “MainActivity”;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

}

private ServiceConnection conn = new ServiceConnection() {

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

Log.i(TAG, “onServiceConnected called.”);

}

@Override

public void onServiceDisconnected(ComponentName name) {

}

};

/**

  • 启动服务

  • @param view

*/

public void start(View view) {

Intent intent = new Intent(this, MyService.class);

startService(intent);

}

/**

  • 绑定服务

  • @param view

*/

public void bind(View view) {

Intent intent = new Intent(this, MyService.class);

bindService(intent, conn, Context.BIND_AUTO_CREATE);

}

/**

  • 解除绑定

  • @param view

*/

public void unbind(View view) {

unbindService(conn);

}

/**

  • 停止服务

  • @param view

*/

public void stop(View view) {

Intent intent = new Intent(this, MyService.class);

stopService(intent);

}

}

在MainActivity中包含了四个按钮事件,分别是startService、bindService、unbindService和stopService,我们逐一地按下,看看都发生了什么。

首先按下启动服务的按钮,MyService打印如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

恩,意料之中。然后我们再按下绑定服务的按钮,MyService打印如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

此时,只有onBind被调用,之后两者就绑定成功。我们再按下解除绑定的按钮,MyService打印如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

此时,onUnbind方法方法被调用,注意,此时MyService并没有因解除绑定而终止,而是继续运行。也许我们心里会问,如果多次按下绑定服务的按钮或重复以上两个步骤,结果如何呢?答案是onBind和onUnbind都不会再被调用了。看不到onBind被调用,是不是没有绑定成功啊,我们来看一下MainActivity打印信息:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

重复按下绑定按钮,几次都绑定成功了。最后我们按下停止服务的按钮,MyService打印如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

此时,onDestroy被调用了,此时MyService停止了运行,整个生命周期结束。

以上就是关于MyService生命周期的讲解,下面我们来介绍一下如何与服务进行通信。与服务之间的通信可以分为两种,进程内的通信和进程间的通信,前者调用者和服务在同一应用进程内,而后者是分布在不同应用进程中的。

2.进程内与服务通信

进程内与服务通信实际上就是通过bindService的方式与服务绑定,获取到通信中介Binder实例,然后通过调用这个实例的方法,完成对服务的各种操作。我们上面也介绍了不少关于bindService的内容,下面我们就针对实际需求对代码做改动。首先是MyService,代码如下:

[java] view plain copy print ?

  1. package com.scott.service;

  2. import android.app.Service;

  3. import android.content.Intent;

  4. import android.os.Binder;

  5. import android.os.IBinder;

  6. import android.util.Log;

  7. public class MyService extends Service {

  8. private static final String TAG = “MyService”;

  9. @Override

  10. public IBinder onBind(Intent intent) {

  11. Log.i(TAG, “onBind called.”);

  12. return new MyBinder();

  13. }

  14. /**

  15. * 绑定对象

  16. * @author user

  17. *

  18. */

  19. public class MyBinder extends Binder {

  20. /**

  21. * 问候

  22. * @param name

  23. */

  24. public void greet(String name) {

  25. Log.i(TAG, "hello, " + name);

  26. }

  27. }

  28. }

package com.scott.service;

import android.app.Service;

import android.content.Intent;

import android.os.Binder;

import android.os.IBinder;

import android.util.Log;

public class MyService extends Service {

private static final String TAG = “MyService”;

@Override

public IBinder onBind(Intent intent) {

Log.i(TAG, “onBind called.”);

return new MyBinder();

}

/**

  • 绑定对象

  • @author user

*/

public class MyBinder extends Binder {

/**

  • 问候

  • @param name

*/

public void greet(String name) {

Log.i(TAG, "hello, " + name);

}

}

}

我们创建了一个MyBinder的内部类,定义了一个greet方法,在onBind方法中就将这个MyBinder的实例返回,只要调用者获取到这个实例,就可以像拿着游戏手柄一样对服务进行操作。我们来看一下调用者的代码吧,MainActivity代码如下:

[java] view plain copy print ?

  1. package com.scott.service;

  2. import android.app.Activity;

  3. import android.content.ComponentName;

  4. import android.content.Context;

  5. import android.content.Intent;

  6. import android.content.ServiceConnection;

  7. import android.os.Bundle;

  8. import android.os.IBinder;

  9. import android.view.View;

  10. public class MainActivity extends Activity {

  11. /**

  12. * 绑定对象实例

  13. */

  14. private MyService.MyBinder binder;

  15. @Override

  16. public void onCreate(Bundle savedInstanceState) {

  17. super.onCreate(savedInstanceState);

  18. setContentView(R.layout.main);

  19. }

  20. private ServiceConnection conn = new ServiceConnection() {

  21. @Override

  22. public void onServiceConnected(ComponentName name, IBinder service) {

  23. binder = (MyService.MyBinder) service;  //获取其实例

  24. binder.greet(“scott”);                  //调用其方法

  25. }

  26. @Override

  27. public void onServiceDisconnected(ComponentName name) {

  28. }

  29. };

  30. /**

  31. * 绑定服务

  32. * @param view

  33. */

  34. public void bind(View view) {

  35. Intent intent = new Intent(this, MyService.class);

  36. bindService(intent, conn, Context.BIND_AUTO_CREATE);

  37. }

  38. /**

  39. * 解除绑定

  40. * @param view

  41. */

  42. public void unbind(View view) {

  43. unbindService(conn);

  44. }

  45. }

package com.scott.service;

import android.app.Activity;

import android.content.ComponentName;

import android.content.Context;

import android.content.Intent;

import android.content.ServiceConnection;

import android.os.Bundle;

import android.os.IBinder;

import android.view.View;

public class MainActivity extends Activity {

/**

  • 绑定对象实例

*/

private MyService.MyBinder binder;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

}

private ServiceConnection conn = new ServiceConnection() {

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

binder = (MyService.MyBinder) service; //获取其实例

binder.greet(“scott”); //调用其方法

}

@Override

public void onServiceDisconnected(ComponentName name) {

}

};

/**

  • 绑定服务

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
layout.main);

}

private ServiceConnection conn = new ServiceConnection() {

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

binder = (MyService.MyBinder) service; //获取其实例

binder.greet(“scott”); //调用其方法

}

@Override

public void onServiceDisconnected(ComponentName name) {

}

};

/**

  • 绑定服务

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-DR0OTckW-1715887787664)]

[外链图片转存中…(img-wYKLlVQb-1715887787664)]

[外链图片转存中…(img-dcdIodN8-1715887787665)]

[外链图片转存中…(img-EWVfdpxU-1715887787666)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值