¡Hola a todos!
Hoy me gustaría compartir con ustedes cómo podemos usar el patrón EventBus, un subconjunto Publicar – Suscribirse patrón, para la comunicación separada entre diferentes componentes.
Este patrón puede ser un buen enfoque si desea enviar (publicar) y recibir y responder a datos de ComponentA (pagar por adelantado) del componente B.
La mejor analogía que se me ocurrió para este wacon una máquina expendedora de boletos que le da un número de boleto, después de haber pedido esta deliciosa comida en un restaurante de una cadena de comida rápida local, y luego muestra en la pantalla el titular del número de boleto al que puede ir a recoger la comida.
Usaremos Kotlin para este tutorial.
Crearemos tres componentes diferentes para este ejercicio, cada uno con su propia responsabilidad:
- Maquina de boletos: Responsable de darte su número de ticket después de pedir comida y por informar a alguien Quien esté interesado (o nadie) sepa que hay un nuevo orden.
- TicketScreen: Responsable de la información que pueda recoger el titular del número de billete.
- HappyCustomer A y B.: Clientes que piden comida. Recibirá un número de boleto único de TicketMachine y espere a que TicketScreen envíe su número de ticket.
Usaremos esta framework para su implementación en Android. Agregue la siguiente línea a su app / build.gradle expediente:
// Event bus
implementation 'org.greenrobot:eventbus:3.2.0'
Para la publicación y las suscripciones, la interfaz utiliza el tipo de objeto para separar lo que se publica y a quién debe entregarse. Empecemos por definir nuestros modelos.
Comida:
Cuando un nuevo cliente selecciona el tipo de comida deseado, solo conoce el nombre de la hamburguesa que ha elegido, por lo que la posible implementación será la siguiente clase de datos:
data class Meal(var burgerName : String)Publisher: CustomerA...Z
Subscriber(s): TicketMachine
Comida detallada:
Luego de recibir los detalles de la comida, TicketMachine se encargará de asignar un número de ticket único, creando así el siguiente tipo:
data class DetailedMeal(val meal : Meal,
val ticket : Ticket)Publisher: TicketMachine
Subscriber(s): TicketScreen
Comida lista:
Una vez que la comida esté lista y lista para la entrega, TicketScreen deberá informar al titular del número de boleto que puede ir a buscar su delicioso almuerzo. Por razones analíticas internas, necesitaremos registrarnos para la entrega de cada comida, por lo que nuestro objetivo puede ser el siguiente:
data class FinishedMeal(val meal: DetailedMeal,
val deliveredTime : Date)Publisher: TicketScreen
Subscriber(s): CustomerA...Z
Para simplificar, cada cliente tiene un botón único que se inicia ordenando comida intención. TicketMachine y TicketScreen un hijo único asignaturascuyos oyentes comienzan / detienen están conectados a actividades ciclo vital.
Actividad principal
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)btnCustomerA.setOnClickListener {
EventBus.getDefault().post(
Meal(
"Single Happy Burger"
)
)
}
btnCustomerB.setOnClickListener {
EventBus.getDefault().post(
Meal(
"Double Happy Burger"
)
)
}
}
}
Hemos agregado acciones de pedido para cada cliente disponible. Ahora debemos registrarnos para comenzar a prestar atención a cualquier evento que nos pueda interesar y cancelar el registro cuando estemos fuera del negocio. Al mismo tiempo, digamos a TicketMachine y TicketScreen si comienzan a funcionar o no:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)btnCustomerA.setOnClickListener {
EventBus.getDefault().post(
Meal(
"Single Happy Burger"
)
)
}
btnCustomerB.setOnClickListener {
EventBus.getDefault().post(
Meal(
"Double Happy Burger"
)
)
}
}
override fun onStart() {
super.onStart()
EventBus.getDefault().register(this)
TicketMachine.onStart()
TicketScreen.onStart()
}
override fun onStop() {
super.onStop()
EventBus.getDefault().unregister(this)
TicketMachine.onStop()
TicketScreen.onStop()
}
}
Todo lo que queda es decir que necesitamos saber cuándo está lista la comida:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)btnCustomerA.setOnClickListener {
EventBus.getDefault().post(
Meal(
"Single Happy Burger"
)
)
}
btnCustomerB.setOnClickListener {
EventBus.getDefault().post(
Meal(
"Double Happy Burger"
)
)
}
}
override fun onStart() {
super.onStart()
EventBus.getDefault().register(this)
TicketMachine.onStart()
TicketScreen.onStart()
}
override fun onStop() {
super.onStop()
EventBus.getDefault().unregister(this)
TicketMachine.onStop()
TicketScreen.onStop()
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onOrderReady(meal: FinishedMeal) {
Toast.makeText(this, "Meal ready for ticket number: ${meal.meal.ticket.number} at ${meal.deliveredTime}", Toast.LENGTH_LONG).show()
}
}
Nota: Estamos suscribiendo Hilo principal porque te mostraremos brindisque se procesa en él.
Nota 2: Más información sobre la interpolación de cadenas aquí.
Maquina de boletos
Él tiene propiedad con el número de ticket actual y se encarga de generar otro.
object TicketMachine {
var currentTicket = 0
private set
private fun getNextTicket() {
currentTicket++
}
}
Además, necesita saber cuándo se ordenó la nueva comida y adjuntar su número de boleto único y la hora en que se imprimió.
object TicketMachine {
var currentTicket = 0
private setfun
onStart() {
EventBus.getDefault().register(this)
}fun onStop() {
EventBus.getDefault().unregister(this)
}
private fun getNextTicket() {
currentTicket++
}
@Subscribe
fun onNewCustomer(meal: Meal) {
getNextTicket()
val detailedMeal = attachTicketToMeal(meal)
askToPrepareMeal(detailedMeal)
}
private fun attachTicketToMeal(meal: Meal): DetailedMeal {
return DetailedMeal(
meal,
Ticket(
currentTicket,
Calendar.getInstance().time
)
)
}
private fun askToPrepareMeal(meal: DetailedMeal) {
EventBus.getDefault().post(meal)
}
}
Nota: Dado que no es necesario procesar ninguna parte de la interfaz de usuario, pagar por adelantado anotación está en el estado predeterminado.
TicketScreen
Para este ejercicio usaremos y Contador regresivo simule el momento en que debe completarse la comida. Usaremos uno simple para registrar nuestros pedidos. Lista de enlacescual es el tipo Frenteasí es FIFO (primero en entrar primero en salir).
object TicketScreen
{
private const val AVERAGE_MEAL_TIME: Long = 10 * 1000 // 10 secondsprivate val orders = LinkedList<DetailedMeal>()
private var timer : CountDownTimer? = null
fun onStart() {
setTimerConditions()
timer?.start()
EventBus.getDefault().register(this)
}
fun onStop() {
EventBus.getDefault().unregister(this)
timer?.cancel()
}
private fun setTimerConditions()
{
timer = object: CountDownTimer(
Long.MAX_VALUE,
AVERAGE_MEAL_TIME
) {
override fun onTick(millisUntilFinished: Long)
{
val order = orders.poll() ?: return
...
}
override fun onFinish() { /* will never happen */ }
}
}
}
Entonces, ahora tenemos que decir que queremos saber cuándo se asoció la comida con el número de boleto para poder comenzar a cocinar.
object TicketScreen
{
private const val AVERAGE_MEAL_TIME: Long = 10 * 1000 // 10 secondsprivate val orders = LinkedList<DetailedMeal>()
private var timer : CountDownTimer? = null
fun onStart() {
setTimerConditions()
timer?.start()
EventBus.getDefault().register(this)
}
fun onStop() {
EventBus.getDefault().unregister(this)
timer?.cancel()
}
private fun setTimerConditions()
{
timer = object: CountDownTimer(
Long.MAX_VALUE,
AVERAGE_MEAL_TIME
) {
override fun onTick(millisUntilFinished: Long)
{
val order = orders.poll() ?: return
...
}
override fun onFinish() { /* will never happen */ }
}
}
@Subscribe
fun onNewMeal(meal: DetailedMeal) {
orders.add(meal)
}
}
Entonces solo queda decir que la próxima comida en la cola está lista para que el cliente adecuado pueda venir a recogerla.
object TicketScreen
{
private const val AVERAGE_MEAL_TIME: Long = 10 * 1000 // 10 secondsprivate val
orders = LinkedList<DetailedMeal>()
private var timer : CountDownTimer? = nullfun
onStart() {
setTimerConditions()
timer?.start()
EventBus.getDefault().register(this)
}fun onStop() {
EventBus.getDefault().unregister(this)
timer?.cancel()
}
private fun setTimerConditions()
{
timer = object: CountDownTimer(
Long.MAX_VALUE,
AVERAGE_MEAL_TIME
) {
override fun onTick(millisUntilFinished: Long)
{
val order = orders.poll() ?: return
callCustomer(order)
}
override fun onFinish() { /* will never happen */ }
}
}
private fun callCustomer(meal : DetailedMeal) {
val finishedMeal = FinishedMeal(
meal,
Calendar.getInstance().time
)
EventBus.getDefault().post(finishedMeal)
}
@Subscribe
fun onNewMeal(meal: DetailedMeal) {
orders.add(meal)
}
}
Eso es todo por hoy. ¡Si lo desea, puede hacer cualquier pregunta o agregar sugerencias!
¡Salud!