Android 四大组件之 Service

Android Service详解

重温Android 四大组件之 Service

目录

一、Service是什么?

1.Service是一个应用组件,它用来在后台完成一个时间跨度比较大的工作且没有关联任何界面

2.一个Service可以完成下面这些工作:

3.服务的特点:

4. 源码

二 、Service的分类

1.Local Service(本地服务)

2.Remote Service(远程服务)

三、 定义Service

1.定义一个类继承于Service类

2.在AndroidManifest.xml中配置Service

四、启动与停止Service

1.方式一:一般启动

context.startService(Intent intent)contstopService(lntent intent)

2.方式二:绑定启动

bindService(Intent intent,ServiceConnection connection)unbindService(ServiceConnection connection)

五、代码示例

1. 本地服务

(1) activity_main.xml 中定义两组按钮

(2) 自定义Service 类, 并实现onBind 方法, 以及重写其它生命周期相关方法(onCreate / onStartCommand/ onUnbind/ onDestroy)

(3) AndroidManifest 中声明service

(4) Activity 中处理Button 点击事件 

(5) 启动或停止服务的 日志输出:

(6) 绑定或解绑服务的 日志输出:



一、Service是什么?


1.Service是一个应用组件,它用来在后台完成一个时间跨度比较大的工作且没有关联任何界面

2.一个Service可以完成下面这些工作:

       访问网络
       播放音乐
       文件1O操作
       大数据量的数据库操作

3.服务的特点:

Service在后台运行,不用与用户进行交互即使应用退出,服务也不会停止.
在默认情况下,Service运行在应用程序进程的主线程(UI线程)中,如果需要在Service中处理一些网络连接等耗时的操作,那么应该将
这些任务放在分线程中处理,避兔阻塞用户界面

4. 源码

Service 类是一个抽象类, 继承了ContextWrapper,  即Context 类里定义的方法也可以用到 (Activity 也是ContextWrapper 的子类)

public abstract class Service extends ContextWrapper implements ComponentCallbacks2,
        ContentCaptureManager.ContentCaptureClient {

二 、Service的分类

1.Local Service(本地服务)

Service对象与Serive的启动者在同个进程中运行,两者的通信是进程内通信


2.Remote Service(远程服务)

Service对象与Service的启动者不在同一个进程中运行,这时存在一个进程间通信的问题,Android专门为此设计了AlDL来实现进程间通信

3. 前台service 、后台service

参考:

Android入门教程 | 四大组件之Service(前台服务,后台服务) - 哔哩哔哩点击进入查看全文>https://www.bilibili.com/read/cv13538561前台需使用 startForegroundService 启动,并在状态栏上显示图标(Notification);

一般用得多的是后台service

三、 定义Service

1.定义一个类继承于Service类

public class MyLocalService extends Service {

2.在AndroidManifest.xml中配置Service

<application 
           ...>
    <service android:name=".MyLocalService"/>
</application>

四、启动与停止Service


1.方式一:一般启动

context.startService(Intent intent)
context.stopService(lntent intent)


2.方式二:绑定启动

bindService(Intent intent,ServiceConnection connection)
unbindService(ServiceConnection connection)


区别:看Service启动后是否与启动者有关联?
Service对象经历的生命周期是否相同?

五、代码示例

1. 本地服务

实例如图:

(1) activity_main.xml 中定义两组按钮

分别为 启动服务 、停止服务  和 绑定服务、解绑服务, 界面很简单

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:textSize="30sp"
        android:text="1. 测试启动本地服务" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:orientation="horizontal">
        <Button
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent"
            android:text="启动服务"
            android:onClick="startService"
            android:textSize="20sp"/>

        <Button
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent"
            android:text="停止服务"
            android:onClick="stopService"
            android:textSize="20sp"/>
    </LinearLayout>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:textSize="30sp"
        android:text="2. 测试绑定本地服务" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:orientation="horizontal">
        <Button
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent"
            android:text="绑定服务"
            android:onClick="bindService"
            android:textSize="20sp"/>

        <Button
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent"
            android:text="解绑服务"
            android:onClick="unbindService"
            android:textSize="20sp"/>
    </LinearLayout>

</LinearLayout>

(2) 自定义Service 类, 并实现onBind 方法, 以及重写其它生命周期相关方法(onCreate / onStartCommand/ onUnbind/ onDestroy)

package com.example.servicetest1;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

import androidx.annotation.Nullable;

public class MyLocalService extends Service {
    private final static String TAG = "MyLocalService";

    @Override
    public void onCreate() {
        super.onCreate();
        log("onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        log("onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        log("onDestroy");
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        log("onBind");
        return new Binder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        log("onUnbind");
        return super.onUnbind(intent);
    }

    private void log(String msg){
        Log.d(TAG, msg);
    }
}

(3) AndroidManifest 中声明service

    <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=".MyLocalService"/>
    </application>

(4) Activity 中处理Button 点击事件 

import androidx.appcompat.app.AppCompatActivity;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    private final static String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void startService(View view) {
        log("startService ");
        Intent intent = new Intent(this, MyLocalService.class);
        startService(intent);
    }

    public void stopService(View view) {
        log("stopService ");
        Intent intent = new Intent(this, MyLocalService.class);
        stopService(intent);
    }

    private void log(String msg) {
        Log.d(TAG, msg);
    }

    private ServiceConnection mConnection = null;

    public void bindService(View view) {
        log("bindService ");
        Intent intent = new Intent(this, MyLocalService.class);
        if (mConnection == null) {
            mConnection = new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName name, IBinder service) {
                    log("onServiceConnected ");
                }

                @Override
                public void onServiceDisconnected(ComponentName name) {
                    log("onServiceDisconnected ");
                }
            };
        }

        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    public void unbindService(View view) {
        log("unbindService ");
        if (mConnection != null) {
            unbindService(mConnection);
            mConnection = null;
            Toast.makeText(this, "unbind service", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    protected void onDestroy() { // 似乎是多余的
        super.onDestroy();
        log("onDestroy ");
        if (mConnection != null) {
            log("onDestroy - need unbind service");
            unbindService(mConnection);
            mConnection = null;
        }
    }
}

(5) 启动或停止服务的 日志输出:

//第一次点击启动
2020-11-26 12:42:27.305  D/MainActivity: startService 
2020-11-26 12:42:27.312  D/MyLocalService: onCreate
2020-11-26 12:42:27.312  D/MyLocalService: onStartCommand
//第二次点击启动
2020-11-26 12:42:31.241  D/MainActivity: startService 
2020-11-26 12:42:31.244  D/MyLocalService: onStartCommand

//点击停止
2020-11-26 12:42:34.118  D/MainActivity: stopService 
2020-11-26 12:42:34.122  D/MyLocalService: onDestroy

可以看到, 在启动时, Service 会调用 onCreate / onStartCommand,   而已经启动情况下,再调启动,仅会执行onStartCommand;

停止时, Service 会调用 onDestroy

(6) 绑定或解绑服务的 日志输出:

//点击绑定
2020-11-26 12:47:46.372  D/MainActivity: bindService 
2020-11-26 12:47:46.379  D/MyLocalService: onCreate
2020-11-26 12:47:46.380  D/MyLocalService: onBind
2020-11-26 12:47:46.383  D/MainActivity: onServiceConnected

//点击解绑
2020-11-26 12:51:48.959  D/MainActivity: unbindService 
2020-11-26 12:51:48.984  D/MyLocalService: onUnbind
2020-11-26 12:51:48.985  D/MyLocalService: onDestroy

//绑定的时候,退出Activity
2020-11-26 12:53:12.285  I/ViewRootImpl@665f8ac[MainActivity]: dispatchDetachedFromWindow
2020-11-26 12:53:12.304  D/MyLocalService: onUnbind
2020-11-26 12:53:12.304  D/MyLocalService: onDestroy

在绑定的时候, 会调用 onCreate /onBind,   客户端会回调 onServiceConnected

解绑的试试,会先调用 onUnBind,  再调用 onDestroy.

此外,在绑定的时候,退出Activity, 似乎会自动解绑服务?? (不需要在Activity onDestroy 时, 手动调用解绑服务??, 不会报 leak service connection ??)

### Service 的作用 ServiceAndroid 四大组件之一,其主要作用是在后台执行长时间运行的任务,而不需要与用户进行交互。它没有界面,适用于执行如网络请求、播放音乐、文件 I/O 等需要在后台持续运行的操作。Service 可以独立于 Activity 运行,即使用户切换到其他应用,Service 仍然可以在后台继续运行 [^1]。 此外,Service 也可以被其他应用调用,从而提供一些特定的功能,例如后台数据处理或资源共享 [^2]。 ### Service 的生命周期 Service 的生命周期相对简单,主要包含以下几个关键方法: - `onCreate()`:当 Service 第一次被创建时调用,用于执行一次性初始化操作。 - `onStartCommand(Intent intent, int flags, int startId)`:当通过 `startService()` 启动 Service 时调用,用于处理传入的 Intent 请求。 - `onBind(Intent intent)`:当通过 `bindService()` 绑定 Service 时调用,返回一个 `IBinder` 对象用于实现组件间的通信。 - `onUnbind(Intent intent)`:当解除绑定时调用。 - `onDestroy()`:当 Service 被销毁时调用,用于释放资源。 根据启动方式的不同,Service 的生命周期会有所不同。 ### Service 的启动方式 Service 可以通过两种方式启动: 1. **通过 `startService()` 启动** - 使用 `startService()` 启动的 Service 会独立运行,与启动它的组件没有直接的绑定关系。 - 一旦启动,Service 会一直运行直到调用 `stopSelf()` 或外部调用 `stopService()`。 - 适用于执行一次性任务,例如下载文件或播放音乐。 2. **通过 `bindService()` 启动** - 使用 `bindService()` 启动的 Service 会与调用者(例如 Activity)建立绑定关系。 - 通过 `onBind()` 方法返回的 `IBinder` 对象,调用者可以与 Service 进行交互。 - 当调用者解除绑定时,Service 不会立即停止,只有当所有绑定都解除后,才会调用 `onUnbind()` 并最终调用 `onDestroy()` [^4]。 ### Service 的使用示例 #### 启动 Service ```java Intent serviceIntent = new Intent(context, MyService.class); context.startService(serviceIntent); ``` #### 停止 Service ```java Intent serviceIntent = new Intent(context, MyService.class); context.stopService(serviceIntent); ``` #### 绑定 Service ```java Intent serviceIntent = new Intent(context, MyService.class); context.bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE); ``` 其中,`serviceConnection` 是一个实现了 `ServiceConnection` 接口的对象,用于接收 Service 绑定后的回调。 #### 解除绑定 ```java context.unbindService(serviceConnection); ``` ### Service 的声明 每个 Service 都需要在 `AndroidManifest.xml` 文件中进行声明,否则无法正常运行。声明方式如下: ```xml <service android:name=".MyService" /> ``` ### 前台 Service 如果需要让 Service 在前台运行,以避免被系统优先级机制杀死,可以使用 `startForegroundService()` 方法启动 Service,并在 Service 中调用 `startForeground()` 方法,将 Service 提升为前台服务 [^3]。 ```java Intent serviceIntent = new Intent(context, MyForegroundService.class); context.startForegroundService(serviceIntent); ``` 在 Service 的 `onStartCommand()` 方法中: ```java Notification notification = new Notification.Builder(this, "channel_id") .setContentTitle("Foreground Service") .setSmallIcon(R.drawable.ic_notification) .build(); startForeground(1, notification); ``` ### 注意事项 - **资源管理**:由于 Service 在后台运行,需要注意资源的合理使用,避免过度消耗系统资源。 - **生命周期管理**:使用 `bindService()` 启动的 Service 必须通过 `unbindService()` 解除绑定,否则可能导致内存泄漏。 - **权限声明**:某些特殊用途的 Service(例如前台服务)可能需要在清单文件中声明额外的权限。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值