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)服务通 ...
随机推荐
- python代码规范整理
规范参考源: 1.pep8(python代码样式规范):中文文档 https://blog.csdn.net/ratsniper/article/details/78954852 2.pep ...
- Linux - 通过expect工具实现脚本的自动交互
目录 1 安装expect工具 2 expect的常用命令 3 作用原理简介 3.1 示例脚本 3.2 脚本功能解读 4 其他脚本使用示例 4.1 直接通过expect执行多条命令 4.2 通过she ...
- python方法的使用
1.函数定义 def 函数名(形参): 函数体 return 返回值 2.函数执行 ...
- eShopOnContainers部署在docker的坑
把eShopOnContainers(.net core 的版本是2.1)下载之后,部署到docker上,查看容器eShopOnContainers的项目都部署上去了. 用http://localho ...
- 2013-2014 ACM-ICPC Pacific Northwest Regional Contest L.Languages
题意略. 思路: 这种字符串的模拟题,应该熟练使用stringstream. 详见代码: #include<bits/stdc++.h> using namespace std; map& ...
- .NET平台下,钉钉微应用开发之:工作消息通知
首先看下官方文档,为我们提供了POST请求地址,和几个必传参数的列表以及参数示例,写的都挺详细的. 无奈提供的SDK请求示例是JAVA的,而我用的是.NET的,所以还是摸了一些坑出来,其实也就是不同平 ...
- vue实现对语言的切换,结合vue-il8n。
1.安装vue-i18n: npm install vue-i18n 如果npm长时间无反应,或安装失败,可以换成淘宝镜像安装: cnpm install vue-i18n 2.在main.js中引用 ...
- Reactive(2) 响应式流与制奶厂业务
目录 再谈响应式 为什么Web后端开发的,对 Reactive 没有感觉 Java 9 支持的 Reactive Stream 范例 小结 扩展阅读 再谈响应式 在前一篇文章从Reactive编程到& ...
- 阿里云(ecs服务器)使用1-安装Mongdb数据库以及远程部署
1.下载mongodb 百度云盘连接 :链接:https://pan.baidu.com/s/1b-hTS0XHQKpatecFoumLxw 提取码:z9ax 并送上可视化工具:链接:https:/ ...
- 【HDU5409】CRB and Graph 边双联通 子树最值
HDU # 题意 有一个简单图,n个点,m条边.对于每条割边,求出删去这条边后,在两个联通块中各取一个u,v.使得u<v,并且u尽量大而v尽量小. # 思路 求出边双联通是肯定的. 答案的限制条 ...