[SOLVED] Having trouble with a custom model and asynchronous data
I am hoping that someone may be able to give me some pointers that may help me solve a problem I am having, in the age of the internet and web services I am pretty sure I am not the first person having this problem. It may be because it is Friday? who knows?
I have created a model class derived from QAbstractTableModel. Inside that class I have a string list of unique ids that reference some JSON that must be downloaded from the web. It is this downlaoded JSON that will provide the model with the data that the view requires.
When the data with Qt::DisplayRole is requested from my model I am making a call to a web service to which I must wait for the JSON blob to be returned. When I have received the JSON I update the data using begin/end model reset.
However what I am finding is that I am making a lot of extra calls to the web services while I wait for the first request to be fulfilled. There is is obviously a race of sorts occurring. Even if there is only one ID to be resolved there are about 20 extra requests on data with the Qt::DisplayRole.
I feel that making the asynchronous call to web from my data override is probably not the best thing to be doing.
Does any of this make sense, am I way off or is there a better way.
One thing that happens is that data is called several times anyway since you have several cells that are shown and thus updated when e.g. scrolling, showing the widget etc.
One thing you could do is prefetch the data to have a "startup set" and then only request additional information when needed. You could also "compress" a burst of request in only one but that means that your endpoint should be able to support getting one request for several ids.
Hope it helps
So all this additional calls are only natural due to to all the events that are triggering interactions between the view and the model.
I think I will try a different approach then, so whenever I get a new list of IDs, in a separate thread, make a request for the data associated with each ID and update the model once all requests return something or timeout after a give time, or simpler may be to update the model when each request returns.
If the list of IDs change then fetch from the endpoints and only update the rows affected and reload the model with new data.
You don't need to reload the complete model, just update what is needed and emit the dataChanged accordingly
Ok I think I am getting some where with this now, I am initially loading my model with the list of IDs in column 0. The resolved JSON will then fill the other columns.
My problem is when the endpoints return the data, I update the affected rows and then emit dataChanged all cells in the updated rows are wiped clean. I can still see each empty row in my view, so the model knows something about my data. If the indexes I reference in the dataChanged signal are wrong, could this wipe the model or would it just gracefully fail to update?
On a side note, will I need to do something with setData?
AFAIK, it should not. There must be something else.
Technically, you don't need to call setData since you manage the underlying data yourself.
Are you sure your structure doesn't get somehow reset when you are updating the json data ?
Sorry for getting back so late, but once I got to the bottom of of the issue, it was full speed ahead. The reason the columns were blank was because my data was not formatted correctly instead of a list of things, it was a list of lists of things. Fixed it and I am no longer spamming the network while waiting on asynchronous data to be returned.
Thanks for the help :
Nice you found out !
You're welcome !
Happy coding :)