我编写的代码使用的是我在webockets上设计的协议,用于创建Android应用程序的项目。
我有一个使用Autobahn库weCommunicationManager
处理websocket通信的类。
我有许多变量和标签,用于处理从我的服务器通过websockets到应用程序的收到的JSON消息。
为了使事物分离并在一个地方,我创建了一个抽象类ExICSProtocol
,它将标记保存为公共静态成员,以便可以在必要时引用它们。
在收到的消息中是消息类型的整数值,我需要能够打开它来定义如何处理该特定的接收消息。
为此,我在ExICSProtocol类中实现了一个公共枚举,如下所示,
public static enum MESSAGE_TYPE{
PROTOCOL_HANDSHAKE(0),
USER_CONNECTED(1),
USER_DISCONNECTED(2),
SYSTEM_STATE(3),
CHANGE_ROOM(4),
EXAM_START(5),
EXAM_PAUSE(6),
EXAM_STOP(7),
EXAM_XTIME(8),
SEND_MESSAGE(9),
SUCCESS(69),
FAILURE(-1),
TERMINATE_CONNECTION(-2);
private int code;
MESSAGE_TYPE(int code){
this.code = code;
}
public int getCode(){
return this.code;
}
}
我试图在wsCommunicationManager代码中使用它,如下所示,
private static void handleMessage(String message){
try{
JSONObject messageObject = new JSONObject(message);
JSONObject messageHeader = messageObject.getJSONObject(ExICSProtocol.TAG_HEADER);
JSONObject messagePayload = messageObject.getJSONObject(ExICSProtocol.TAG_PAYLOAD);
int messageType = messageHeader.getInt(ExICSProtocol.TAG_MESSAGE_TYPE);
switch(messageType){
case ExICSProtocol.MESSAGE_TYPE.PROTOCOL_HANDSHAKE.getCode():
//DO SOMETHING HERE
break;
...
default:
throw new ExICSException("Unknown Message Type Received");
break;
}
}catch (JSONException e){
Log.e(TAG, "Failed to parse received message " + message, e);
}catch (ExICSException e){
Log.e(TAG, "Excaption Handling Message Occurred", e);
}
}
我在ExICSProtocol.MESSAGE_TYPE.PROTOCOL_HANDSHAKE.getCode():
下标记了错误,表示需要使用常量表达式。然而,这应该是不变的吗?
我尝试了一些不同的东西,将枚举移动到正在使用它的类中;同样的问题。使enum公共持有私有int,以便可以直接访问;同样的问题。
我已经看到很多在switch语句中使用枚举的例子,但不像我一样。我在申报或初始化中遗漏了什么,或者我正在尝试做一些不能工作的事情。
我知道有一些相对简单的解决方法,例如将数字类型代码定义为公共静态最终整数,但我希望在可能的情况下将类型代码保存在MESSAGE_TYPE下。
答案 0 :(得分:5)
如您所见,调用方法不算作constant expression。
清洁解决方案(IMO)将在您的枚举中使用静态方法:
// Enum renamed to comply with conventions
public enum MessageType {
private static final Map<Integer, MessageType> codeMap = new HashMap<>();
// Can't do this in the constructor, as the codeMap variable won't have been
// initialized
static {
for (MessageType type : MessageType.values()) {
codeMap.put(type.getCode(), type);
}
}
public static MessageType fromCode(int code) {
return codeMap.get(code);
}
}
然后在你的wsCommunicationManager代码中:
int messageCode = messageHeader.getInt(ExICSProtocol.TAG_MESSAGE_TYPE);
MessageType messageType = MessageType.fromCode(messageCode);
if (messageType == null) {
// Unknown message code. Do whatever...
}
switch(messageType) {
case MessageType.PROTOCOL_HANDSHAKE:
...
}
基本上,尽可能早地从“面向整数”转向“面向对象”的世界。这有点像早期解析基于数字和日期的用户输入而不是传递字符串 - 只是在你的情况下,代理表示是int
。
答案 1 :(得分:4)
你可以在你的MESSAGE_TYPE枚举中添加一个getFromCode(int code)静态方法,如下所示:
public static MESSAGE_TYPE getFromCode(int code) {
for(MESSAGE_TYPE mt : MESSAGE_TYPE.values())
if(mt.code == code)
return mt;
throw new IllegalArgumentException();
}
然后在你的handleMessage中:
MESSAGE_TYPE messageType = MESSAGE_TYPE.getByCode(messageHeader.getInt(ExICSProtocol.TAG_MESSAGE_TYPE));
switch(messageType){
case PROTOCOL_HANDSHAKE:
//handle handshake...
答案 2 :(得分:2)
除非你的枚举做了一些你没有向我们展示过的内容,否则这不是对枚举的好用。对于这种特殊情况,静态类可能更有用(和可读):
public class MessageType {
public static final int PROTOCOL_HANDSHAKE = 0;
public static final int USER_CONNECTED = 1;
....
}
然后在你的switch语句中,你可以使用
switch( messageType ) {
case MessageType.PROTOCOL_HANDSHAKE:
....
break;
这实际上是Android在其他领域(例如ContentResolver,数据库等)提倡的合同类模式。
答案 3 :(得分:1)
您正在使用在运行时评估的函数。将相同的值放在int中也不起作用,因为它也在运行时进行评估。
将值放在private final static int
中会起作用,因为它是在编译时计算的,因此是一个常量表达式。
尝试类似
的内容private final static int PROTOCOL_HANDSHAKE = 0;
并在您的switch语句中执行此操作
case PROTOCOL_HANDSHAKE:
//Do something