HarmonyOS-Service&Android-Service,一次关于JVM的面试经历

Android:创建 Service 的子类(或使用它的一个现有子类)。开发者需要重写一些回调方法,从而处理服务生命周期的某些关键方面,并提供一种机制将组件绑定到服务。

public class AndroidService extends Service {
@Override
public void onCreate() {
super.onCreate();
}

}

或者创建IntentService(Service 子类)子类,串行执行所有启动服务请求。

public class AndroidIntentService extends IntentService {

public AndroidIntentService() {
s

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

uper(“AndroidIntentService”);
}
@Override
protected void onHandleIntent(Intent intent) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// Restore interrupt status.
Thread.currentThread().interrupt();
}
}
}

注册

HarmonyOS:Service需要在应用配置文件中进行注册,注册类型type需要设置为service。

{
“module”: {
“abilities”: [
{
“name”: “.ServiceAbility”,
“type”: “service”,
“visible”: true

}
]

}

}

Android:开发者必须在应用的清单文件中声明所有服务。如要声明服务,需要添加 元素作为 元素的子元素,name属性是唯一必需的属性。

<manifest … >

<application … >



启动服务

HarmonyOS

HarmonyOS中Ability为开发者提供了startAbility()方法来启动另外一个Ability。因为Service也是Ability的一种,开发者同样可以通过将Intent传递给该方法来启动Service。不仅支持启动本地Service,还支持启动远程Service。其中启动本地服务如下:

Intent intent = new Intent();
Operation operation = new Intent.OperationBuilder()
.withDeviceId("")
.withBundleName(“com.huawei.hiworld.himusic”)
.withAbilityName(“com.huawei.hiworld.himusic.entry.ServiceAbility”)
.build();
intent.setOperation(operation);
startAbility(intent);

参数说明:

  • DeviceId:表示设备ID。如果是本地设备,则可以直接留空;如果是远程设备,可以通过ohos.distributedschedule.interwork.DeviceManager提供的getDeviceList获取设备列表。
  • BundleName:表示包名称。
  • AbilityName:表示待启动的Ability名称。 启动远程服务如下:

Operation operation = new Intent.OperationBuilder()
.withDeviceId(“deviceId”)
.withBundleName(“com.huawei.hiworld.himusic”)
.withAbilityName(“com.huawei.hiworld.himusic.entry.ServiceAbility”)
.withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE) // 设置支持分布式调度系统多设备启动的标识
.build();
Intent intent = new Intent();
intent.setOperation(operation);
startAbility(intent);

Ability将通过startAbility() 方法来启动Service。 如果Service尚未运行,则系统会先调用onStart()来初始化Service,再回调Service的onCommand()方法来启动Service。 如果Service正在运行,则系统会直接回调Service的onCommand()方法来启动Service。

Android

开发者可以通过将 Intent 传递给 startService() 或 startForegroundService(),从 Activity 或其他应用组件启动服务。Android 系统会调用服务的 onStartCommand() 方法,并向其传递 Intent,从而指定要启动的服务。如果应用面向 API 级别 26 或更高版本,除非应用本身在前台运行,否则系统不会对使用或创建后台服务施加限制。如果应用需要创建前台服务,则其应调用 startForegroundService()。此方法会创建后台服务,但它会向系统发出信号,表明服务会将自行提升至前台。创建服务后,该服务必须在五秒内调用自己的 startForeground() 方法。

Intent intent = new Intent(this, AndroidService.class);
startService(intent);

startService() 方法会立即返回,并且 Android 系统会调用服务的 onStartCommand() 方法。如果服务尚未运行,则系统首先会调用 onCreate(),然后调用 onStartCommand()。 如果服务亦未提供绑定,则应用组件与服务间的唯一通信模式便是使用 startService() 传递的 Intent。但是,如果开发者希望服务返回结果,则启动服务的客户端可以为广播(通过 getBroadcast() 获得)创建一个 PendingIntent,并将其传递给启动服务的 Intent 中的服务。然后,服务便可使用广播传递结果。 多个服务启动请求会导致多次对服务的 onStartCommand() 进行相应的调用。但是,如要停止服务,只需一个服务停止请求(使用 stopSelf() 或 stopService())即可。

启动前台服务(可选)

HarmonyOS

开发者只需在Service创建的方法里,调用keepBackgroundRunning()将Service与通知绑定。调用keepBackgroundRunning()方法前需要在配置文件中声明。ohos.permission.KEEP_BACKGROUND_RUNNING权限,该权限是normal级别,同时还需要在配置文件中添加对应的backgroundModes参数。在onStop()方法中调用cancelBackgroundRunning​()方法可停止前台Service。使用前台Service的onStart()代码示例如下:

// 创建通知,其中1005为notificationId
NotificationRequest request = new NotificationRequest(1005);
NotificationRequest.NotificationNormalContent content = new NotificationRequest.NotificationNormalContent();
content.setTitle(“title”).setText(“text”);
NotificationRequest.NotificationContent notificationContent = new NotificationRequest.NotificationContent(content);
request.setContent(notificationContent);

// 绑定通知,1005为创建通知时传入的notificationId
keepBackgroundRunning(1005, request);

在配置文件中配置如下:

{
“name”: “.ServiceAbility”,
“type”: “service”,
“visible”: true,
“backgroundModes”: [“dataTransfer”,“location”]
}

Android

开发者创建前台服务,需要调用startForeground(),这个方法同样需要notificationId和Notification实例:

Intent notificationIntent = new Intent(this, AndroidActivity.class);
PendingIntent pendingIntent =
PendingIntent.getActivity(this, 0, notificationIntent, 0);

Notification notification =
new Notification.Builder(this, CHANNEL_DEFAULT_IMPORTANCE)
.setContentTitle(getText(R.string.notification_title))
.setContentText(getText(R.string.notification_message))
.setSmallIcon(R.drawable.icon)
.setContentIntent(pendingIntent)
.setTicker(getText(R.string.ticker_text))
.build();
startForeground(ONGOING_NOTIFICATION_ID, notification);

注意:Notification ID不能为0,同时在Android 9 (API level 28) 获取更高版本中前台服务需要申明:FOREGROUND_SERVICE权限:

<manifest xmlns:android=“http://schemas.android.com/apk/res/android” …>

<application …>


如果应用目标level高于Android 10 (API level 29) 在清单文件中还要申明相关前台服务类型:

...

代码中也要申明:

Notification notification = …;
Service.startForeground(notification,
FOREGROUND_SERVICE_TYPE_LOCATION | FOREGROUND_SERVICE_TYPE_CAMERA);

绑定服务(可选)

HarmonyOS

如果Service需要与Page Ability或其他应用的Service Ability进行交互,则应创建用于连接的Connection。Service支持其他Ability通过connectAbility()方法与其进行连接。 在使用connectAbility()处理回调时,需要传入目标Service的Intent与IAbilityConnection的实例。IAbilityConnection提供了两个方法供开发者实现:onAbilityConnectDone()用来处理连接的回调,onAbilityDisconnectDone()用来处理断开连接的回调。

// 创建连接回调实例
private IAbilityConnection connection = new IAbilityConnection() {
// 连接到Service的回调
@Override
public void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int resultCode) {
// 在这里开发者可以拿到服务端传过来IRemoteObject对象,从中解析出服务端传过来的信息
}

// 断开与连接的回调
@Override
public void onAbilityDisconnectDone(ElementName elementName, int resultCode) {
}
};
// 连接Service
connectAbility(intent, connection);

同时,Service侧也需要在onConnect()时返回IRemoteObject,从而定义与Service进行通信的接口。onConnect()需要返回一个IRemoteObject对象,HarmonyOS提供了IRemoteObject的默认实现,用户可以通过继承RemoteObject来创建自定义的实现类。Service侧把自身的实例返回给调用侧的代码示例如下:

// 创建自定义IRemoteObject实现类
private class MyRemoteObject extends RemoteObject {
public MyRemoteObject() {
super(“MyRemoteObject”);
}
}

// 把IRemoteObject返回给客户端
@Override
protected IRemoteObject onConnect(Intent intent) {
return new MyRemoteObject();
}

Android

绑定服务是客户端-服务器接口中的服务器。借助绑定服务,组件(例如 Activity)可以绑定到服务、发送请求、接收响应,以及执行进程间通信 (IPC)。绑定服务通常只在为其他应用组件提供服务时处于活动状态,不会无限期在后台运行。创建提供绑定的服务时,您必须提供 IBinder,进而提供编程接口,以便客户端使用此接口与服务进行交互。开发者可以通过三种方法定义接口:扩展 Binder 类,使用 Messenger,使用 AIDL(一般不用)。

  • 扩展 Binder 类。创建代码如下:

public class LocalService extends Service {
private final IBinder binder = new LocalBinder();
private final Random mGenerator = new Random();

public class LocalBinder extends Binder {
LocalService getService() {
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}

public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}

启动如下:

public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;

@Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, LocalService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}

@Override
protected void onStop() {
super.onStop();
unbindService(connection);
mBound = false;
}
public void onButtonClick(View v) {
if (mBound) {
int num = mService.getRandomNumber();

}
}

private ServiceConnection connection = new ServiceConnection() {

@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}

@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}

  • 使用 Messenger。创建代码如下:

public class MessengerService extends Service {
static final int MSG_SAY_HELLO = 1;

static class IncomingHandler extends Handler {
private Context applicationContext;

IncomingHandler(Context context) {
applicationContext = context.getApplicationContext();
}

@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:

break;
default:
super.handleMessage(msg);
}
}
}
Messenger mMessenger;
@Override
public IBinder onBind(Intent intent) {

mMessenger = new Messenger(new IncomingHandler(this));
return mMessenger.getBinder();
}
}

服务会在 Handler 的 handleMessage() 方法中接收传入的 Message,并根据 what 成员决定下一步操作。客户端只需根据服务返回的 IBinder 创建 Messenger,然后利用 send() 发送消息。例如,以下简单 Activity 展示如何绑定到服务并向服务传递 MSG_SAY_HELLO 消息:

public class ActivityMessenger extends Activity {
Messenger mService = null;
boolean bound;

private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mService = new Messenger(service);
bound = true;
}

public void onServiceDisconnected(ComponentName className) {
mService = null;
bound = false;
}
};

上一篇:鸿蒙系统生态开发分应用和设备开发


下一篇:第五节·跨设备迁移