Android服务之混合方式开启服务
引言
前面介绍过了Android服务的两种开启方式:Start方式可以让服务在后台运行;bind方式能够调用到服务中的方法。
在实际的开发工作中,有很多需求是:既要在后台能够长期运行,又要在服务中操作业务。那么就需要两种方式结合在一起,才能做到我们想要的结果。
需求:模仿音乐后台播放案例,实现应用退出后,服务中依然可以在后台运行。
代码如下
AndroidManifest.xml 清单文件中配置service
<service android:name=".service.music.MusicPlayService" />
MusicPlayService.class 自定义一个服务类
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Log;
/**
* 创建一个服务:模拟后台播放音乐(以控制台打印Log代替)
*/
public class MusicPlayService extends Service {
//音乐播放状态(播放:true; 暂停:false)
private boolean running = false;
@Override
public IBinder onBind(Intent intent) {
return new MusicBindImpl();
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
//服务中的方法:播放音乐
public void player() {
new Thread(new Runnable() {
@Override
public void run() {
running = true;
while (true) {
if (running) {
SystemClock.sleep(500);
Log.e("music", "音乐播放中...");
}
}
}
}).start();
}
//服务中的方法:继续播放
public void rePlayer() {
player();
}
//服务中的方法:暂停音乐
public void pause() {
running = false;
}
/**
* 创建中间帮助类对象
*/
class MusicBindImpl extends Binder implements IMusicService {
@Override
public void callPlayer() {
player();
}
@Override
public void callRePlayer() {
rePlayer();
}
@Override
public void callPause() {
pause();
}
}
}
IMusicService.interface 抽取一个接口封装方法
/**
* 定义一个接口,封装中间帮助类要实现的函数
*/
public interface IMusicService {
public void callPlayer();
public void callRePlayer();
public void callPause();
}
MusicServiceConnection.class 创建一个服务连接对象
import android.content.ComponentName;
import android.content.ServiceConnection;
import android.os.IBinder;
/**
* 定义服务连接对象,接收中间帮助类对象
*/
public class MusicServiceConnection implements ServiceConnection {
private MusicPlayService.MusicBindImpl musicBind;
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//获取:服务绑定成功后,返回的中间帮助类对象
this.musicBind = (MusicPlayService.MusicBindImpl) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
//暴露方法:获取中间帮助类对象
public MusicPlayService.MusicBindImpl getMusicBindImpl(){
return musicBind;
}
}
MusicPlayActivity.class
该类使用kotlin语言,模拟音乐 开、关、暂停、继续、退出 操作
/**
* 混合方式开启服务
*/
class MusicPlayActivity : BaseActivity() {
//意图,开启服务
private var musicIntent: Intent? = null
//服务连接对象
private var msconn: MusicServiceConnection? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_music_play)
startMusicService()
tvPlayer.setOnClickListener {
playerMethod()
}
tvPause.setOnClickListener {
pauseMethod()
}
tvRePlayer.setOnClickListener {
rePlayerMethod()
}
tvSignOut.setOnClickListener {
signOutMethod()
}
}
//开启服务
private fun startMusicService() {
//1. 使用start方式开启服务
musicIntent = Intent(this, MusicPlayService::class.java)
this.startService(musicIntent)
//2. 通过bind方式绑定该服务(同一个Intent对象)
if (msconn == null) {
//保证ServiceConnection连接对象的唯一性
msconn = MusicServiceConnection()
}
bindService(musicIntent, msconn, Context.BIND_AUTO_CREATE)
}
//播放
private fun playerMethod() {
msconn?.musicBindImpl?.callPlayer()
}
//暂停
private fun pauseMethod() {
msconn?.musicBindImpl?.callPause()
}
//继续
private fun rePlayerMethod() {
msconn?.musicBindImpl?.callRePlayer()
}
//退出(先暂停播放,在解绑,最后应用退出)
private fun signOutMethod() {
msconn?.musicBindImpl?.callPause()
//3. 解绑服务并停止服务
if (msconn != null) {
this.unbindService(msconn)
msconn = null
}
if (musicIntent != null) {
stopService(musicIntent)
}
this.finish()
}
override fun onDestroy() {
super.onDestroy()
if (msconn != null) {
this.unbindService(msconn)
msconn = null
}
musicIntent = null
}
}
代码流程补充说明:
- 创建一个Service,定义具体的操作。并创建一个中间人对象(中间帮助类),由中间对象调用Service内的方法(内部类的使用)。
- 创建Service连接对象,当Service绑定成功后,接收中间人对象。
- 在Activity中开启服务,获取中间人对象,通过中间人对象执行Service内的方法
- 先以 start方式开启服务:。目的:让服务可以在后台运行。
- 再以 bind方式开启服务。目的:能够调用到服务中的方法。
- unbind 解绑服务。(解绑后切记把ServiceConnection对象置null,避免运行异常)
- stopService终止服务。(用户主动关闭服务执行该操作)
PS:
- 混合方式开启的服务虽然可以做到后台运行,但并不是不能被Kill掉,假如整个应用程序的进程被Kill掉了,那么服务就会结束。
- 平常我们操作退出应用,应用的进程只是从前台进程变成了后台进程,并没有直接被kill掉,所以我们的服务还能够运行。
- 如果想要服务即便是在应用进程被kill掉的情况下依然可以运行,那么就需要做"服务后台保活"的操作。
这里先提供一个方案:在代码中定义两个Service,如:ServiceA,ServiceB,当ServiceA执行onDestroy时,让ServiceA开启ServiceB,当ServiceB执行onDestroy时,再让ServiceB开启ServiceA。这样两个服务相互开启,就会一直有一个服务在运行中。(具体的代码操作,后面我抽时间会写一个案例贴出了,大家一起探讨)
Android服务之混合方式开启服务的更多相关文章
- Android(java)学习笔记231:服务(service)之混合方式开启服务
1. 前面我们已经讲过可以使用两种方式开启服务 startService----stopService: oncreate() ---> onstartCommand() ---& ...
- Android(java)学习笔记174:服务(service)之混合方式开启服务
1. 前面我们已经讲过可以使用两种方式开启服务 startService----stopService: oncreate() ---> onstartCommand() ---& ...
- Android -- service的开启方式, start开启和绑定开启服务,调用服务的的方法, aidl调用远程服务
1. 概述 bindService() 绑定服务 可以得到服务的代理人对象,间接调用服务里面的方法. 绑定服务: 间接调用服务里面的方法. 如果调用者activity被销毁了, ...
- [android] 绑定方式开启服务&调用服务的方法
需求:后台开启一个唱歌服务,这个服务里面有个方法切换歌曲 新建一个SingService继承系统Service 重写onCreate()和onDestory()方法 填一个自定义的方法changeSi ...
- Android使用bindService作为中间人对象开启服务
Android使用bindService作为中间人对象开启服务 项目结构如下: MyService: package com.demo.secondservice; import android.ap ...
- Android入门:绑定本地服务
一.绑定服务介绍 前面文章中讲过一般的通过startService开启的服务,当访问者关闭时,服务仍然存在: 但是如果存在这样一种情况:访问者需要与服务进行通信,则我们需要将访问者与服务进行绑定: ...
- Android 程式开发:(廿二)服务 —— 22.1 自定义服务
服务,就是跑在后台的“程序”,不需要和用户进行交互.举个例子,当使用一款应用的时候,可能同时想在后台播放一些音乐.在这种情况下,后来播放音乐的代码不需要和用户进行交互,所以,它就可能被当成一个服务.当 ...
- Android ListView分页载入(服务端+android端)Demo
Android ListView分页载入功能 在实际开发中经经常使用到,是每一个开发人员必须掌握的内容,本Demo给出了服务端+Android端的两者的代码,并成功通过了測试. 服务端使用MyEcli ...
- start方式开启服务的特点&bindService 方式开启服务的特点
服务是在后台运行 可以理解成是没有界面的activity 定义四大组件的方式都是一样的 定义一个类继承Service start方式开启服务的特点 特点: (1)服务通 ...
随机推荐
- c++智能指针介绍
C++11标准引入了boost库中的智能指针,给C++开发时的内存管理提供了极大的方便.接下来这篇文件介绍shared_ptr/weak_ptr内部实现原理及使用细节. C++不像java有内存回收机 ...
- 一个简单的Python调度器Schedule
关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...
- Python+Selenium - Web自动化测试(二):元素定位
前言 前面已经把环境搭建好了,现在开始使用 Selenium 中的 Webdriver 框架编写自动化代码脚本,我们常见的在浏览器中的操作都会有相对应的类方法,这些方法需要定位才能操作元素,不同网页的 ...
- unity编辑器扩展_02(分别在Hierarchy,Project中创建一个选项)
在Hierarchy面板创建选项的代码: [MenuItem("GameObject/Test",false,1)] static void Test1() { ...
- [Python] Django框架入门3——深入视图
说明: 本文主要深入了解视图(views.py),涉及路由配置.定义视图.Request对象.Response对象.状态保持等. 一.路由配置 1.配置位置(settings.py 的 ROOT_UR ...
- switch语句(下)(转载)
之前我们介绍了在switch语句中使用整数类型和枚举类型的情况.这一部分继续介绍使用string类型的情况.string类型是switch语句接受的唯一一种引用类型参数. 下面来看一段C#代码. 代码 ...
- helm部署Redis哨兵集群
介绍 Redis Sentinel集群是由若干Sentinel节点组成的分布式集群,可以实现故障发现.故障自动转移.配置中心和客户端通知. 如下图: Redis Sentinel 故障转移过程: 从这 ...
- qt学习笔记(1):qt点击运行没有反应。
因为公司的项目需要,今天开始重新学习已经忘干净了的QT, 说起qt之前在学校刚接触的时候就打心底里喜欢这个编辑器, 因为一直使用vs做项目,面对着黑洞洞的窗口总让人不舒服, 自从接触了qt感觉迎来了曙 ...
- Delphi - cxGrid颜色显示相关设置
1:单元格的值满足某个条件时,该单元格所在整行颜色设置整行字体设置 选中cxGridDBTableView,单击F11调出属性配置面板,在Events中双击OnCustomDrawCell后双击编辑重 ...
- iOS仿写下厨房
把之前简书的博客搬到博客园了,还是放在一个地方看着舒服. 先看一下做的效果,是不是还不错?(可以看一下早餐那块的轮播,上面盖着一个都是点点的图片,但是它不是和轮播一起滚动的,是盖在轮播上面的,需要在那 ...