【问题标题】:When making a POJO in Firebase, can you use ServerValue.TIMESTAMP?在 Firebase 中制作 POJO 时,可以使用 ServerValue.TIMESTAMP 吗?
【发布时间】:2016-01-10 19:37:41
【问题描述】:

当您制作一个旨在从 Firebase 序列化和反序列化到 Firebase 的普通旧 Java 对象时,有没有办法使用 ServerValue.TIMESTAMP 值?

例如,假设我想要一个对象,其中一个属性是上次编辑它的时间,并且您想使用 ServerValue.TIMESTAMP 值。

在 POJO 类中,您可能有:

private String timeLastChanged;

private Map<String, String> timeLastChanged;

String 的第一个示例中,我遇到了设置timeLastChange = ServerValue.TIMESTAMP; 的问题,因为ServerValue.TIMESTAMP 是一个地图。

Map&lt;String, String&gt; 的第二个示例中,我收到“去抖动失败”错误,因为它无法将数据库中存储的 long 正确反序列化为 Map&lt;String, String&gt;。有什么解决办法吗?

【问题讨论】:

标签: android firebase firebase-realtime-database


【解决方案1】:

2016 年 12 月 27 日更新

正如许多人所提到的,将@JsonIgnore 换成@Exclude


我终于想出了一个灵活的解决方案来处理 Dates 和 ServerValue.TIMESTAMP。这是来自Ivan VOssamapuf 的示例。

我想不出一种方法来处理longHashMap&lt;String, String&gt; 之间的转换,但是如果您将属性嵌套在更通用的HashMap&lt;String, Object&gt; 中,它可以作为单个长值进入数据库("date", "1443765561874") 或 ServerValue.TIMESTAMP 哈希映射 ("date", {".sv", "servertime"})。然后当你把它拉出来时,它总是一个带有(“日期”,“某个长数字”)的 HashMap。然后,您可以使用 @JsonIgnore @Exclude 注释在您的 POJO 类中创建一个辅助方法(这意味着 Firebase 将忽略它并且不将其视为用于从数据库序列化/从数据库序列化的方法)以轻松获取从返回的 HashMap 中提取长值以在您的应用中使用。

POJO 类的完整示例如下:

import com.google.firebase.database.Exclude;
import com.firebase.client.ServerValue;

import java.util.HashMap;
import java.util.Map;

public class ExampleObject {
    private String name;
    private String owner;
    private HashMap<String, Object> dateCreated;
    private HashMap<String, Object> dateLastChanged;

    /**
     * Required public constructor
     */
    public ExampleObject() {
    }

    public ExampleObject(String name, String owner, HashMap<String,Object> dateCreated) {
        this.name = name;
        this.owner = owner;
        this.dateCreated = dateCreated;

        //Date last changed will always be set to ServerValue.TIMESTAMP
        HashMap<String, Object> dateLastChangedObj = new HashMap<String, Object>();
        dateLastChangedObj.put("date", ServerValue.TIMESTAMP);
        this.dateLastChanged = dateLastChangedObj;
    }

    public String getName() {
        return name;
    }

    public String getOwner() {
        return owner;
    }

    public HashMap<String, Object> getDateLastChanged() {
        return dateLastChanged;
    }

    public HashMap<String, Object> getDateCreated() {
      //If there is a dateCreated object already, then return that
        if (dateCreated != null) {
            return dateCreated;
        }
        //Otherwise make a new object set to ServerValue.TIMESTAMP
        HashMap<String, Object> dateCreatedObj = new HashMap<String, Object>();
        dateCreatedObj.put("date", ServerValue.TIMESTAMP);
        return dateCreatedObj;
    }

// Use the method described in https://stackoverflow.com/questions/25500138/android-chat-crashes-on-datasnapshot-getvalue-for-timestamp/25512747#25512747
// to get the long values from the date object.
    @Exclude
    public long getDateLastChangedLong() {

        return (long)dateLastChanged.get("date");
    }

    @Exclude
    public long getDateCreatedLong() {
        return (long)dateCreated.get("date");
    }

}

【讨论】:

  • 当我调用getDateLastChangedLong() 时,使用下面的示例,我得到一个 NullPointerException 可能是因为转换为 Long ..虽然时间戳被正确创建...对此有什么想法或解决方法吗?在您要求我的代码之前,我基本上复制并粘贴了您的代码:)
  • 如果我能有这个的 c# 版本,那就太棒了。谢谢
  • 还有其他人面临铸造问题吗?我收到 java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Long
【解决方案2】:

我想稍微改进一下莱拉的回答。首先,我想摆脱公共方法public HashMap<String, Object> getDateLastChanged() public HashMap<String, Object> getDateCreated()。为此,您可以使用 @JsonProperty 注释标记 dateCreated 属性。另一种可能的方法是像这样更改属性检测:@JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
其次,我不明白为什么我们需要将ServerValue.TIMESTAMP 放入HashMap 而我们可以将它们存储为属性。所以我的最终代码是:

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.firebase.client.ServerValue;

public class ShoppingList {
    private String listName;
    private String owner;
    @JsonProperty
    private Object created;

    public ShoppingList() {
    }

    public ShoppingList(String listName, String owner) {
        this.listName = listName;
        this.owner = owner;
        this.created = ServerValue.TIMESTAMP;
    }

    public String getListName() {
        return listName;
    }

    public String getOwner() {
        return owner;
    }

    @JsonIgnore
    public Long getCreatedTimestamp() {
        if (created instanceof Long) {
            return (Long) created;
        }
        else {
            return null;
        }
    }

    @Override
    public String toString() {
        return listName + " by " + owner;
    }

}

【讨论】:

  • 此方法有助于将时间戳与其他键保持在同一级别。
  • 真正的魔法。谢谢你。这种行为是否记录在任何地方?
  • 无论如何我都可以得到一个与此等效的 C# 用于 unity3D #unity3d
  • 如果您想改进为更具体的名称(如“server_time_stamp”)创建的更多更改
【解决方案3】:

这些解决方案对我来说似乎有点困难,因为我不知道 @JsonIgnore 在做什么。我试着用一种简单的方式来做这件事,似乎很有效。

private Object dateLastChanged;

public Object getDateLastChanged() {
    return dateLastChanged;
}

为了获得人类可读的内容,我只是通过将返回值 dateLastChanged Object 转换为 Long 来将其传递到以下方法中。

static String convertTime(Long unixtime) {
    Date dateObject = new Date(unixtime);
    SimpleDateFormat dateFormatter = new SimpleDateFormat("dd-MM-yy hh:mmaa");
    return dateFormatter.format(dateObject);
}

欢迎对我的解决方案提出意见^^

【讨论】:

  • 当@snayde getter 对我不起作用时,您的 getter 方法对我有帮助(权限错误)
  • 他们必须使用 jason ignore,因为对象是地图,他们将其存储为更简单的字段
【解决方案4】:

您可以使用 Firebase 原生 @Exclude,而不是使用 @JsonIgnore。 比如我在一个类似的项目中工作,我的模型是这样的。

package com.limte.app.borrador_1.mModel;

import com.google.firebase.database.Exclude;
import com.google.firebase.database.ServerValue;

/**
 * Created by Familia on 20/12/2016.
 */

public class ChatItem {
    String chatName;
    Long creationDate;


    public ChatItem() {
    }

    public String getChatName() {
        return chatName;
    }

    public void setChatName(String chatName) {
        this.chatName = chatName;
    }

    public java.util.Map<String, String> getCreationDate() {
        return ServerValue.TIMESTAMP;
    }

    @Exclude
    public Long getCreationDateLong() {
        return creationDate;
    }
    public void setCreationDate(Long creationDate) {
        this.creationDate = creationDate;
    }

}

这段代码有效!在 Firebase 中,结果是: Results

【讨论】:

    【解决方案5】:

    Server.TIMESTAMP 最常见的用途是:

    1. 设置数据发送到服务器时的服务器值
    2. 从 firebase 获取此模型,然后轻松将其转换为 Long

    这个技巧让我省去了只为 1 个值处理 2 个不同字段的繁重工作

        public class HandleTimestampFirebaseObject {
    
        Object timestamp;
    
        public HandleTimestampFirebaseObject() {
    
        }
    
        public Object getTimestamp(){
            if(timestamp instanceof Double){
    
          /*    this will handle the case of AFTER fetch from backend,and  
                serialize to object into SharedPreferences for example ,when the 
                Object casting automatically into Double.
                (Anyway,call (long)getTimestamp from your code who use this model*/
                return ((Double) timestamp).longValue();
            }
            else{
                return timestamp;  //this handle to firebase requirement in the server side(Object needed)
            }
        }
    

    【讨论】:

      【解决方案6】:

      相同的解决方案,但我使用这个。

      @IgnoreExtraProperties
      public class FIRPost {
          Object timestamp;
      
          public FIRPost() {
              // Default constructor required for calls to DataSnapshot.getValue(FIRPost.class)
              this.timestamp = ServerValue.TIMESTAMP;
          }
      
          public Object getTimestamp() {
              return timestamp;
          }
      
          @Exclude
          public Long getTimestamp(boolean isLong) {
              if (timestamp instanceof Long) return (Long) timestamp;
              else return null;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-02-02
        • 2020-04-12
        • 1970-01-01
        • 2017-06-18
        • 1970-01-01
        • 2020-03-28
        • 1970-01-01
        相关资源
        最近更新 更多