引言

前面介绍过了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内的方法
      1. 先以 start方式开启服务:。目的:让服务可以在后台运行。
      1. 再以 bind方式开启服务。目的:能够调用到服务中的方法。
      1. unbind 解绑服务。(解绑后切记把ServiceConnection对象置null,避免运行异常)
      1. stopService终止服务。(用户主动关闭服务执行该操作)

PS:

  • 混合方式开启的服务虽然可以做到后台运行,但并不是不能被Kill掉,假如整个应用程序的进程被Kill掉了,那么服务就会结束。
  • 平常我们操作退出应用,应用的进程只是从前台进程变成了后台进程,并没有直接被kill掉,所以我们的服务还能够运行。
  • 如果想要服务即便是在应用进程被kill掉的情况下依然可以运行,那么就需要做"服务后台保活"的操作。

这里先提供一个方案:在代码中定义两个Service,如:ServiceA,ServiceB,当ServiceA执行onDestroy时,让ServiceA开启ServiceB,当ServiceB执行onDestroy时,再让ServiceB开启ServiceA。这样两个服务相互开启,就会一直有一个服务在运行中。(具体的代码操作,后面我抽时间会写一个案例贴出了,大家一起探讨)

Android服务之混合方式开启服务的更多相关文章

  1. Android(java)学习笔记231:服务(service)之混合方式开启服务

    1. 前面我们已经讲过可以使用两种方式开启服务 startService----stopService:        oncreate() ---> onstartCommand() ---& ...

  2. Android(java)学习笔记174:服务(service)之混合方式开启服务

    1. 前面我们已经讲过可以使用两种方式开启服务 startService----stopService:        oncreate() ---> onstartCommand() ---& ...

  3. Android -- service的开启方式, start开启和绑定开启服务,调用服务的的方法, aidl调用远程服务

    1. 概述 bindService() 绑定服务  可以得到服务的代理人对象,间接调用服务里面的方法. 绑定服务: 间接调用服务里面的方法.           如果调用者activity被销毁了, ...

  4. [android] 绑定方式开启服务&调用服务的方法

    需求:后台开启一个唱歌服务,这个服务里面有个方法切换歌曲 新建一个SingService继承系统Service 重写onCreate()和onDestory()方法 填一个自定义的方法changeSi ...

  5. Android使用bindService作为中间人对象开启服务

    Android使用bindService作为中间人对象开启服务 项目结构如下: MyService: package com.demo.secondservice; import android.ap ...

  6. Android入门:绑定本地服务

    一.绑定服务介绍   前面文章中讲过一般的通过startService开启的服务,当访问者关闭时,服务仍然存在: 但是如果存在这样一种情况:访问者需要与服务进行通信,则我们需要将访问者与服务进行绑定: ...

  7. Android 程式开发:(廿二)服务 —— 22.1 自定义服务

    服务,就是跑在后台的“程序”,不需要和用户进行交互.举个例子,当使用一款应用的时候,可能同时想在后台播放一些音乐.在这种情况下,后来播放音乐的代码不需要和用户进行交互,所以,它就可能被当成一个服务.当 ...

  8. Android ListView分页载入(服务端+android端)Demo

    Android ListView分页载入功能 在实际开发中经经常使用到,是每一个开发人员必须掌握的内容,本Demo给出了服务端+Android端的两者的代码,并成功通过了測试. 服务端使用MyEcli ...

  9. start方式开启服务的特点&bindService 方式开启服务的特点

      服务是在后台运行 可以理解成是没有界面的activity   定义四大组件的方式都是一样的     定义一个类继承Service     start方式开启服务的特点   特点:   (1)服务通 ...

随机推荐

  1. Zabbix-绘制动态拓扑图基础篇

    一.实验环境 1.1 zabbix 4.0.2 二.实验需求介绍 公司希望网络拓扑能够动态反应物理接口的状态或者业务的状态,希望将网络拓扑显示到大屏上 三.Zabbix在绘制拓扑的优缺点 3.1 优点 ...

  2. C++中轻量级多线程openmp

    关于其概念及使用方法: https://baike.baidu.com/item/openmp/3735430?fr=aladdin

  3. GPU服务器安装NVIDIA驱动以及CUDA

    1.安装系统 系统版本: ubuntu16.04.05 LTS 分区要求: /boot 1024M swap 64G / 剩余空间

  4. python 17 内置模块

    目录 1. 序列化模块 1.1 json 模块 1.2 pickle 模块 2. os 模块 3. sys 模块 4. hashlib 加密.摘要 4.1 加密 4.2 加盐 4.3 文件一致性校验 ...

  5. ionic3.x脚手架(基于个人项目自用)

    ionic3项目开发脚手架(基于个人练习项目) 一.    基于ionic3的生产环境搭建 1.    配置安卓SDK: 安装jdk  --->  安装AndroidSDK (1)      安 ...

  6. Springboot源码分析之事务拦截和管理

    摘要: 在springboot的自动装配事务里面,InfrastructureAdvisorAutoProxyCreator ,TransactionInterceptor,PlatformTrans ...

  7. JavaScript String 字符串方法

    JavaScript String 字符串方法汇总   1.str.indexOf() 方法查找字符串中的字符串  返回   字符串中指定文本首次出现的索引(位置)       JavaScript ...

  8. 007 Linux系统优化进阶

    一.更改 ssh 服务远程登录的配置 windows:默认远程端口和管理员用户 管理员:administrator port :3389 Linux:远程连接默认端口和超级用户 管理员:root   ...

  9. Java连载26-方法(语法结构)

    一.方法 1.返回值类型如果不是void,表示这个方法执行结束之后必须返回一个具体的数值,当方法执行结束的时候没有返回任何数值,编译器会报错,怎么返回值呢?并且要求“值”的数据类型必须和“方法的返回值 ...

  10. CodeForces 340E Iahub and Permutations 错排dp

    Iahub and Permutations 题解: 令 cnt1 为可以没有限制位的填充数字个数. 令 cnt2 为有限制位的填充数字个数. 那么:对于cnt1来说, 他的值是cnt1! 然后我们对 ...