我的安卓第一课:四大组件之一Service

引言

Service的主要作用,在 Android 开发中,Service 是一种用于在后台执行操作的组件。与 Activity 不同,Service 并不提供用户界面,而是专注于处理长时间运行的任务或执行需要在后台进行的工作。Activity生活在前台,而Service生活在后台

使用场景

  1. 当需要执行可能需要较长时间才能完成的任务(例如网络请求、文件下载等),或者需要持续运行的任务(记录日志等),使用 Service 可以避免阻塞主线程(UI 线程),从而保证应用的响应性。

  2. 即使应用程序不在前台显示,Service 也可以继续在后台运行。这对于需要持续更新数据的应用来说非常有用,比如音乐播放器即使退出了主界面也能继续播放音乐。(但如果不是前台Service,则随时会被回收)

TIP: 虽然Service运行在后台,但实际上Service并不会自动开启新线程,所有的代码都是默认运行在主线程当中的 。也就是说,需要在Service的内部手动创建子线程,并在这里执行具体的任务,否则就有可能出现主线程被阻塞的情况(导致停止响应)。

Service的创建与使用

我们可以直接在Android Studio中创建Service

其中Exported属性表示是否将这个Service暴露给 外部其他程序访问,Enabled属性表示是否启用这个Service

java 复制代码
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class MyService extends Service {
    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

使用Service 启用Service与启用新的Activity一样,都需要Intent的支持。比如:

java 复制代码
Intent intent = new Intent(this, MyService.class);
startService(intent);

但有不同的是,Service支持暂停

java 复制代码
Intent intent = new Intent(this, MyService.class);
stopService(intent);

TIP: 从Android 8.0系统开始,应用的后台功能被大幅削减。现在只有当应用保持在前台可见状态的情况下,Service才能保证稳定运行,一旦应用进入后台之后,Service随时都有可能被系统回收。 之所以做这样的改动,是为了防止许多恶意的应用程序长期在后台占用手机资源,从而导致手机变得越来越卡。当然,如果真的非常需要长期在后台执行一些任务,可以使用前台Service或者WorkManager

(听说早期有APP把自己缩小为一个像素来保活)

Service与Activity通信

我们在extends Service后,会强制要求实现onBind。而onBind也正是实现Service与Activity通信的基础。onBind的方法签名如下所示

java 复制代码
@Override
public IBinder onBind(Intent intent) {
    return new MyBind();
}

主要是接收一个Intent,响应一个IBinder。此时我们可以编写一个类实现IBinder接口或继承Binder。然后在绑定后返回。同时,在Service与Activity绑定时一共需要两个类,一个ServiceConnection类以及一个IBinder

ServiceConnection

该类主要是在连接成功与断开时使用。具有两个主要方法 ServiceConnected(ComponentName name, IBinder service)onServiceDisconnected(ComponentName name)

  1. 前者,当 Activity 与 Service 成功绑定后调用,可以通过 service 参数获取到 Service 的通信接口。
  2. 后者,当连接意外断开时调用(如 Service 崩溃或被杀死)。

IBinder

IBinder是一个接口,它是 Android 中进程间通信 (IPC) 的基础 。在 Service 与 Activity 绑定的场景中,Service 需要通过IBinder向 Activity 提供交互接口。他是交互的实际执行对象。 ,通常我们不选择implements IBinder接口,而是选择extends Binder。之后编写自己的方法。

Service与Activity的绑定

bindService(intent, mConnection, Context.BIND_AUTO_CREATE);用于两者的绑定

unbindService(mConnection);用于两者的解绑 下方是部分示例代码

java 复制代码
public class MyService extends Service {
    // 自定义Binder类,继承自Binder并实现我们需要的方法
    private final IBinder mBinder = new LocalBinder();
    
    public class LocalBinder extends Binder {
        // 返回当前Service的实例,这样Activity就能调用Service中的公共方法
        MyService getService() {
            return MyService.this;
        }
        
        // 也可以直接在这里定义供Activity调用的方法
        public void doSomething() {
            // 实现具体功能
        }
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
    
    // Service中其他的公共方法,Activity可以通过LocalBinder获取Service实例后调用
    public void publicMethod() {
        // 实现具体功能
    }
}
java 复制代码
public class MainActivity extends AppCompatActivity {
    private MyService mService;
    private boolean mBound = false;
    
    // 实现ServiceConnection接口
    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            // 当与Service的连接建立后,此方法会被调用
            // 通过IBinder获取Service实例
            MyService.LocalBinder binder = (MyService.LocalBinder) service;
            mService = binder.getService();
            mBound = true;
            
            // 连接成功后可以立即调用Service中的方法
            if (mBound) {
                mService.publicMethod();
                // binder.doSomething()
            }
        }
        
        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            // 当与Service的连接意外断开时(如Service崩溃或被杀死),此方法会被调用
            mBound = false;
        }
    };
    // ...
    
    @Override
    protected void onStart() {
        super.onStart();
        // 绑定Service
        Intent intent = new Intent(this, MyService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }
    
    @Override
    protected void onStop() {
        super.onStop();
        // 解除绑定
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }
    
    // Activity中的方法,调用Service的功能
    public void callServiceMethod(View view) {
        if (mBound) {
            mService.doSomething();
        }
    } 
    // ...
}

在上面的示例中,MainActivity启动后,执行onStart。绑定并启动Service。同时通过onBind()获得IBinder对象,执行onServiceConnected(ComponentName, IBinder)获得IBinder对象,就可以执行IBinder中的方法了。断开则是执行去onServiceDisconnected()

onBind() -> onServiceConnected() -> onServiceDisconnected()

Service的生命周期

类似于Activity,Service也有自己的生命周期。不过Service的生命周期相对来说比较复杂。主要有两种启用方式,startServicebindService。具体执行流程可以如下图所示。

text 复制代码
               onCreate()
                   ↓
           ┌────────────────┐
           │   启动方式?   │───────────┐
           └───────┬────────┘           │
                   ↓                    │
     ┌───────────────────────┐          ↓         
     │    startService()     │    bindService()
     │  ┌─────────────────┐  │    ┌────────────┐
     │  │ onStartCommand()│  │    │  onBind()  │
     │  └─────────────────┘  │    └──────┬─────┘
     │         ↓             │           ↓
     │    运行中 Service     │       客户端绑定
     │         ↓             │           ↓
     │    stopService()/     │    unbindService()
     │     stopSelf()        │           ↓
     └───────────┬───────────┘    ┌─────────────┐
                 │                │  onUnbind() │
                 │                └──────┬──────┘
                 │                       ↓
                 └───────────┬───────────┘
                             ↓
                        onDestroy()
  1. 每调用一次startService()方法,onStartCommand()就会执行一次,但实际上每个Service只会存在一个实例 。所以不管你调用了多少次startService()方法,只需调用一次stopService()stopSelf()方法,Service就会停止。在这一类启动方法下- Service 会在后台无限期运行,直到被系统终止 或调用stopService()/stopSelf()

  2. 当调用bindService()时,Service 与绑定的组件(如 Activity)生命周期绑定组件解除绑定时 Service 会被销毁

  3. 当两种启动方式都使用呢,根据Android系统的机制,一个Service只要被启动或者被绑定了之后,就会处于运行状态必须要让以上两种条件同时不满足 ,Service才能被销毁。所以,这种情况下要同时调用stopService()unbindService()方法,onDestroy()方法才会执行。

TIP:每个Service只会存在一个实例,其是单例的。所以对于同一个Service,onCreate()与onDestory()只会执行一次。

相关推荐
移动开发者1号12 分钟前
Activity onCreate解析
android·kotlin
帅得不敢出门3 小时前
Android Framework预装traceroute执行文件到system/bin下
android
xzkyd outpaper3 小时前
从面试角度回答Android中ContentProvider启动原理
android·面试·计算机八股
编程乐学3 小时前
基于Android 开发完成的购物商城App--前后端分离项目
android·android studio·springboot·前后端分离·大作业·购物商城
这个家伙很笨8 小时前
了解Android studio 初学者零基础推荐(4)
android·ide·android studio
alexhilton9 小时前
在Android应用中实战Repository模式
android·kotlin·android jetpack
二流小码农14 小时前
鸿蒙开发:DevEcoTesting中的稳定性测试
android·ios·harmonyos
一起搞IT吧14 小时前
相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
android·图像处理·数码相机
xzkyd outpaper14 小时前
Android中ContentProvider细节
android·计算机八股