-
Notifications
You must be signed in to change notification settings - Fork 6.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Follow up of: https://github.com/bumptech/glide/pull/2261 #2270
Comments
I'm not sure I can support this. Passing in a new model object is plausible, but it's hard to justify. Could you track connection state another way? Maybe by setting a tag on the View? Or do you need this connection state in the request somewhere (like the ModelLoader). |
@sjudd well adapter should not know about internal states and model should not modify the views. Anyway point 1 was just a quick and easy (hackish I agree) workaround to solve the issue. I tried to point out something also in previous issues, but obviously failed :) With all due respect I think that there's a big design flaw in Glide 4 to use model hashCode/equals to handle cache / equity from Glide point of view. hashCode / equals are basic java stuff designed to means something precise. The equity of the model. The problem is that you also use that as equity / cache key for the resulting image. Let's take a way simpler example than my advanced use case. A user needs to use a custom model / loader to load images from something not supported natively by Glide. He already have a simple model
To use this model efficiently in Glide (use of cache) it needs to implement hashCode / equals to only take care of image as different beach could share a same image. But that guy store those in a list and got push of that data. So to avoid duplicates he uses, list.contains. Solution: fix hashCode/equals to do what they are meant to, and use all the fields. But then, Glide is broken and no more use properly it's cache. Having hashCode/equals to handle to very different purpose put the users in an impossible choice, have their app working correctly or have Glide cache working. |
Did you consider creating a second class that contains just the data you want to be used in Glide? Then you can have two different objects with two different equals/hashcode implementations. |
@sjudd This is actually the case for my needs and implementation :) I was just giving another very simple use case that is now quite complicated to handle with Glide 4 compared to Glide 3. My need is to have different models that contains meta data, internal state, whatever, but still be able to indicate to Glide that the end result image is the same. In glide 3 this was possible. In Glide 4 there's the Key interface but not only it's only for diskCache but still does take the model as another Key. For my use case since the object is unique to Glide I did hack the hashCode / equals to be the image Key and not real ones. But this triggers this issue that I can't force a reload from my fetcher with the correct data on second calls. I'm kinda stuck with no possible solution except maybe rewriting 100% of the app image handling. To be honest I prefer maintaining a fork with a little hack, than rewriting everything with risks for a 4.73 rating millions users app ;) (But I'd really like to not have to) Maybe another solution would be to have an optional callback configured somehow, that would be called to decide if the query should actually be restarted and passing to the callback the previous model and the new one? (But certainly complicated to handle via generics without breaking the new nice API). |
Some details about part of why complex use case could help. My app can connect to multiple media centers and will get the images from the media centers so the actual real download url will be different. All this needs to be handled in the model as it's the proper place for that. Maybe it's more clear why there's currently no solution :( Except calling clear of course but then flickering so not really a solution. |
@sjudd last other small basic use case to show the issue that more looks like my need. Hoping we find an agreement that something might be needed. Take an application X that can connect to two different servers and display images from those. The app offer a button to switch between servers without stopping the activity so triggering just a refresh of the view. Now serverA have an image http://servera/image1.png and serverB have an image http://serverb/image1.png. Both images are the exact same and the app knows it. So to handle this correctly and use Glide cache without duplicates, the app implements a model.
And all seems to works perfectly, correct cache is used all is perfect. Then a real user start the app that is pre configured to connect to serverA. The app start, glide load the serverA image url, but since the serverA is down the image is not shown and the error is triggered. All normal. Maybe this sample explain more, why hashCode / equals poses a problem. I'm not English native but I think it's more or less clear :) |
The only two differences between v3 and v4 are:
There's nothing about equals or hashcode that I can think of that changes #1. If we had the same behavior but used the string id from Glide v3 instead of equals/hashcode, you'd still have exactly the same problem. Or am I missing something? I think your actual issue here is with the flashing that you see if you copy Glide v3's behavior and clear the Target before each load? |
@sjudd If you use the string id and not the hash code this change all :) 2 different models can share the same image result and cache but still be different models. This means the issue would not happens, as the model are different you'd clear the query when needed and do a full restart. Yet still use the memory cache. Yes the end issue is the flickering if we always clear. But what I try to demonstrate is that there's so many cases where clear could be needed that totally remove the utility of Glide 4 optimisations. The thing is that is the query is the same query then what is done actually is correct. Having devs to always call clear to fix some case issue is counter productive :( As to force users to have a model dedicated to Glide as hashCode/equals needs to be specific for image cache to work. If the model is actually the same model then current behavior is correct. If the model change but the final image is the same, current behavior is not correct. Solution would be to have devs to find a way to check by themself if the target already had a load, get previous model if possible then call another compare function then clear then reload. 2 different models can share the same image cache. Currently this is not possible. Edit: Updating to new model on recycle may not be perfect, but this allows things to at least works consistently with the API that force hashCode to be used for something else. I can understand that you find it hackish but then finding another way to properly handle different models sharing image cache is important for Glide 4 to be as effective as Glide 3. |
@sjudd Since this is mostly an important issue with failed request would you accept a compromise ? Add This does not introduce fundamental changes to your implementation, yet ensure that failed request are started with the correct updated model in case there's some difference in it to allow the request to have more chance to success ? |
You're nothing if not persistent :). So I think I'm finally clueing in. You want both the cache key mechanism from Glide v3 and the equals/hashcode mechanism from Glide v4. Where equals/hashcode is used to determine whether or not to restart the request and the cache key is used for the memory cache/request deduplication. How do you know which model to pass in for a given cache key if you don't know whether the request has failed or not? Would adding a request parameter that allowed you to specify a fallback request that would be run if the main request failed work? I'm not totally opposed to clearing/restarting if the request is failed, but it seems a little weird since that can already be handled by SingleRequest. How common is it for people to have multiple model objects that have the same cache key? Equals()/hashcode() was supposed to be a more flexible alternative to Glide v3's string cache key because you don't have to find a way to serialize your model to use it in Glide. |
Well it took me a lot of time to adapt to Glide 4 as I go deeper in my usage than most to optimize every bits. High ratings are hard to get easy to loose :) And I'm now stuck with no solution to have something that work so yes I insist a little to avoid maintaining a fork. Anyway about different model and cache key, I don't know if it's that common. But as the little example I gave earlier there's a simple reason to want that. Same cache for different urls. Could be because the app can connect to mutiple servers or frontend for example. I've tested the last proposed approach (on reuse only when completed or running) and this works ok on all cases. Proper cache usage, proper event triggering on load or ignored restart when imahe loaded and proper restart on failure with changed model. |
Could you theoretically store the current server in a singleton instead of in each model and retrieve the current server in the ModelLoader? I guess that would be race prone? I'm not totally opposed to your idea, I'm just exploring options. |
Well it's not that simple, my app.connects to multiple servers at the same time to control them. It's not like round robin of internet servers. Nothing that can be handled outside of the model to represent the state at the moment of the request. Sorry to bother you so much. |
I found another issue with my change:
Because we're restarting the previous request here: 73a8e01#diff-a38a476f7aa7c143d4cde2716bb2b59dR369 rather than the new request, the two requests I listed above will recurse infinitely. Our new assertion that throws if a request is started in a I don't think we want to include the It seems like it might be reasonable to just start the new request, instead of restarting the old request? It's somewhat less efficient because we have to build the new @Tolriq would just starting the new request, rather than restarting the old request, unless the old request is actively running fix your issues? |
Well yes but then it removes most of the optimizations done no? |
sompor038
|
Wups @Tolriq sorry I missed your comment. I think it keeps the optimization. The current behavior is that if the requests are equivalent, but the old request is not running, we restart the old request. My proposal is that we do the same thing, but instead of restarting the old request, we start the new request. The cases where we do or don't start a request don't change. The only thing that will change is which request we start. |
Oh no I"m wrong it does remove some of the optimizations added in SingleRequest. |
More progress toward bumptech#2270.
@sjudd Ok so there's one last side effect remaining after #2245
Opening a new issue as it's a special case, that will maybe needs something on my side to workaround.
As explained on previous issues, I do have a special model that handles some connexion states internaly.
And those states as they do not change the actual picture data, are not handled in the model hashcode/equals so that memory cache can properly be used.
The problem is that the restart of the query after your patch still use the previous model and not the new one with the updated internal flags so does not work.
The text was updated successfully, but these errors were encountered: