43. 【Android教程】服务:Service

简介: 43. 【Android教程】服务:Service

今天来学习 Android 的另一个组件——Service,相比于 Activity,Service通常运行在后台,没有任何 UI 界面,对用户是透明感知。通常用来执行一些后台任务,比如播放音乐、下载、加载一些数据等等,也可以用作一些进程间通信(IPC)机制。

1. Service 的基本定义

我们还是先来看看官方文档的部分解释:


A Service is an application component representing either an application’s desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use. Each service class must have a corresponding declaration in its package’s AndroidManifest.xml. Services can be started with Context.startService() and Context.bindService().


还是用我蹩脚的英语给大家简单翻译一下:


Service 是 Android 四大组件之一,通常用来执行一些需要长时间运行并且不需要和用户发送交互的任务,或者是要持续给其他 App 提供服务的场景。每一个服务和 Activity 一样,需要在包下的 “AndroidManifest.xml”文件中添加注册,Service可以通过Context.startService()或者Context.bindService()两种方式启动。


简而言之,Service适用于无 UI 界面并且长时间运行或者专门给其他 App 提供服务的场景。

2. Service 的基本概念

为了更好的理解 Service的运行机制,这里提出几个容易混淆的概念:

  • **进程:**进程是操作系统为一个 App 提供的独立的运行单元,是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。
  • **线程:**线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是

一般说来,在 Android 中一个 App 运行在一个独立进程,而每一个进程可以有多个线程。从编程的角度来看,多个线程是同时并行运行的(是否是真并行依赖操作系统的调度以及 CPU 的核数)。

我们的 Activity 就是运行在主线程(UI线程),而 Service 默认也是在主线程,所以如果需要做一些耗时操作仍然需要主动放到子线去运行。

3. Service 的启动方式及生命周期

在第 1 小节的最后讲到过,Service 有两种启动方式:Context.startService()Context.bindService(),所以也对应着两类 Service:

  • Started Service
  • Bound Service

2.1 Started Service

顾名思义,Started 类型的 Service 就是通过Context.startService()方法启动的 Service,此时 Service 会立即在后台启动,可以调用Context.stopService()关闭。当然,在 Service 内也可以使用Context.stopService()来关闭自己。

2.2 Bound Service

Service 进入 Bound 状态需要在 Activity 中调用Context.bindService()方法,这样这两个组件就绑定到了一起,此后二者可以很方便的相互通信,调用Context.unbindService()可以解除绑定。


其实以上两种方式的最大差异就是,第 1 种在 start 之后,两个组件之间就没有太大关系了,而第 2 种是以“bind”形式启动的,启动之后两者仍然是绑定关系,可以进行数据的传递以及状态的监听。

这两种启动方式的生命周期如下:


相比于 Activity,Service 的生命周期就简化了很多,主要还是依赖于启动方式,通常如果是一个相对独立的 Service,未来不需要和 Activity 强关联,推荐使用第一种;当然如果需要在 Activity 里面做一些交互甚至对 Service 做一些管理,那么必须使用 bind 的方式。

4. Service 使用示例

接下通过 Service 实现一个非常常见的功能——音乐播放器。现在市面的绝大多数音乐播放器都是在一个 Service 里面实现的,它需要长时间在后台运行,所以天然就适合运行在 Service 中。

4.1 播放器控制

这里主要是演示 Service 的用法,所以只对播放器进行简单的控制,大家课后感兴趣的可以继续补充,将示例做成一个更加完整的播放器。我们在 Service 创建的时候初始化播放器,在 Servce 启动的时候启动播放器,销毁的时候关闭。首先创建“PlayerService”,代码如下:


package com.emercy.myapplication;
 
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.IBinder;
import android.widget.Toast;
 
public class PlayerService extends Service {
    MediaPlayer myPlayer;
 
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
 
    @Override
    public void onCreate() {
        Toast.makeText(this, "Service Created", Toast.LENGTH_LONG).show();
 
        myPlayer = MediaPlayer.create(this, R.raw.mc_guitar);
        myPlayer.setLooping(false); // Set looping
    }
 
    @Override
    public void onStart(Intent intent, int startid) {
        Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
        myPlayer.start();
    }
 
    @Override
    public void onDestroy() {
        Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
        myPlayer.stop();
    }
}
 

代码很简单,在 Service 的onCreate()中初始化播放器,设置音频地址,将你喜欢的音乐放置在 raw 目录,或者指定一个网络 Mp3 的 url 地址均可;然后在onStart()中启动播放器。

4.2 布局文件编写

我们希望能够随时控制播放器的起播和停止,所以需要两个 Button 分别进行控制:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <Button
        android:id="@+id/buttonStart"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="74dp"
        android:text="启动播放器" />
 
    <Button
        android:id="@+id/buttonStop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="停止播放" />
</RelativeLayout>

4.3 主控逻辑编写

在 MainActivity 里主要要做两件事:

  1. 通过startService()启动 PlayerService,播放音乐;
  2. 通过stopService结束播放
 
package com.emercy.myapplication;
 
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
 
public class MainActivity extends Activity implements View.OnClickListener {
    Button buttonStart, buttonStop;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        buttonStart = findViewById(R.id.buttonStart);
        buttonStop = findViewById(R.id.buttonStop);
 
        buttonStart.setOnClickListener(this);
        buttonStop.setOnClickListener(this);
    }
 
    public void onClick(View src) {
        switch (src.getId()) {
            case R.id.buttonStart:
                startService(new Intent(this, PlayerService.class));
                break;
            case R.id.buttonStop:
                stopService(new Intent(this, PlayerService.class));
                break;
        }
    }
}

4.4 清单文件

需要注意的是,Service 是一个组件,凡是添加组件都需要在 AndroidManifest.xml 中注册(动态注册除外),否则无法使用:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.emercy.myapplication">
 
    <uses-permission android:name="android.permission.INTERNET" />
 
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
 
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
 
        <service
            android:name=".PlayerService"
            android:enabled="true"
            android:exported="true" />
    </application>
 
</manifest>

**注意:**如果你的音频文件是一个远程的 url,还需要增加网络权限:


<uses-permission android:name="android.permission.INTERNET" />

到此,整个初级的播放器就开发完成了。大家如果感兴趣还可以考虑增加其他的功能,比如快进、快退、切歌、增加通知栏、展示歌词等等。

5. 小结

本节介绍了 Android 第二个组件,Service 的主要场景是运行一些耗时且在后台的任务,并且相比 Activity 它更轻量且没有用户界面。有两种启动方式,通过startService()启动之后 Service 与启动它的 Activity 再无任何关联,而bindService()方式启动之后二者还会绑定在一起,可以进行相互的调用和数据传递。同时由于 Service 无 UI 界面,所以在用完后一定要记得要 stop,回收资源。

相关文章
|
1月前
|
Android开发 数据安全/隐私保护 虚拟化
安卓手机远程连接登录Windows服务器教程
安卓手机远程连接登录Windows服务器教程
62 4
|
1月前
|
Android开发
布谷语音软件开发:android端语音软件搭建开发教程
语音软件搭建android端语音软件开发教程!
|
2月前
|
安全 Java 网络安全
Android远程连接和登录FTPS服务代码(commons.net库)
Android远程连接和登录FTPS服务代码(commons.net库)
33 1
|
3月前
|
JavaScript 前端开发 Android开发
让Vite+Vue3项目在Android端离线打开(不需要起服务)
让Vite+Vue3项目在Android端离线打开(不需要起服务)
118 10
|
3月前
|
调度 Android开发 UED
Android经典实战之Android 14前台服务适配
本文介绍了在Android 14中适配前台服务的关键步骤与最佳实践,包括指定服务类型、请求权限、优化用户体验及使用WorkManager等。通过遵循这些指南,确保应用在新系统上顺畅运行并提升用户体验。
261 6
|
3月前
|
安全 API 开发工具
Android平台RTMP推送|轻量级RTSP服务如何实现麦克风|扬声器声音采集切换
Android平台扬声器播放声音的采集,在无纸化同屏等场景下,意义很大,早期低版本的Android设备,是没法直接采集扬声器audio的(从Android 10开始支持),所以,如果需要采集扬声器audio,需要先做系统版本判断,添加相应的权限。
|
3月前
|
编解码 开发工具 Android开发
Android平台实现屏幕录制(屏幕投影)|音频播放采集|麦克风采集并推送RTMP或轻量级RTSP服务
Android平台屏幕采集、音频播放声音采集、麦克风采集编码打包推送到RTMP和轻量级RTSP服务的相关技术实现,做成高稳定低延迟的同屏系统,还需要有配套好的RTMP、RTSP直播播放器
|
4月前
|
数据处理 开发工具 数据安全/隐私保护
Android平台RTMP推送|轻量级RTSP服务|GB28181接入之文字、png图片水印的精进之路
本文探讨了Android平台上推流模块中添加文字与PNG水印的技术演进。自2015年起,为了满足应急指挥及安防领域的需求,逐步发展出三代水印技术:第一代为静态文字与图像水印;第二代实现了动态更新水印内容的能力,例如实时位置与时间信息;至第三代,则优化了数据传输效率,直接使用Bitmap对象传递水印数据至JNI层,减少了内存拷贝次数。这些迭代不仅提升了用户体验和技术效率,也体现了开发者追求极致与不断创新的精神。
|
4月前
|
编解码 网络协议 Android开发
Android平台GB28181设备接入模块实现后台service按需回传摄像头数据到国标平台侧
我们在做Android平台GB28181设备对接模块的时候,遇到这样的技术需求,开发者希望能以后台服务的形式运行程序,国标平台侧没有视频回传请求的时候,仅保持信令链接,有发起视频回传请求或语音广播时,打开摄像头,并实时回传音视频数据或接收处理国标平台侧发过来的语音广播数据。
|
4月前
|
数据采集 编解码 开发工具
Android平台实现无纸化同屏并推送RTMP或轻量级RTSP服务(毫秒级延迟)
一个好的无纸化同屏系统,需要考虑的有整体组网、分辨率、码率、实时延迟、音视频同步和连续性等各个指标,做容易,做好难