Android --- Service

发布于:2024-07-02 ⋅ 阅读:(146) ⋅ 点赞:(0)

出自于此,写得很清楚。
关于Android Service真正的完全详解,你需要知道的一切_android service-CSDN博客
出自【zejian的博客】

什么是Service?

Service(服务)是一个一种可以在后台执行长时间运行操作而没有用户界面的应用组件。

服务可由其他应用组件启动(如Activity),服务一旦被启动将在后台一直运行,即使启动服务的组件(Activity)已销毁也不受影响。

此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC)。 例如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行。

Service基本上分为两种形式:

  • 启动状态

  当应用组件(如 Activity)通过调用 startService() 启动服务时,服务即处于“启动”状态。一旦启动,服务即可在后台无限期运行,即使启动服务的组件已被销毁也不受影响,除非手动调用才能停止服务, 已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。

  • 绑定状态

  当应用组件通过调用 bindService() 绑定到服务时,服务即处于“绑定”状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。 仅当与另一个应用组件绑定时,绑定服务才会运行。 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。

如何使用Service?

清单文件声明

使用Service前会在清单文件中声明配置。

<service android:enabled=["true" | "false"]
    android:exported=["true" | "false"]
    android:icon="drawable resource"
    android:isolatedProcess=["true" | "false"]
    android:label="string resource"
    android:name="string"
    android:permission="string"
    android:process="string" >
    . . .
</service>
  • android:exported:代表是否能被其他应用隐式调用,其默认值是由service中有无intent-filter决定的,如果有intent-filter,默认值为true,否则为false。为false的情况下,即使有intent-filter匹配,也无法打开,即无法被其他应用隐式调用。
  • android:name:对应Service类名
  • android:permission:是权限声明
  • android:process:是否需要在单独的进程中运行,当设置为android:process=”:remote”时,代表Service在单独的进程中运行。注意“:”很重要,它的意思是指要在当前进程名称前面附加上当前的包名,所以“remote”和”:remote”不是同一个意思,前者的进程名称为:remote,而后者的进程名称为:App-packageName:remote。
  • android:isolatedProcess :设置 true 意味着,服务会在一个特殊的进程下运行,这个进程与系统其他进程分开且没有自己的权限。与其通信的唯一途径是通过服务的API(bind and start)。
  • android:enabled:是否可以被系统实例化,默认为 true因为父标签 也有 enable 属性,所以必须两个都为默认值 true 的情况下服务才会被激活,否则不会激活。

创建Service子类

首先要创建服务,必须创建 Service 的子类(或使用它的一个现有子类如IntentService)。

在实现中,我们需要重写一些回调方法(其中onBind()方法必须重写),以处理服务生命周期的某些关键过程。

package com.example.androidstudiostudy.service;

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

//创建 Service 的子类(或使用它的一个现有子类如IntentService),重写一些回调方法
public class OneService extends Service {
    public OneService() {
    }

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

    // 首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或onBind() 之前)。
    // 如果服务已在运行,则不会调用此方法,该方法只调用一次
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("服务","首次创建服务调用此方法来执行一次性设置程序,该方法只调用一次");
    }

    // 每次通过startService()方法启动Service时都会被回调。
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("服务","onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

   // 服务销毁时回调
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("服务","销毁服务");
    }
}
  •  onBind()

  当另一个组件想通过调用 bindService() 与服务绑定(例如执行 RPC)时,系统将调用此方法。在此方法的实现中,必须返回 一个IBinder 接口的实现类,供客户端用来与服务进行通信。无论是启动状态还是绑定状态,此方法必须重写,但在启动状态的情况下直接返回 null。

  • onCreate()

  首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或onBind() 之前)。如果服务已在运行,则不会调用此方法,该方法只调用一次

  • onStartCommand()

  当另一个组件(如 Activity)通过调用 startService() 请求启动服务时,系统将调用此方法。一旦执行此方法,服务即会启动并可在后台无限期运行。 如果自己实现此方法,则需要在服务工作完成后,通过调用 stopSelf() 或 stopService() 来停止服务。(在绑定状态下,无需实现此方法。)

  • onDestroy()

  当服务不再使用且将被销毁时,系统将调用此方法。服务应该实现此方法来清理所有资源,如线程、注册的侦听器、接收器等,这是服务接收的最后一个调用。

启动Service

使用 startService(intent);

停止Serviece

使用 stopService(intent);

 通过Demo测试一下Service启动状态方法的调用顺序,依次点击启动和停止。StudyService 代码如下:

public class StudyService extends AppCompatActivity {

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

    }

    public void serviceAction(View view) {
        int id = view.getId();
        Intent intent = new Intent(this,OneService.class);
        if(id == R.id.bindService){
            // 绑定service

        } else if (id == R.id.stopService) {
            stopService(intent); // 停止服务
        } else {
            startService(intent); // 启动服务
        }
    }
}

 此时的清单文件:

 <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/study"
        android:label="@string/app_name"
        android:networkSecurityConfig="@xml/network_security_config"
        android:roundIcon="@mipmap/study"
        android:supportsRtl="true"
        android:theme="@style/Theme.AndroidStudioStudy"
        tools:targetApi="31">
        <activity
            android:name=".service.StudyService"
            android:exported="false" />
        <activity
            android:name=".service.studyService"
            android:exported="false" />

        <service
            android:name=".service.OneService"
            android:enabled="true"
            android:exported="true"
            android:permission=".service.OneService" />

日志打印:

绑定Service

绑定服务是Service的另一种变形,当Service处于绑定状态时,其代表着客户端-服务器接口中的服务器。

当其他组件(如 Activity)绑定到服务时,组件(如Activity)可以向Service(也就是服务端)发送请求,或者调用Service(服务端)的方法,此时被绑定的Service(服务端)会接收信息并响应,甚至可以通过绑定服务进行执行进程间通信 。

有时我们可能需要从Activity组件中去调用Service中的方法,此时Activity以绑定的方式挂靠到Service后,我们就可以轻松地方法到Service中的指定方法

与启动服务不同的是绑定服务的生命周期通常只在为其他应用组件(如Activity)服务时处于活动状态,不会无限期在后台运行,也就是说宿主(如Activity)解除绑定后,绑定服务就会被销毁。

那么在提供绑定的服务时,该如何实现呢?

实际上我们必须提供一个 IBinder接口的实现类,该类用以提供客户端用来与服务进行交互的编程接口,该接口可以通过三种方法定义接口:

  • 扩展 Binder 类

如果服务是提供给自有应用专用的,并且Service(服务端)与客户端相同的进程中运行(常见情况),则应通过扩展 Binder 类并从 onBind() 返回它的一个实例来创建接口。

客户端收到 Binder 后,可利用它直接访问 Binder 实现中以及Service 中可用的公共方法。如果我们的服务只是自有应用的后台工作线程,则优先采用这种方法。

不采用该方式创建接口的唯一原因是,服务被其他应用或不同的进程调用。

  1. 在Service子类中创建一个扩展 Binder 的类(OneServiceBinder),在类中声明了一个getService方法,客户端可访问该方法获取 Service子类 对象的实例,只要客户端获取到 OneServiceBinder 对象的实例就可调用服务端的公共方法。
  2. 创建一个实现IBinder 接口的实例对象并提供公共方法给客户端调用
  3. 从 onBind() 回调方法返回此 Binder 实例。
private OneServiceBinder oneServiceBinder = new OneServiceBinder();


// 当另一个组件想通过调用 bindService() 与服务绑定(例如执行 RPC)时,系统将调用此方法。
// 在此方法的实现中,必须返回 一个IBinder 接口的实现类,供客户端用来与服务进行通信。
// 无论是启动状态还是绑定状态,此方法必须重写,但在启动状态的情况下直接返回 null。
@Override
public IBinder onBind(Intent intent) {
   return oneServiceBinder;
 }

/**
 * 创建Binder对象,返回给客户端即Activity使用,提供数据交换的接口
 */
 public class OneServiceBinder extends Binder {
    // 声明一个方法,getService。(提供给客户端调用)
    OneService getService() {
    // 返回当前对象LocalService,这样我们就可在客户端端调用Service的公共方法了
     return OneService.this;
   }
 }

完整service代码

package com.example.androidstudiostudy.service;

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

//创建 Service 的子类(或使用它的一个现有子类如IntentService),重写一些回调方法
public class OneService extends Service {
    private OneServiceBinder oneServiceBinder = new OneServiceBinder();
    private Thread thread;

    // 当另一个组件想通过调用 bindService() 与服务绑定(例如执行 RPC)时,系统将调用此方法。
    // 在此方法的实现中,必须返回 一个IBinder 接口的实现类,供客户端用来与服务进行通信。
    // 无论是启动状态还是绑定状态,此方法必须重写,但在启动状态的情况下直接返回 null。
    @Override
    public IBinder onBind(Intent intent) {
        return oneServiceBinder;
    }

    /**
     * 创建Binder对象,返回给客户端即Activity使用,提供数据交换的接口
     */
    public class OneServiceBinder extends Binder {
        // 声明一个方法,getService。(提供给客户端调用)
        OneService getService() {
            // 返回当前对象LocalService,这样我们就可在客户端端调用Service的公共方法了
            return OneService.this;
        }
    }

    // 首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或onBind() 之前)。
    // 如果服务已在运行,则不会调用此方法,该方法只调用一次
    private int count = 0;
    private boolean quit = false;

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("服务", "首次创建服务调用此方法来执行一次性设置程序,该方法只调用一次");
        thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!quit) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    count++;
                }
            }
        });
        thread.start();
    }

    // 当另一个组件(如 Activity)通过调用 startService() 请求启动服务时,系统将调用此方法。
    // 一旦执行此方法,服务即会启动并可在后台无限期运行。 如果自己实现此方法,则需要在服务工作完成后,通过调用 stopSelf() 或 stopService() 来停止服务。
    // (在绑定状态下,无需实现此方法。)
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("服务", "onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    // 当服务不再使用且将被销毁时,系统将调用此方法。服务应该实现此方法来清理所有资源,如线程、注册的侦听器、接收器等,这是服务接收的最后一个调用。
    @Override
    public void onDestroy() {
        super.onDestroy();
        this.quit = true;
        Log.d("服务", "销毁服务");
    }

    //--------------------公共方法------------------
    public int getCount() {
        return count;
    }
    //--------------------解除绑定时调用------------------

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d("服务", "解除绑定");
        return super.onUnbind(intent);
    }
}

客户端绑定到服务步骤:

1.ServiceConnection代表与服务的连接,它只有两个方法,实现ServiceConnection,重写这两个回调方法。

  • onServiceConnected()—系统会调用该方法以传递服务的onBind()返回的IBinder;
  • onServiceDisconnected()—Android系统会在服务崩溃或被杀死导致的连接中断时调用(或者随着activity 的生命周期stop)时调用该方法,当客户端取消绑定的时候,不会回调该方法
private ServiceConnection serviceConnection;
    private OneService myService;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_study_service);

        serviceConnection = new ServiceConnection() {
            // 绑定成功时调用
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                Log.d("绑定服务","成功绑定服务");
                OneService.OneServiceBinder oneServiceBinder = (OneService.OneServiceBinder) iBinder;
                myService = oneServiceBinder.getService();
            }
            // Android 系统会在与服务的连接意外中断时(例如当服务崩溃或被终止时)调用该方法
            @Override
            public void onServiceDisconnected(ComponentName componentName) {
                Log.d("绑定服务","与服务的连接意外中断");
                myService = null;
            }
        };

    }

2.调用bindService(),传递ServiceConnection

3.当系统调用onServiceConnected()的回调方法时,可以使用接口定义的方法开始调用服务

4.要断开与服务的连接,请调用unBindService()

如果应用在客户端与服务仍然绑定的状态下被销毁了,则销毁会导致客户端取消绑定。

Activity代码         

public class StudyService extends AppCompatActivity {

    private ServiceConnection serviceConnection;
    private OneService myService;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_study_service);

        serviceConnection = new ServiceConnection() {
            // 绑定成功时调用
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                Log.d("绑定服务","成功绑定服务");
                OneService.OneServiceBinder oneServiceBinder = (OneService.OneServiceBinder) iBinder;
                myService = oneServiceBinder.getService();
            }
            // Android 系统会在与服务的连接意外中断时(例如当服务崩溃或被终止时)调用该方法
            @Override
            public void onServiceDisconnected(ComponentName componentName) {
                Log.d("绑定服务","与服务的连接意外中断");
                myService = null;
            }
        };

    }

    public void serviceAction(View view) {
        int id = view.getId();
        Intent intent = new Intent(this,OneService.class);
        if(id == R.id.bindService){
            // 绑定service
            bindService(intent,serviceConnection,Service.BIND_AUTO_CREATE);
            if (myService != null) {
                // 通过绑定服务传递的Binder对象,获取Service暴露出来的数据

                Log.d("获取绑定数据", "从服务端获取数据:" + myService.getCount());
            } else {

                Log.d("获取绑定数据", "还没绑定呢,先绑定,无法从服务端获取数据");
            }
        } else if (id == R.id.stopService) {
            stopService(intent);
        } else {
            startService(intent);
        }
    }
}

打印数据

  • 使用 Messenger

前面了解到应用内同一进程的通信可以使用IBinder,而不同进程间的通信,最简单的方式则是使用 Messenger 服务提供通信接口,利用此方式,我们无需使用 AIDL 便可执行进程间通信 (IPC)。以下是 Messenger 使用的主要步骤:

1.服务实现一个 Handler,由其接收来自客户端的每个调用的回调

// 用于接收从客户端传递过来的数据
    class ServiceReciveHandle extends Handler {
        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Log.i(TAG, "thanks,Service had receiver message from client!");
                    break;
                default:
                    super.handleMessage(msg);
            }

        }
    }

2.Handler 用于创建 Messenger 对象(对 Handler 的引用)

3.Messenger 创建一个 IBinder,服务通过 onBind() 返回这个Messenger对象的底层Binder

final Messenger messenger = new Messenger(new ServiceReciveHandle());

    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "服务绑定");
        return messenger.getBinder();
    }

4.客户端使用 IBinder 将 Messenger(引用服务的 Handler)实例化,然后使用Messenger将 Message 对象发送给服务。

// 实现与服务端链接的对象
    private final ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            // 通过服务端传递的IBinder对象,创建相应的Messenger
            // 通过该Messenger对象与服务端进行交互
            Log.i(TAG, "服务链接绑定");
            myService = new Messenger(iBinder);
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Log.i(TAG, "服务链接绑定取消");
            myService = null;
            mBound = false;
        }
    };

5.服务在其 Handler 中(在 handleMessage() 方法中)接收每个 Message。

完整Service代码:

package com.example.androidstudiostudy.service;

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.util.Log;

import androidx.annotation.NonNull;

public class MessengerService extends Service {
    static final int MSG_SAY_HELLO = 1;
    private static final String TAG = "MessengerService";

    // 用于接收从客户端传递过来的数据
    class ServiceReciveHandle extends Handler {
        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Log.i(TAG, "服务器接收到来自客户端的消息");

                    break;
                default:
                    super.handleMessage(msg);
            }

        }
    }

    final Messenger messenger = new Messenger(new ServiceReciveHandle());

    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "服务绑定");
        return messenger.getBinder();
    }

    @Override
    public void onCreate() {
        Log.i(TAG, "服务onCreate");
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        Log.i(TAG, "服务Destroy");
        super.onDestroy();
    }
}

Activity代码

package com.example.androidstudiostudy.service;


public class MessengerServiceActivity extends AppCompatActivity {
    private static final String TAG = "MessengerService-Activity";

    // 与服务端交互的Messenger
    private Messenger myService = null;
   
    // 是否绑定
    boolean mBound = false;
   
    // 实现与服务端链接的对象
    private final ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            // 通过服务端传递的IBinder对象,创建相应的Messenger
            // 通过该Messenger对象与服务端进行交互
            Log.i(TAG, "服务链接绑定");
            myService = new Messenger(iBinder);
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Log.i(TAG, "服务链接绑定取消");
            myService = null;
            mBound = false;
        }
    };

    private Button sendMsg, bindService, unbindService, createService, destoryService;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_messenger_service);
        sendMsg = findViewById(R.id.sendMessageToService);
        sendMsg.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (!mBound)
                    return;
                Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
                try {
                    // 发送消息
                    myService.send(msg);
                } catch (RemoteException e) {
                    throw new RuntimeException(e);
                }

            }
        });

        Intent intent = new Intent(MessengerServiceActivity.this, MessengerService.class);

        unbindService = findViewById(R.id.unbindMessengerService);
        unbindService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                unbindService(mConnection);
            }
        });

        bindService = findViewById(R.id.bindMessengerService);
        bindService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.i(TAG, "bd");
                bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
            }
        });

        createService = findViewById(R.id.startMessengerService);
        createService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startService(intent);
            }
        });

        destoryService = findViewById(R.id.destoreyMessengerService);
        destoryService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                stopService(intent);
            }
        });
    }
}
 服务器与客户端的双向通信

上述代码能够实现客户端向服务器的通信,如果想要服务器向客户端通信,则需要在客户端也创建一个接收消息的Messenger和Handler。


网站公告

今日签到

点亮在社区的每一天
去签到