引言

前面介绍过了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. [HAOI2015]树上染色(树上dp)

    [HAOI2015]树上染色 这种要算点对之间路径的长度和的题,难以统计每个点的贡献.这个时候一般考虑算每一条边贡献了哪些点对. 知道这个套路以后,那么这题就很好做了. 状态:设\(dp[u][i]\ ...

  2. spring中的事件 applicationevent 讲的确实不错(转)

    event,listener是observer模式一种体现,在spring 3.0.5中,已经可以使用annotation实现event和eventListner里. 我们以spring-webflo ...

  3. SSH开发模式——Struts2(第三小节)

    struts2框架的知识点,虽然分了几个小节,感觉内容还是挺多的,但是你仅仅是入门了而已,想要进一步地提升自己,你得有一颗持之以恒的学习的心,最后的内容我都将在这篇博客中讲到,所以篇幅可能会有点长,希 ...

  4. N*N矩阵的旋转 不开辟新空间

    /* N*N矩阵的旋转 不开辟新空间 programmer:qpz time:2014-11-09 */ #include <iostream> using namespace std; ...

  5. G1 collector 介绍

    背景:由于CMS算法产生空间碎片和其它一系列的问题缺陷,HotSpot提供了另外一种垃圾回收策略,G1(也就是Garbage First)算法,该算法在JDK7u4版本被正式推出,官网对此描述如下: ...

  6. Java多线程之线程的暂停

    Java多线程之线程的暂停 下面该稍微休息一下了呢……不过,这里说的是线程休息,不是我们哦.本节将介绍一下让线程暂停运行的方法. 线程Thread 类中的sleep 方法能够暂停线程运行,Sleep ...

  7. 漫话:如何给女朋友解释什么是"锟斤拷"?

    漫话:如何给女朋友解释什么是"锟斤拷"? ​ 周末女朋友出去逛街了,我自己一个人在家看综艺节目,突然,女朋友给我打来电话. 过了一会,女朋友回来了,她拿出手机,给我看了她在超市拍的 ...

  8. Delphi - cxGrid添加Footer显示

    cxGrid - 添加footer显示 1:添加Footer Items 单击cxGrid Customize... ,Summary,Add: 2:添加Footer items数据绑定 选中一条需要 ...

  9. 【selenium】- webdriver常见api

    本文由小编根据慕课网视频亲自整理,转载请注明出处和作者. 1.常见API 2.打开网址 3.操作浏览器 quit()没有完全关闭进程,依旧占用资源. 4.输入框操作 5.选择框操作 6.特殊窗口操作 ...

  10. KDTree 板子

    从杨哥哪里偷的板子, 存一下. #include<bits/stdc++.h> using namespace std; #define Fopen freopen("_in.t ...