usuario1209216
Ejemplo de modelo de vista:
public class NameViewModel extends ViewModel {
// Create a LiveData with a String
private MutableLiveData<String> mCurrentName;
public MutableLiveData<String> getCurrentName() {
if (mCurrentName == null) {
mCurrentName = new MutableLiveData<>();
}
return mCurrentName;
}
}
Actividad principal:
mModel = ViewModelProviders.of(this).get(NameViewModel.class);
// Create the observer which updates the UI.
final Observer<String> nameObserver = textView::setText;
// Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
mModel.getCurrentName().observe(this, nameObserver);
quiero llamar mModel.getCurrentName().setValue(anotherName);
en la segunda actividad y hacer que MainActivity reciba cambios. ¿Es eso posible?
saeed masoumi
Cuando usted llama ViewModelProviders.of(this)
en realidad creas/retienes un ViewModelStore
que está obligado a this
por lo que diferentes actividades tienen diferentes ViewModelStore
y cada ViewModelStore
crea una instancia diferente de un ViewModel
utilizando una fábrica determinada, por lo que no puede tener la misma instancia de un ViewModel
en diferentes ViewModelStore
s.
Pero puede lograr esto pasando una única instancia de una fábrica ViewModel personalizada que actúa como una fábrica única, por lo que siempre pasará la misma instancia de su ViewModel
entre diferentes actividades.
Por ejemplo:
public class SingletonNameViewModelFactory extends ViewModelProvider.NewInstanceFactory {
NameViewModel t;
public SingletonNameViewModelFactory() {
// t = provideNameViewModelSomeHowUsingDependencyInjection
}
@Override
public NameViewModel create(Class<NameViewModel> modelClass) {
return t;
}
}
Entonces lo que necesitas es hacer SingletonNameViewModelFactory
singleton (por ejemplo, usando Dagger) y úsalo así:
mModel = ViewModelProviders.of(this,myFactory).get(NameViewModel.class);
Nota:
Conservación ViewModel
s entre diferentes ámbitos es un anti-patrón. Se recomienda encarecidamente conservar los objetos de la capa de datos (p. ej., hacer que su Fuente de datos o Repositorio sea único) y conservar sus datos entre diferentes ámbitos (Actividades).
Leer este artículo para más detalles.
-
Si ya está almacenando datos en caché en una capa de datos singleton, ¿cuál es el punto de ViewModel?
– EpicPandaForce
19 de marzo de 2018 a las 14:36
-
@EpicPandaForce, quiero decir, no importa cómo actúe su capa de datos,
ViewModel
debe notificar sobre sus cambios de datos de alguna manera, por lo que almacenar en caché su capa de datos es una forma de mantener sus datos en diferentes ámbitos.– Saeed Masoumi
19 de marzo de 2018 a las 14:43
-
Bueno, sí, creo que tienes razón, no debería intentar hacer eso. Pero, ¿qué pasa con el fragmento? ¿Es una buena práctica hacer que los fragmentos secundarios observen el mismo modelo de vista? Por ejemplo
ViewModelProviders.of(getActivity()).get(NameViewModel.class)
fragmento interior.– usuario1209216
20 de marzo de 2018 a las 6:48
-
@user1209216 Sí, ¿por qué no ver este artículo para obtener más detalles? desarrollador.android.com/topic/libraries/architecture/…
– Saeed Masoumi
20 de marzo de 2018 a las 9:19
-
¿Cómo lograr esto si usamos DaggerViewModelFactory?
– Morteza Rastgoo
17 de agosto de 2019 a las 11:36
TotoliciCristian
Al obtener el modelo de vista usando los ViewModelProviders que está pasando como propietario del ciclo de vida MainActivity, esto le dará el modelo de vista para esa actividad. En la segunda actividad, obtendrá una instancia diferente de ese ViewModel, esta vez para su segunda actividad. El segundo modelo tendrá un segundo datos en vivo.
Lo que puede hacer es mantener los datos en una capa diferente, como un repositorio, que puede ser un singleton y de esa manera puede usar el mismo modelo de vista.
public class NameViewModel extends ViewModel {
// Create a LiveData with a String
private MutableLiveData<String> mCurrentName;
public MutableLiveData<String> getCurrentName() {
if (mCurrentName == null) {
mCurrentName = DataRepository.getInstance().getCurrentName();
}
return mCurrentName;
}
}
//SingleTon
public class DataRepository
private MutableLiveData<String> mCurrentName;
public MutableLiveData<String> getCurrentName() {
if (mCurrentName == null) {
mCurrentName = new MutableLiveData<>();
}
return mCurrentName;
}
//Singleton code
...
}
-
esta debería ser una respuesta aceptada … sin violar el patrón de arquitectura de Android
– suma20156
29 de diciembre de 2020 a las 13:40
-
Este enfoque también se recomienda aquí en este tutorial oficial:
LiveData in repositories: To avoid leaking ViewModels and callback hell, repositories can be observed
– alierdogan7
17 de junio de 2021 a las 9:43
Simplemente cree la instancia de su Ver modeloen este caso NombreVerModelo
Tu ViewModel Factory será como
class ViewModelFactory : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel?> create(modelClass: Class<T>) =
with(modelClass){
when {
isAssignableFrom(NameViewModel::class.java) -> NameViewModel.getInstance()
else -> throw IllegalArgumentException("Unknown viewModel class $modelClass")
}
} as T
companion object {
private var instance : ViewModelFactory? = null
fun getInstance() =
instance ?: synchronized(ViewModelFactory::class.java){
instance ?: ViewModelFactory().also { instance = it }
}
}
}
Y tu modelo de vista
class NameViewModel : ViewModel() {
//your liveData objects and many more...
companion object {
private var instance : NameViewModel? = null
fun getInstance() =
instance ?: synchronized(NameViewModel::class.java){
instance ?: NameViewModel().also { instance = it }
}
}
}
Ahora puedes usar ViewModelProviders
para obtener la misma instancia de su ViewModel para usar en cualquier actividad
ViewModelProviders.of(this, ViewModelFactory.getInstance()).get(NameViewModel::class.java)
O
crear una función de extensión para facilitar el acceso
fun <T : ViewModel> AppCompatActivity.getViewModel(viewModelClass: Class<T>) =
ViewModelProviders.of(this, ViewModelFactory.getInstance()).get(viewModelClass)
-
Probé esta solución pero no funciona. Intentando actualizar un TextView en un fragmento de una segunda actividad.
– Samuel
23 de enero de 2020 a las 20:49
-
¿Puede echar un vistazo a mi presentación: stackoverflow.com/questions/59887014/…
– Samuel
23 de enero de 2020 a las 21:06
Darrel Burk
El alcance/ciclo de vida de ViewModel está vinculado a una actividad simplemente porque el ViewModelStoreOwner que pasa al constructor de ViewModelProvider resulta ser la actividad.
Dado que puede proporcionar ViewModelStoreOwner, puede proporcionar fácilmente uno que tenga un ciclo de vida más largo, como la aplicación.
Puedes
- Proporcione su propia subclase de aplicación y haga que implemente ViewModelStoreOwner (y tenga un ViewModelStore)
- En las llamadas al constructor de ViewModelProvider, pase actividad.aplicación en lugar de actividad.
Esto hará que ViewModelProvider interactúe con ViewModelStore a nivel de la aplicación, lo que le permitirá crear instancias de ViewModel que tendrán el alcance de la aplicación.
La respuesta “correcta” es que “si desea compartir datos entre ellos, no deberían ser actividades diferentes, y en su lugar debería intercambiar fragmentos”.
– EpicPandaForce
19 de marzo de 2018 a las 14:34
@EpicPandaForce tal vez, pero no es así como funciona la plantilla maestra/detalle de AndroidStudio, ni los planos de arquitectura de Android
– Marca
10 de julio de 2018 a las 6:09
@Mark que es una falla de los planos de arquitectura de Android y la plantilla, entonces.
– EpicPandaForce
25/01/2019 a las 22:00
Consulte este stackoverflow.com/questions/56521969/…
– Levon Petrosián
10 de junio de 2019 a las 16:12