我正在尝试构建一个自定义应用程序,以利用Tasmota固件和MQTT控制智能家居设备。目前主要是智能灯。因此,根据设备的类型,我有一个Device
类的孩子。每个设备都存储一个DeviceState
,由于通过该应用程序进行的任何更改而被更新。因此DeviceState
始终是设备的当前状态。根据设备的不同,我需要不同的DeviceState,因此又有一个超类和子类。
现在,我想存储带有DeviceStates的ArrayList的场景以首先存储,而不是重新创建某些明亮的气氛。因此,有一个名为Scene的类,它包含基本信息和所描述的ArrayList。
为了存储这些列表,我正在使用Android中的Gson库。现在我的问题是如何能够保存带有多态列表的场景对象。
我已遵循以下stackoverflow帖子:Gson serialize a list of polymorphic objects使用Gson库和自定义序列化器/反序列化器将设备另存为Json String。但是现在DeviceState不会扩展场景,所以我不能使用一个序列化程序从Scene对象中创建String。而且,如果我将DeviceState扩展到Scene,则DeviceState类将声明具有相同名称的多个JSON字段,因为我使用“ typeName”来区分这些类。
所以基本上我得到了错误,DeviceState没有扩展Scene或DeviceState声明了多个名为“ typeName”的JSON字段。
public class Scene{
private ArrayList<DeviceState> states;
private String name;
private String room;
private String typeName;
public ArrayList<Scene> sceneList = new ArrayList<>();
public Scene(){
}
public Scene(String pName, String pRoom) {
name = pName;
room = pRoom;
states = new ArrayList<>();
typeName = "Scene";
}
public String getName() {
return name;
}
public String getRoom() {
return room;
}
public void addDevice(Device d) {
states.add(d.getState());
}
public void execute() {
System.out.println(states.size());
}
public String getTypeName(){
return typeName;
}
}
public class DeviceState {
private String typeName;
private String deviceTopic;
public static final String RGBWLightState = "RGBWLightState";
public static final String Default = "DeviceState";
public DeviceState(String pTypeName, String pDeviceTopic){
typeName = pTypeName;
deviceTopic = pDeviceTopic;
}
public DeviceState(){
typeName = Default;
}
public String getTypeName() {
return typeName;
}
}
public class CustomSceneSerializer implements JsonSerializer<ArrayList<Scene>> {
private static Map<String, Class> map = new TreeMap<>();
static {
map.put(DeviceState.RGBWLightState, RGBWLightState.class);
map.put(DeviceState.Default, DeviceState.class);
map.put("Scene", Scene.class);
}
@Override
public JsonElement serialize(ArrayList<Scene> src, Type typeOfSrc, JsonSerializationContext context) {
if(src == null) {
return null;
}else{
JsonArray ja = new JsonArray();
for(Scene s : src){
Class c = map.get(s.getTypeName());
if(c == null){
throw new RuntimeException("Unkown class: " + s.getTypeName());
}
ja.add(context.serialize(s, c));
}
return ja;
}
}
}
public class CustomSceneDeserializer implements JsonDeserializer<List<Scene>> {
private static Map<String, Class> map = new TreeMap<>();
static {
map.put(DeviceState.RGBWLightState, RGBWLightState.class);
map.put(DeviceState.Default, DeviceState.class);
map.put("Scene", Scene.class);
}
@Override
public List<Scene> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
ArrayList list = new ArrayList<Scene>();
JsonArray ja = json.getAsJsonArray();
for (JsonElement je : ja) {
String type = je.getAsJsonObject().get("typeName").getAsString();
Class c = map.get(type);
if (c == null)
throw new RuntimeException("Unknow class: " + type);
list.add(context.deserialize(je, c));
}
return list;
}
}
要保存包含我正在使用的那些对象的列表的对象,请执行以下操作:
String json = preferences.getString("scene_holder", "");
GsonBuilder gb = new GsonBuilder();
List<Scene> al = new ArrayList<>();
gb.registerTypeAdapter(al.getClass(), new CustomSceneDeserializer());
gb.registerTypeAdapter(al.getClass(), new CustomSceneSerializer());
Gson gson = gb.create();
System.out.println(list.size());
list.get(0).execute();
System.out.println(json);
if (!(json.equals(""))) {
Scene result = gson.fromJson(json, Scene.class);
System.out.println(result.sceneList.size());
result.sceneList = list;
System.out.println(result.sceneList.size());
editor.putString("scene_holder", gson.toJson(result)).commit();
} else {
Scene scene = new Scene();
scene.sceneList = list;
editor.putString("scene_holder", gson.toJson(scene)).commit();
}