How to save LocalData in Firebase Realtime database?

懵懂的女人 提交于 2021-01-28 03:24:16

问题


I am very new using Kotlin and programming and I am currently making a calendar with events. My problem comes when I want to connect these events to firebase.

I am using an example that I found in git (https://github.com/kizitonwose/CalendarView) that uses the ThreeTen library for dates. This is the Event object:

class Event (val id: String, val text: String, val date: LocalDate) : Serializable

The data variable is of the LocalData type and this is what is causing me problems since it seems that Firebase only accepts variables of type String, Int, etc ...

I tried to pass the variable to String with toString and with Gson (), without success.

Here is the code if it helps

 private val inputDialog by lazy {
    val editText = AppCompatEditText(requireContext())
    val layout = FrameLayout(requireContext()).apply {
        // Setting the padding on the EditText only pads the input area
        // not the entire EditText so we wrap it in a FrameLayout.
        setPadding(20, 20, 20, 20)
        addView(editText, FrameLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT))
    }
    AlertDialog.Builder(requireContext())
        .setTitle(getString(R.string.example_3_input_dialog_title))
        .setView(layout)
        .setPositiveButton(R.string.save) { _, _ ->
            saveEvent(editText.text.toString())
            // Prepare EditText for reuse.
            editText.setText("")
        }
        .setNegativeButton(R.string.close, null)
        .create()
        .apply {
            setOnShowListener {
                // Show the keyboard
                editText.requestFocus()
                context.inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0)
            }
            setOnDismissListener {
                // Hide the keyboard
                context.inputMethodManager.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0)
            }
        }
}
private var selectedDate: LocalDate? = null
private val today = LocalDate.now()
private val titleSameYearFormatter = DateTimeFormatter.ofPattern("MMMM")
private val titleFormatter = DateTimeFormatter.ofPattern("MMM yyyy")
private val selectionFormatter = DateTimeFormatter.ofPattern("yyyy MM dd")
private val events = mutableMapOf<LocalDate, List<Event>>()
private var prueba = Gson().toJson(events)
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    return inflater.inflate(R.layout.fragment_calendar, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    mDatabaseReference = mDatabase!!.reference.child("events")
    exThreeRv.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false)
    exThreeRv.adapter = eventsAdapter
    exThreeRv.addItemDecoration(DividerItemDecoration(requireContext(), RecyclerView.VERTICAL))
    val daysOfWeek = daysOfWeekFromLocale()
    val currentMonth = YearMonth.now()
    exThreeCalendar.setup(currentMonth.minusMonths(10), currentMonth.plusMonths(10), daysOfWeek.first())
    exThreeCalendar.scrollToMonth(currentMonth)
    if (savedInstanceState == null) {
        exThreeCalendar.post {
            // Show today's events initially.
            selectDate(today)
        }
    }
    class DayViewContainer(view: View) : ViewContainer(view) {
        lateinit var day: CalendarDay // Will be set when this container is bound.
        val textView = view.exThreeDayText
        val dotView = view.exThreeDotView
        init {
            view.setOnClickListener {
                if (day.owner == DayOwner.THIS_MONTH) {
                    selectDate(day.date)
                }
            }
        }
    }
    exThreeCalendar.dayBinder = object : DayBinder<DayViewContainer> {
        override fun create(view: View) = DayViewContainer(view)
        override fun bind(container: DayViewContainer, day: CalendarDay) {
            container.day = day
            val textView = container.textView
            val dotView = container.dotView
            textView.text = day.date.dayOfMonth.toString()
            if (day.owner == DayOwner.THIS_MONTH) {
                textView.makeVisible()
                when (day.date) {
                    today -> {
                        textView.setTextColorRes(R.color.white)
                        textView.setBackgroundResource(R.drawable.today_bg)
                        dotView.makeInVisible()
                    }
                    selectedDate -> {
                        textView.setTextColorRes(R.color.white)
                        textView.setBackgroundResource(R.drawable.selected_bg)
                        dotView.makeInVisible()
                    }
                    else -> {
                        textView.setTextColorRes(R.color.black)
                        textView.background = null
                        dotView.isVisible = events[day.date].orEmpty().isNotEmpty()
                    }
                }
            } else {
                textView.makeInVisible()
                dotView.makeInVisible()
            }
        }
    }
    exThreeCalendar.monthScrollListener = {
        requireActivity().home.text = if (it.year == today.year) {
            titleSameYearFormatter.format(it.yearMonth)
        } else {
            titleFormatter.format(it.yearMonth)
        }
        // Select the first day of the month when
        // we scroll to a new month.
        selectDate(it.yearMonth.atDay(1))
    }
    class MonthViewContainer(view: View) : ViewContainer(view) {
        val legendLayout = view.legendLayout
    }
    exThreeCalendar.monthHeaderBinder = object : MonthHeaderFooterBinder<MonthViewContainer> {
        override fun create(view: View) = MonthViewContainer(view)
        override fun bind(container: MonthViewContainer, month: CalendarMonth) {
            // Setup each header day text if we have not done that already.
            if (container.legendLayout.tag == null) {
                container.legendLayout.tag = month.yearMonth
                container.legendLayout.children.map { it as TextView }.forEachIndexed { index, tv ->
                    tv.text = daysOfWeek[index].name.first().toString()
                    tv.setTextColorRes(R.color.black)
                }
            }
        }
    }
    exThreeAddButton.setOnClickListener {
        inputDialog.show()
    }
}
private fun selectDate(date: LocalDate) {
    if (selectedDate != date) {
        val oldDate = selectedDate
        selectedDate = date
        oldDate?.let { exThreeCalendar.notifyDateChanged(it) }
        exThreeCalendar.notifyDateChanged(date)
        updateAdapterForDate(date)
    }
}
private fun saveEvent(text: String) {
    if (text.isBlank()) {
        Toast.makeText(requireContext(),
            R.string.example_3_empty_input_text, Toast.LENGTH_LONG).show()
    } else {
        selectedDate?.let {
            events[it] = events[it].orEmpty().plus(
                Event(
                    UUID.randomUUID().toString(),
                    text,
                    it
                )
            )
            uploadFirebase()
            updateAdapterForDate(it)
        }
    }
}
private fun deleteEvent(event: Event) {
    val date = event.date
    events[date] = events[date].orEmpty().minus(event)
    updateAdapterForDate(date)
}
private fun updateAdapterForDate(date: LocalDate) {
    eventsAdapter.events.clear()
    eventsAdapter.events.addAll(events[date].orEmpty())
    eventsAdapter.notifyDataSetChanged()
    exThreeSelectedDateText.text = selectionFormatter.format(date)
}

fun uploadFirebase(){
    val newEvent = mDatabaseReference.push()
    newEvent.setValue(events)
}


override fun onStart() {
    super.onStart()
}
override fun onStop() {
    super.onStop()
}

}


回答1:


There is no way you can add a property of type LocalDate in a Firebase Realtime database because it is not a supported data-type. However, there are two ways in which you can solve this:

  1. You save the date as a ServerValue.TIMESTAMP, which basically means that you save the number of seconds that have elapsed since the Unix epoch. In this case, the server writes the current date in the database. To achieve this, please see my answer from the following post:

    • How to save the current date/time when I add new value to Firebase Realtime Database
  2. You specify a custom long value for your date field. In this case, it's up to you to determine what date is written.

Unfortunately, there is no way you can combine these two options, you can use one or the other.

When talking about a LocalDate, we usually talk about an offset, in which case, this what I'll do. I'll store a Timestamp property, as explained at point one, that will let the server populate with the server Timestamp, as well as an offset property, that should be populated with the offset in days/hours.



来源:https://stackoverflow.com/questions/59586220/how-to-save-localdata-in-firebase-realtime-database

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!