这是我参与8月更文挑战的第18天,活动详情查看:8月更文挑战
概述
Service
是一种可在后台执行长时间运行操作而不提供界面的应用组件,与Activity不同,Activity是显示图形用户界面的,而Service的运行是不可见的。服务可由其他应用组件启动,即使切换到其他的应用,Service仍将在后台继续运行。此外,组件可通过绑定到服务与之进行交互,甚至是执行进程间通信 (IPC)。例如,服务可在后台处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序进行交互。
Sercvice类型
前台Service
前台服务执行一些用户能注意到的操作。例如,音频应用会使用前台服务来播放音频曲目。前台服务必须显示Notification
。即使用户停止与应用的交互,前台服务仍会继续运行。
后台Service
后台服务执行用户不会直接注意到的操作。例如,如果应用使用某个服务来压缩其存储空间,则此服务通常是后台服务。
注意:如果您的应用面向 API 级别 26 或更高版本,当应用本身未在前台运行时,系统会对运行后台服务施加限制。在诸如此类的大多数情况下,您的应用应改为使用计划作业。
绑定Service
绑定Service方式核心在于bindService()
绑定服务会提供客户端-服务器接口,以便组件与服务进行交互、发送请求、接收结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。仅当与另一个应用组件绑定时,绑定服务才会运行。多个组件可同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。
Service生命周期
public class MyService extends Service {
/**
* 首次创建服务时,系统会(在调用 onStartCommand() 或 onBind() 之前)调用此方法来执行一次性设置程序。如果服务已在运行,则不会调用此方法。
*/
@Override
public void onCreate() {
super.onCreate();
}
/**
* 当另一个组件(如 Activity)请求启动服务时,系统会通过调用 startService() 来调用此方法。执行此方法时,服务即会启动并可在后台无限期运行。
* 如果您实现此方法,则在服务工作完成后,您需负责通过调用 stopSelf() 或 stopService() 来停止服务。(如果您只想提供绑定,则无需实现此方法。)
* @param intent
* @param flags
* @param startId
* @return
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
/**
* 当另一个组件想要与服务绑定(例如执行 RPC)时,系统会通过调用 bindService() 来调用此方法。在此方法的实现中,您必须通过返回 IBinder 提供一个接口,
* 以供客户端用来与服务进行通信。请务必实现此方法;但是,如果您并不希望允许绑定,则应返回 null。
* @param intent
* @return
*/
@Override
public IBinder onBind(Intent intent) {
return null;
}
/**
* 取消绑定时调用
* @param intent
* @return
*/
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
/**
* 当不再使用服务且准备将其销毁时,系统会调用此方法。服务应通过实现此方法来清理任何资源,如线程、注册的侦听器、接收器等。这是服务接收的最后一个调用。
*/
@Override
public void onDestroy() {
super.onDestroy();
}
}
创建启动和绑定Service
常见的需要定义一个Service的子类,重写其生命周期方法,当创建一个Service后,必须将这个Service在
AndroidManifest.xml
中进行注册。
<service
android:name=".MyService"
android:enabled="true"
android:exported="true" />
private ServiceConnection mConnection;
private Intent mServiceIntent;
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.start_service:
//启动Service
if(mServiceIntent == null){
mServiceIntent = new Intent(this,MyService.class);
}
startService(mServiceIntent);
break;
case R.id.bind_service:
//绑定Service
if(mServiceIntent == null){
mServiceIntent = new Intent(this,MyService.class);
}
if(mConnection == null){
mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
}
bindService(mServiceIntent, mConnection,BIND_AUTO_CREATE);
break;
case R.id.unbind_service:
//解绑Service
if(null != mConnection){
unbindService(mConnection);
mConnection = null;
}
break;
case R.id.stop_service:
//停止Service
if(mServiceIntent == null){
mServiceIntent = new Intent(this,MyService.class);
}
stopService(mServiceIntent);
break;
}
}
- 如果服务存在,binderService方法只能是onBind方法被调用,而unBindService方法只能是onUnbind被调用
- 如果服务不存在:onCreate->onBind->onUnbind->onDestory
AIDL
Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信。
定义AIDL文件,父级目录与java同级。
interface IMyAIDL {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
int getProcess();
}
定义完之后make project ,AS快捷键Ctrl
+ F9
,之后才可以使用。
make之后
//继承字Binder实现AIDL
public static abstract class Stub extends android.os.Binder implements com.Shixf.androidbasic.IMyAIDL
public class MyService extends Service {
private static final String TAG = "MyService";
MyBinder mBinder;
private volatile int i;
public MyService() {
mBinder = new MyBinder();
}
class MyBinder extends Binder{
public MyService getService(){
return MyService.this;
}
public int getProcess(){
return i;
}
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
new Thread(()->{
while (true){
i++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return new IMyAIDL.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public int getProcess() throws RemoteException {
Log.d("Shixf","AIDL processs = " + i);
return i;
}
};
}
@Override
public void onRebind(Intent intent) {
Log.d(TAG, "onRebind");
super.onRebind(intent);
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "onUnbind");
return true;
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy");
mBinder = null;
}
}
新创建一个应用以及AIDL,保持包名一致
package com.shixf.aidldemo;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.Shixf.androidbasic.IMyAIDL;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private static final String TAG = "MainActivity";
private Button mStartService;
private Button mBindService;
private Button mStopService;
private Button mUnBindService;
ServiceConnection connection;
private Intent i;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate: startService = " + mStartService);
mStartService = findViewById(R.id.btn_startService);
mStartService.setOnClickListener(this);
mBindService = findViewById(R.id.btn_bindService);
mBindService.setOnClickListener(this);
mStopService = findViewById(R.id.btn_stopService);
mStopService.setOnClickListener(this);
mUnBindService = findViewById(R.id.btn_unbindService);
mUnBindService.setOnClickListener(this);
}
@SuppressLint("NonConstantResourceId")
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_startService:
Log.d(TAG, "onClick: start Service");
i = new Intent();
/*i.setAction("com.shixf.MyService");
i.setPackage("com.Shixf.androidbasic");*/
i.setComponent(new ComponentName("com.Shixf.androidbasic",
"com.Shixf.androidbasic.Service.MyService"));//第一个参数是包名,第二个是类名
startForegroundService(i);
break;
case R.id.btn_stopService:
if(i == null){
i = new Intent();
/*i.setAction("com.shixf.MyService");
i.setPackage("com.Shixf.androidbasic");*/
i.setComponent(new ComponentName("com.Shixf.androidbasic",
"com.Shixf.androidbasic.Service.MyService"));//第一个参数是包名,第二个是类名
}
stopService(i);
break;
case R.id.btn_bindService:
if(i == null){
i = new Intent();
/*i.setAction("com.shixf.MyService");
i.setPackage("com.Shixf.androidbasic");*/
i.setComponent(new ComponentName("com.Shixf.androidbasic",
"com.Shixf.androidbasic.Service.MyService"));//第一个参数是包名,第二个是类名
}
if(connection == null){
connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
aidlGetProcess(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
}
bindService(i,connection,BIND_AUTO_CREATE);
break;
case R.id.btn_unbindService:
if(null != connection){
unbindService(connection);
connection = null;
}
break;
default:
throw new IllegalStateException("Unexpected value: " + v.getId());
}
}
private void aidlGetProcess(IBinder iBinder){
IMyAIDL aidl = IMyAIDL.Stub.asInterface(iBinder);
try {
int process = aidl.getProcess();
Toast.makeText(MainActivity.this,"process = " + process,Toast.LENGTH_LONG).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
注意如果exported = false 是无法启动Service的。