I have an issue with the data observation and the fragment backstack on a single activity application.
For example, I have parent fragment A which will observe data from viewmodel and fill to ExitText. User can change the information in the EditText. Fragment A can navigate to fragment B and listen to B result by using setFragmentResultListener.
The problem is, when popBackStack from B, the changed data on fragment B will be revert to data from viewmodel because I observed the data in onCreateView.
Is there anyway I can retain the changed data from fragment A after popBackStack from fragment B?
Thank you!
You can use SharedViewModel since both fragments share same activity. In this way view model does not die and you can use the data.
Offical doc:
https://developer.android.com/topic/libraries/architecture/viewmodel#sharing
Related
I have a fragment that implements Recycler View with switches. RecyclerView sets id for every switch in id+=1 way. The problem is I can get nothing from these IDs as soon as calling throws NullableException. I understand that I have to call it correctly from parent, but I don`t get how to do it correctly.
There is the structure of code:
Fragment with ConstraintLayout(R.id.settingsScreen) -> RecylerView(R.id.recyclerView), that creates LinearLayouts(R.id.settingLayout) with switches(R.id.switch).
class ViewHolder{
val l : LinearLayout = view.findViewById(R.id.settingLayout)
}
if (holder.l.findViewById<SwitchCompat>(1100).isActivated){..}
throws java.lang.NullPointerException: Attempt to invoke virtual method 'boolean androidx.appcompat.widget.SwitchCompat.isActivated()' on a null object reference
It is very fragile to create view IDs yourself like this. They could easily collide with IDs generated by the Android build. So if you create IDs, you should be using ViewCompat.generateViewId() to do it safely.
But findViewById is something you generally want to avoid in the first place. It is slow. That's why View Binding is provided, to cache the views so you don't have to keep searching for them.
I highly recommend storing your Views in a collection instead of assigning them IDs. Then you can efficiently pull them from the collection when you need them. You just need to be sure the collection will be garbage collected when you're done with the views (don't create a collection that will outlive the screen the views are on).
You can get the view by using itemView property
Not sure of you are trying to do when you mean custom id.
You can get all views inflated by viewHolder with itemView.
this property is given to ViewHolder after you pass view as parameter in ViewHolder constructor, than ViewHolder will inflate views according with their id's.
than you can get view inside ViewHolder by:
itemView.findViewById<LinearLayout>(R.id.settingLayout)
itemView.findViewById<SwitchCompat>(R.id.switch)
You can look to see more options in google docs
If these are not what you asked for please let me know
I've implemented data binding and view model in my app, everything works great but I face a dumb issue which actually makes me wonder about re usability.
I have a fragment which has a picture and a title from a database that I put in other fragments. It's all bind to the viewModel calling some getters.
My issue is I need it in another activity now which has a different viewmodel for clarity and also because I don't need all the livedata from before but I can't really give it the new viewmodel since when I define it the type is specific to the other one.
<variable
name="viewModel"
type="com.example.thegreenstring.view.ObjectiveViewModel" />
So what am I suppose to do? It kind of means that you can't reuse fragments unless you have the same view model right? Sucks a little. I thought the only workaround was to make a specific view model for this fragment but it feels a little weird no?
Thanks for your help in advance !
When is executed the onDraw method of a DynamicForm exactly?
When I first load my page (a puremvc.Mediator page) and draw my DynamicForm with an onDraw method, I enter in this onDraw method. Then I destroy the view component, remove the Mediator from the Facade, and re-load the page. DynamicForm is being created again, the viewComponent too, but I don't enter in the onDraw method. Just as if the object has already been drawn! But the thing is it was destroyed, its parent too, and the parent of the parent, too.
What could be the problem?
OK, I got it.
The thing is that I use PUREMVC Mediator and Notification. On the first load, everything's good as the async method that returns data for DynamicForm C is sending the successful notification AFTER I have already created the VLayout B, and thus the addMember method adds and displays the DynamicForm C.
On the second load, I use the data that has already been gathered from DB, so no async method is being processed and the notification arrives BEFORE I create VLayout B, so basically the DynamicForm C is NOT being drawn.
My solution : I reordered some lines of code to make sure I always call the method that sends data via Notification (whether from DB or stocked) AFTER of the page creation.
First of all I am using support library (android-support-v4.jar) for using fragments.
I have an activity with layout containing a fragment in it. So when the activity starts it calls onCreateView method of my fragment. In this method I inflated a layout( containing a linearlayout and a listview in it ) and return that inflated view.
So when the activity starts it loads my listview and call a webservice and in response of the webservice loads the data on the listview.
Every thing works perfect as expected. But the problem is when I press the back button and restart the activity then it doesn't attach my fragment to the activity and throws IllegalStateException when I try to call getActivity(). And also throws NullPointerException when I try to call getView() method of my fragment.
One more thing to mention that when i see the view hierarchy from the TraceView tool then it shows my fragment views there.
Please help me!
I figured out the problem and hence solved it as well.
I was using the Observer interface to get the response from the web service. So when i started the activity first time then I added(or registered) my fragment activity to the Observable class and received the response but forgot to remove(or de-register) my fragment object when it destroyed. So when the activity and fragment restarts it again add my fragment object to the Observable class so now Observable class now has two instances of fragment first one has been destroyed and the current fragment and web service is called and it first respond with the destroyed fragment and that time it will crash. So i removed the fragment instance from the Observable class in the onDestroy method of fragment and it working now.
So the problem is not with the fragments but with the multiple instances of my fragment.
If I changed my NSOutlineView from using bindings and an NSTreeController to having a data source and a delegate, how would I automatically update the NSOutlineView, if my model tree changes? Should I observe the childNodes property of every single node in my tree with my controller and trigger a reload when a change occurs? Or is there another way?
That's one way. Another way would be for the model to post notifications when it changes and have your controller observe those.
Also, a model doesn't typically change spontaneously. Usually, the change is initiated outside of the model in response to some event. A controller is usually doing that. So, that controller could also provoke an update to the outline view. (There may be multiple controllers, so maybe the controller that initiates the model change just informs a window or view controller, which would be responsible for updating the outline view.)
I asked a similar question that was marked as duplicate here: Recommended Pattern for Observing Changes in Tree Structure [duplicate]
I wanted to avoid using NSTreeController as it means you lose control of animations when updates occur.
I have an MVVM set up. My model is a graph, my view model is a tree. There is a one-one relationship between any tree nodes and a graph node. As detailed in the question above, there is obviously a many-one relationship between the tree nodes and an outline view.
So, I settled with...
The view-model tree nodes need to know when their children are updated, so I used KVO of the associated graph node to catch when children are added or removed.
For the outline view update I settled on a model-view delegate that I implement on the view-controller. Each tree-node in the view model can call delegate methods on the tree root when children are added or removed. This felt the clearest approach to me, and easily debuggable. I didn't want chains of things happening behind the scenes.
The final outline view update call felt satisfyingly simple:
func itemsInserted(atIndexes indexes: IndexSet, forParent parent: ECViewModelNode) {
outlineView?.insertItems(at: indexes, inParent: parent, withAnimation: .slideDown)
}
At the table-cell-view level I bind directly to the details of the graph model nodes.