我使用 Kotlin,所以我想要一个 Kotlin 解决方案,而不是 Java 解决方案。
所以首先我会仔细研究@FrostRocket 的解决方案作为起点。 @FrostRocket 的解决方案对我很有用。
就我而言,我忽略了所有的 Kotlin 世界。以及我只能使用 OffsetDateTime 而不能使用日历类。另外,我之前从来没有用过协程,所以我不得不阅读和研究 Kotlin 中的协程。如果您在我的代码中发现一些理论或实际错误,请告诉我。
首先在我的扩展包中添加一个新文件:ContextExtention.kt
import android.app.DatePickerDialog
import android.app.TimePickerDialog
import android.content.Context
import android.text.format.DateFormat
import java.time.OffsetDateTime
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
suspend fun Context.openDateTimePicker(offsetDateTime: OffsetDateTime = OffsetDateTime.now()): OffsetDateTime =
suspendCoroutine { continuation ->
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, day ->
//month (0-11 for compatibility with Calendar#MONTH)
// day of the month (1-31, depending on month)
val timeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
offsetDateTime.let {
val newOffsetDateTime =
offsetDateTime.withHour(hour).withMinute(minute).withYear(year)
//withMonth from 1 (January) to 12 (December)
//so I have to adapt it.
.withMonth((month+1))
//withDayOfMonth from 1 to 28-31
//so no need adaptation
.withDayOfMonth(day)
continuation.resume(newOffsetDateTime)
}
}
TimePickerDialog(
this,
timeSetListener,
offsetDateTime.hour,
offsetDateTime.minute,
DateFormat.is24HourFormat(this)
).show()
}
//the initially selected month (0-11 for compatibility with Calendar#MONTH)
//when offsetDateTime.monthValue from 1 (January) to 12 (December)
//so I have to adapt it.
DatePickerDialog(
this,
dateSetListener,
offsetDateTime.year,
(offsetDateTime.monthValue-1),
offsetDateTime.dayOfMonth
).show()
}
那么我怎样才能运行一个挂起的函数呢?所以你在 kotlinx.coroutines.Job 中运行一个协程,CoroutineScope 让我想起了 iPhone 编程中的 Grand Central Dispatcher 那里有一个服务质量列表。
在这种情况下,如果您想使用 UI 线程,您必须使用:Dispatchers.Main 或 Dispatchers.Main.immediate 如果您需要更好的服务。
import android.widget.TextView
import androidx.lifecycle.Observer
// the R import here
// the openDateTimePicker import here
// the TimeHelper (is text formatter) import here
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
class FooFragment : Fragment() {
private lateinit var viewModel: FooViewModel
private lateinit var dateButton: Button
private lateinit var dateText: TextView
private var datePickerJob : Job? = null
val uiScope = CoroutineScope(Dispatchers.Main)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val root =
inflater.inflate(R.layout.foo_fragment, container, false)
dateButton = root.findViewById(R.id.textButtonChangeDate)
dateText = root.findViewById(R.id.textViewWeighingDateValue)
viewModel = ViewModelProvider(this).get(FooViewModel::class.java)
return root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel.dateTimeText.observe(viewLifecycleOwner, Observer {
dateText.text = it.format(TimeHelper.formatter)
//the call to setNewDateTime will refresh this value
})
}
override fun onStart() {
super.onStart()
dateButton.setOnClickListener {
datePickerJob = uiScope.launch {
viewModel.setNewDateTime(context?.openDateTimePicker())
//setNewDateTime is a setValue in a MutableLiveData
}
}
}
override fun onStop() {
super.onStop()
dateButton.setOnClickListener(null)
datePickerJob?.cancel()
}
}