Una mejor comprensión para la separación de preocupaciones. Androide; Kotlin -- android campo con kotlin campo con mvvm camp codereview Relacionados El problema

A better understanding for separation of concerns. Android; Kotlin


2
vote

problema

Español

Soy un desarrollador de Android con solo 5 meses de experiencia. Todavía estoy aprendiendo y tratando de hacer mi mejor esfuerzo.

En este momento estoy interesado en el concepto de Separation of concerns . Sin embargo, entiendo lo que significa y estoy haciendo todo lo posible para seguirlo en mi desarrollo de Android, me encontré un poco confundido cuando comencé a aprender sobre la arquitectura limpia.

Me gustaría mostrar mi parte de código, y si, es posible, obtener algunos comentarios sobre mi implementación y su corrección cuando se trata de Separation of concerns

Código [NOTA: Estoy usando MVVM en esta aplicación]:

popularmoviesfragment:

  class MoviesPopularFragment : Fragment() {      private val moviesViewModel: MoviesViewModel by activityViewModels()     private val adapter = PopularMoviesRecyclerAdapter()      override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {         val binding = FragmentMoviesPopularBinding.inflate(inflater, container, false)          binding.viewModel = moviesViewModel         binding.popularMoviesRV.layoutManager = GridLayoutManager(requireContext(), 2)         binding.popularMoviesRV.adapter = adapter          moviesViewModel.popularMoviesState.observe(viewLifecycleOwner, { state ->             when (state) {                 is PopularMoviesState.Content -> {                     // TODO: Find a way to deal with this via DataBinding                     binding.popularMoviesSwipeRefresh.isRefreshing = false                     binding.progressBarLayout.visibility = View.GONE                     binding.pageNavigation.visibility = View.VISIBLE                      adapter.submitList(state.response.results)                 }                 is PopularMoviesState.Failure -> {                     // TODO: Find a way to deal with this via DataBinding                     binding.popularMoviesSwipeRefresh.isRefreshing = false                     binding.progressBarLayout.visibility = View.GONE                     binding.pageNavigation.visibility = View.VISIBLE                      adapter.submitList(state.cachedListOfMovies)                     showSnackbar(requireView(), getString(R.string.movies_popular_message_viewing_cached_content), Snackbar.LENGTH_INDEFINITE)                 }             }         })          // TODO: Look into implementing this via DataBinding         binding.popularMoviesSwipeRefresh.setOnRefreshListener {             binding.popularMoviesSwipeRefresh.isRefreshing = true             moviesViewModel.fetchPopularMovies()         }          return binding.root     }      private fun showSnackbar(view: View, message: String, length: Int) {         val snackbar = Snackbar.make(view, message, length)         snackbar.animationMode = Snackbar.ANIMATION_MODE_SLIDE         snackbar.setAction(view.context.getString(R.string.alert_dialog_default_button_ok)) { snackbar.dismiss() }         snackbar.show()     } }   

PelículasViewModel.KT:

  fun fetchPopularMovies(page: Int = currentPage) {         viewModelScope.launch {             val result = MainRepository.fetchPopularMovies(page = page)              _popularMoviesState.value = when (result) {                  is PopularMoviesState.Loading -> PopularMoviesState.Loading                 is PopularMoviesState.Content -> {                     //TODO: Perhaps find a way to work with pages in a better, more isolated way.                     currentPage = result.response.page                     PopularMoviesState.Content(result.response)                 }                 is PopularMoviesState.Failure -> {                     PopularMoviesState.Failure(result.errorMessage, result.cachedListOfMovies)                 }             }         }     }   

mainrepository.kt

  suspend fun fetchPopularMovies(page: Int = 1) = try {         val response = IPopularMovies.getInstance().getMovies(page = page)          if (response.code() == 200) {             savePopularMoviesToCache(response.body()!!.results)             PopularMoviesState.Content(response.body()!!)         } else {             PopularMoviesState.Failure(response.body()!!.status_message, popularMovieDao.getMovies() ?: listOf())         }     } catch (error: Throwable) {         PopularMoviesState.Failure(error.localizedMessage!!, popularMovieDao.getMovies() ?: listOf())     }      private suspend fun savePopularMoviesToCache(listOfMovies: List<PopularMovie>) {         popularMovieDao.clearTable()         popularMovieDao.addMovies(listOfMovies)     }   

Estoy interesado principalmente en MainRepository y su implementación de fetchPopularMovies Como puede ver, esta función no tiene solo 1 trabajo, de hecho, hace varias cosas dependiendo de la situación en la que está.

  1. TIPTE PELÍCULAS UTILIZANDO EL USO DE LA INTERFAZA DE RETROFIT. - & gt; Exactamente lo que debe hacer Luego, tampoco: 2.1. Guarda películas al caché o 2.2. Obtiene películas de caché

Por lo tanto, realmente no hace 1 cosa, ya que si seguimos el Separation of concerns si entiendo correctamente.

Aquí es cómo creo que una implementación correcta podría verse:

  1. en MainRepository, cree 2 funciones separadas. 1 Para guardar películas en caché, 1 para obtener películas de caché

  2. en ViewModel hacen lo mismo y cree 2 funciones separadas. 1 por ahorrar en caché. 1 para obtener de caché

  3. en fragmento, donde observamos. Si el éxito - & gt; Llame a la función Savecache en ViewModel Si el fracaso - & gt; Llame a GetCache en ViewModel

Por favor, dame algunos comentarios sobre mi proceso de pensamiento. ¡Realmente apreciaría esto!

Original en ingles

I am an Android developer with only 5 months of experience. I am still learning and trying to do my best.

Right now I am interested in concept of Separation of concerns. I do understand what it means and I am trying my best to follow it in my android development, however, I found myself a bit confused when I started learning about Clean Architecture.

I would like to show my bit of code, and if, possible, get some feedback on my implementation and its correctness when it comes to Separation of concerns

Code [Note: I am using MVVM in this app]:

PopularMoviesFragment:

class MoviesPopularFragment : Fragment() {      private val moviesViewModel: MoviesViewModel by activityViewModels()     private val adapter = PopularMoviesRecyclerAdapter()      override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {         val binding = FragmentMoviesPopularBinding.inflate(inflater, container, false)          binding.viewModel = moviesViewModel         binding.popularMoviesRV.layoutManager = GridLayoutManager(requireContext(), 2)         binding.popularMoviesRV.adapter = adapter          moviesViewModel.popularMoviesState.observe(viewLifecycleOwner, { state ->             when (state) {                 is PopularMoviesState.Content -> {                     // TODO: Find a way to deal with this via DataBinding                     binding.popularMoviesSwipeRefresh.isRefreshing = false                     binding.progressBarLayout.visibility = View.GONE                     binding.pageNavigation.visibility = View.VISIBLE                      adapter.submitList(state.response.results)                 }                 is PopularMoviesState.Failure -> {                     // TODO: Find a way to deal with this via DataBinding                     binding.popularMoviesSwipeRefresh.isRefreshing = false                     binding.progressBarLayout.visibility = View.GONE                     binding.pageNavigation.visibility = View.VISIBLE                      adapter.submitList(state.cachedListOfMovies)                     showSnackbar(requireView(), getString(R.string.movies_popular_message_viewing_cached_content), Snackbar.LENGTH_INDEFINITE)                 }             }         })          // TODO: Look into implementing this via DataBinding         binding.popularMoviesSwipeRefresh.setOnRefreshListener {             binding.popularMoviesSwipeRefresh.isRefreshing = true             moviesViewModel.fetchPopularMovies()         }          return binding.root     }      private fun showSnackbar(view: View, message: String, length: Int) {         val snackbar = Snackbar.make(view, message, length)         snackbar.animationMode = Snackbar.ANIMATION_MODE_SLIDE         snackbar.setAction(view.context.getString(R.string.alert_dialog_default_button_ok)) { snackbar.dismiss() }         snackbar.show()     } } 

MoviesViewModel.kt:

fun fetchPopularMovies(page: Int = currentPage) {         viewModelScope.launch {             val result = MainRepository.fetchPopularMovies(page = page)              _popularMoviesState.value = when (result) {                  is PopularMoviesState.Loading -> PopularMoviesState.Loading                 is PopularMoviesState.Content -> {                     //TODO: Perhaps find a way to work with pages in a better, more isolated way.                     currentPage = result.response.page                     PopularMoviesState.Content(result.response)                 }                 is PopularMoviesState.Failure -> {                     PopularMoviesState.Failure(result.errorMessage, result.cachedListOfMovies)                 }             }         }     } 

MainRepository.kt

suspend fun fetchPopularMovies(page: Int = 1) = try {         val response = IPopularMovies.getInstance().getMovies(page = page)          if (response.code() == 200) {             savePopularMoviesToCache(response.body()!!.results)             PopularMoviesState.Content(response.body()!!)         } else {             PopularMoviesState.Failure(response.body()!!.status_message, popularMovieDao.getMovies() ?: listOf())         }     } catch (error: Throwable) {         PopularMoviesState.Failure(error.localizedMessage!!, popularMovieDao.getMovies() ?: listOf())     }      private suspend fun savePopularMoviesToCache(listOfMovies: List<PopularMovie>) {         popularMovieDao.clearTable()         popularMovieDao.addMovies(listOfMovies)     } 

I am mostly interested in MainRepository and its implementation of fetchPopularMovies As you can see, this one function does not have only 1 job, in fact, it does multiple things depending on the situation it is in.

  1. It fetches movies using Retrofit Interface. -> Exactly what it should do Then it either: 2.1. Saves movies to cache or 2.2. Gets movies from cache

Therefore it does not really do 1 thing as it should if we follow the Separation of concerns if I understand correctly.

Here is how I think a correct implementation could look:

  1. In MainRepository, create 2 separate functions. 1 for saving movies to cache, 1 for getting movies from cache

  2. In ViewModel do the same thing and create 2 separate functions. 1 for saving to cache. 1 for getting from cache

  3. In Fragment, where we observe. If success -> call saveCache function in ViewModel if Failure -> call getCache in ViewModel

Please give me some feedback on my thought process. I would really appreciate this!

        
 
 

Lista de respuestas


Relacionados problema

3  Cargando subistemas de TreeView en el fondo  ( Loading sub items of treeview in background ) 
Estoy trabajando con un TreeView (Control predeterminado desde .NET Framework) que muestra datos hierachicales. Los datos están vinculados a la vista utiliz...

2  Establecer objetos para MVVM adecuados en Knockout  ( Structuring objects for proper mvvm in knockout ) 
Estoy trabajando con Knockout y estoy tratando de mantenernos cierto la estructura MVVM y tratar de hacer que los objetos tengan esa dependencia entre sí. M...

4  Insertar objeto de modelo de manera efectiva usando la entidad Framework  ( Insert model object effectively using entity framwork ) 
Tengo una aplicación MVVM de WPF. Tengo un modelo de cliente que es generado por un marco de entidad (primer enfoque de la base de datos) y un 99887766555443...

1  Una compilación ViewModel con Reactiveui 8 para obtener imágenes web  ( A viewmodel build with reactiveui 8 to get web images ) 
Esta es una aplicación de práctica que construí para aprender RX.NET & AMP; Rxui. Sigue el patrón MVVM y está escrito en C # con WPF. aquí es un enlace a un...

1  Elija aleatoriamente un juego ejecutable de una carpeta 2.0  ( Randomly choose a game executable from a folder 2 0 ) 
Después de preguntarle a Elija aleatoriamente un juego ejecutable de una carpeta < / a>, aplicé los cambios recomendados. También rediseñé el programa para h...

7  Ver base de modelo  ( View model base ) 
Necesitaba escribir código en WPF para un cliente. La solicitud se realiza con prisma (no mi decisión, ya tenían personas que trabajaban en ella), por lo que ...

1  Usando VUE para ayudar a formar validación con peso para la edad  ( Using vue to help form validation with weight for age ) 
Estoy refactorizando una página web muy antigua que calcula las dosis de los medicamentos de Bolus y Infusión para los niños de la edad prematura a la edad ad...

6  Vistas de grasa para editar imágenes  ( Fat viewmodels for editing images ) 
¿Cómo debo tratar con ViewModel s que son "grasas"? O debería simplemente aceptarlo a veces. Ejemplo: uno de mis ViewModel S (Edición de la página de la...

6  Modelo de vista de reloj simple  ( Simple clock view model ) 
He estado tratando de envolver mi cabeza alrededor de MVVM durante la última semana o más y aún luchando un poco. He visto Jason Dolingers MVVM video y ha p...

7  MV * Patrón para un juego de mesa  ( Mv pattern for a board game ) 
He hecho un pequeño juego en JavaScript, mientras se entera simultáneamente sobre el controlador de visualización modelo más popular. El juego es este, hay 3 ...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos