生产环境Android应用LocalDateTime调用isAfter()引发空指针异常求助
I’ve run into a similar issue with ThreeTen BP’s date/time classes and Android serialization libraries like Paper, so let me break down what’s likely happening and how to fix it.
The Root Cause
Your null checks are passing because the LocalDateTime instance itself isn’t null—but its internal LocalDate field is null after deserialization. Paper’s default reflection-based serialization doesn’t properly handle complex immutable value types like ThreeTen’s LocalDateTime. When you deserialize the TemplatesCacheInfo object, Paper might create a "broken" LocalDateTime instance where critical internal fields (like year in LocalDate) aren’t initialized, even though the object reference isn’t null.
This explains why your null checks (templatesCacheInfo.lastUpdate != null) pass, but calling isAfter() triggers an NPE when accessing the internal year field.
Fix Recommendations
1. Implement a Custom Serializer for LocalDateTime
The most robust fix is to tell Paper how to properly serialize/deserialize LocalDateTime with a custom adapter. Here’s a working example:
import org.threeten.bp.LocalDateTime import org.threeten.bp.format.DateTimeFormatter import io.paperdb.Serializer class LocalDateTimeSerializer : Serializer<LocalDateTime> { private val formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME override fun write(obj: LocalDateTime): ByteArray { // Serialize as a standard ISO 8601 string return formatter.format(obj).toByteArray(Charsets.UTF_8) } override fun read(bytes: ByteArray): LocalDateTime { // Deserialize from the stored string val dateString = String(bytes, Charsets.UTF_8) return LocalDateTime.parse(dateString, formatter) } override fun getUniqueTag(): String { return "org.threeten.bp.LocalDateTime" } }
Register this serializer when initializing Paper in your app:
Paper.init(context) Paper.register(LocalDateTime::class.java, LocalDateTimeSerializer())
This ensures LocalDateTime is stored as a safe, human-readable string instead of relying on Paper’s default serialization which can break internal object structure.
2. Store LocalDateTime as a String/Timestamp Instead
If you don’t want to deal with custom serializers, modify your TemplatesCacheInfo to store the date as a string (or epoch timestamp) instead of the raw LocalDateTime:
data class TemplatesCacheInfo( val lastUpdate: String, // Store ISO 8601 formatted string val templatesLanguage: String, val appVersion: String? ) : Serializable // When saving to Paper: val cacheInfo = TemplatesCacheInfo( lastUpdate = LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME), templatesLanguage = "en", appVersion = "1.0.0" ) // When reading and using the date: val lastUpdateDate = LocalDateTime.parse(cacheInfo.lastUpdate, DateTimeFormatter.ISO_LOCAL_DATE_TIME)
This bypasses the serialization issue entirely by using a primitive type that Paper handles reliably.
3. Add Defensive Checks (Temporary Workaround)
As a quick fix while implementing the proper solution, wrap the isAfter() call in a try-catch and add an extra check to validate the LocalDateTime instance:
private fun isLastUpdateChanged( templatesCacheInfo: TemplatesCacheInfo?, lastUpdateDate: LocalDateTime? ): Boolean { return try { if (lastUpdateDate != null && templatesCacheInfo != null) { // Trigger early NPE if internal fields are broken templatesCacheInfo.lastUpdate.run { year // Access internal field to validate instance isAfter(lastUpdateDate) } } else false } catch (e: NullPointerException) { false // Treat broken instances as "not changed" } }
This will catch broken instances and prevent crashes, but it’s not a long-term solution.
4. Update Paper to the Latest Version
Occasionally, serialization bugs get fixed in newer Paper releases. Check if you’re using the latest stable version and upgrade if possible—it might resolve the issue out of the box.
Final Note
The custom serializer approach is the most maintainable long-term solution, as it ensures ThreeTen’s date/time classes are handled correctly across all serialization operations.
内容的提问来源于stack exchange,提问作者Jakub Anioła

