Issues accessing ViewModel and observing LiveData in views
Opened this issue · 5 comments
Hi,
I've been trying to access viewmodel and livedata in my views using Magellan but it don't work.
Am I missing something?
I tryed to access the ViewModel this way
MyViewModel = ViewModelProviders.of((LifeCycleOwner)getScreen().getActivity()).get(MyViewModel.class);
But it keep telling me that I can't call virtual method "getActivity()" from null object reference.
Does anyone else have the same problem as me?
Thank you for your help,
Cordially,
Matthieu
Hi Matthieu,
First of all, Magellan has not be designed to work well with ViewModel and LiveData (it was created before those even existed). So anything you are trying to do there is unsupported for now.
With that being said, getActivity() definitely returns your single Activity. Can you share more of your code? How are you initializing Magellan, where do you call getActivity()? (getActivity() returns null until createView() is called)
Hi,
Here is the way I initialized Magellan. Everything seemed to work well, is that what I'm concerned about, nothing should have gone wrong.
Parent activity
`public class NewInterventionFlow extends SingleActivity {
@BindView(R.id.intervention_flow_toolbar)Toolbar toolbar;
@Override
protected Navigator createNavigator() {
return Navigator.withRoot(new StepOneScreen()).build();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new_intervention_flow);
ButterKnife.bind(this);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
assert actionBar!=null;
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeAsUpIndicator(R.drawable.ic_menu_black_24dp);
}
}`
StepOneScreen
public class StepOneScreen extends Screen<StepOneView>{ @Override protected StepOneView createView(Context context) { return new StepOneView(context); } }
StepOneScreen
`public class StepOneView extends BaseScreenView {
@BindView(R.id.company_autocomplete)AutoCompleteTextView companyAutocomplete;
@BindView(R.id.contact_autocomplete)AutoCompleteTextView contactAutocomplete;
@BindView(R.id.intervention_date)TextView interventionDate;
public StepOneView(Context context) {
super(context);
inflate(context, R.layout.view_intervention_step_one, this);
ButterKnife.bind(this);
/*How I initialize the viewmodel */
MyViewModel viewModel = ViewModelProviders.of(((LifecycleOwner)getScreen().getActivity())).get(MyViewModel.class);
}
}`
This always failed because I tried to access a null object. Either the screen or the returned activity are nulls. When I tried to create my viewmodel directly in the activity and then get the viewmodel from the activity (always by going through getScreen().getActivity() I got the same, can't access null reference.
By the way are there any plans to "adapt" Magellan to the new architecture components? I have the feeling this combination could make powerful application flows.
Thank you :)
While you are creating the view, the screen is not yet attached to it so you can't call getScreen. But the context you get is you Activity! So you should be able to just do ViewModelProviders.of((LifecycleOwner)context).get(MyViewModel.class);
Let me know if this works.
That being said, the point of ViewModel is to retain your Model across Activity configuration changes like rotation. With Magellan, the Screen already survives rotation so you can simply store your data in a simple member variable of the Screen.
I don't know much about Arch components ViewModel so maybe there is some other good reason to use them.
I do plan to look into them more and see if there is a way to "adapt" magellan to them, but they solve similar problems, so not sure yet if this will make sense.
But the context you get is you Activity!
If it's the View's context, then sometimes it's ContextThemeWrapper, you know.
@Zhuinden in this case, you get the context from Magellan and it's an Activity (strongly typed to it) all the way until the very end (createVIew being called) so you are actually guaranteed that this will be an Activity.
I chose to make it a Context in the type to discourage manipulating the Activity from there (all you should need is a Context), but if you must, casting is safe.