-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
AnimationView init blocks main thread for a noticeable amount of time #872
Comments
Starting to look into this a little bit. First point of note, the decoding of the Animation object (using our troublesome animation file) from the JSON currently takes around 350ms. I'm looking to see if there's a way to improve the parsing at all, but for complex models, it's possible that manual code will be significantly more performant than Decodable. |
Dang, yeah it seems that Codable doesnt perform very well with complex object mappings: |
The objects are being parsed on the main thread, we could offload those onto another thread and then feed them back into the animation view. In the meantime you can initialize an animation view without the animation, and in another thread initialize the animation. You could also initialize the animation object early, and let the animation cache provide it to the animation view on allocation. This is a bit of a work around but would help a lot with large animations. |
I'm going to see if I can spend a little more time digging into this. I might see how hard it would be to support Dictionary-based initialization in parallel to Decodable support to do performance testing. I also need to go back and see if there are other performance bottlenecks, as the decoding problem only appears to be half the issue. The initialization of the node tree is another bottleneck on the main thread. |
And Just a heads up @JoeSzymanski #873 also made changes to how the node tree is initialized. Hidden layers and nodes are skipped during tree initializaiton, which should help with performance hits. Im sure theres tons of performance fixes to be had though. Thanks! |
Thanks for the heads up. I'll do some more performance testing with the latest master. |
I put together a proof of concept for decoding an Animation class from the JSON rather than using Codable. See https://github.com/JoeSzymanski/lottie-ios/tree/initFromJSON In testing, it drops the decoding time from ~350ms to ~70ms. This includes the fact that I haven't finished the implementation for KeyFrame related classes (very complex classes to decode, and this PoC works without requiring that). I can see about cleaning the implementation up if you think it makes sense to move forward in that direction, but it might take me some time to get around to a full clean implementation. |
It's a shame that decodable is not very performant. My hope was to have built in support for encoding and decoding. I see that you aren't decoding shapes or anything downstream from that? Shape objects usually take up more than 80% of the JSON so I wonder what the performance would be like if shapes were also decoded. I don't think we can get an idea what the true performance difference without decoding shapes or doing some sort of testing there. If there is a huge performance difference then it makes sense to move forward here. I wonder if theres any quick wins or tricks to squeeze performance out of codable? |
I'll have to look more into that. I'm not 100% sure how much is happening in the decoding logic for Animation versus in other locations. I know that my current code doesn't decode LayerModel.transform or LayerModel.masks via the JSON (it reverts back to the Decodable handling of those). I was trying to resolve only the one side of the problem, which is the initial decoding. There are additional performance gains that can be made in setting up the animation within AnimationContainer, too, I think. |
@buba447 I'm looking more into this now and realized that my code misses a very important step in the decoding process around the layer model and was not decoding all of the subtypes for that array. It looks like that is the core performance hit that I can find, so I'm looking a little more today into that to see if there's a specific place where we're hitting the performance problem. |
As I do a little more digging, I'm leaning towards the handling of the heterogeneous collections as one of the big performance bottlenecks: https://github.com/airbnb/lottie-ios/blob/master/lottie-swift/src/Private/Model/Extensions/KeyedDecodingContainerExtensions.swift#L27-L40 In doing some logging of decoding times, a simple ShapeLayerModel that only has one item in it (A Group item with 3 sub-items) can take up to a full millisecond to decode. Cases with more sub-items can be longer. When there are a large number of items, the decoding time seems to increase significantly. I'm not sure if there's a better way to handle it, and I don't know if I have time at the moment to dig into a full JSON-based replacement to get performance numbers out of this. |
As an update, I was able to dig into this again, and created a solution that cut the decoding time for our complex animation from ~285 ms to ~90-100 ms. Now for the negatives. To do this, I had to create a completely new and parallel decoding system, which is rife with potential decoding errors compared to the existing code paths. In addition, most of the time saving appears to be coming from making the decoding of arrays of class families concurrent, which isn't possible with the current Decoder system. I'm going to do a little more digging to see if I can find a way to make the existing code path work a little faster, maybe by trying to find a way to do the array decoding in parallel, if possible. |
@buba447 I've done ab it more testing, and I think this code is hitting the limits of what Decodable can do with current support levels. Unfortunately, Decodable doesn't have any kind of concurrent support (and didn't seem to get much traction for adding that in the one Swift thread I found), and converting the data to a Dictionary to do the concurrent processing make it significantly slower. The only option I see here looks like it's removing the Decodable support and moving to a JSON dictionary-based initialization, but I know that this is complex and error prone, as I saw trying to implement it myself. It does provide significant performance gains, but will be hard to get finished 100%. Thoughts? |
That seems like the logical solution. It would be a large project, but worth it for the performance gains. I also have a pretty large project in the queue for increasing playback performance. Ill ad this to my list of future projects.
Thanks again for all of the work you put into researching this.
|
I pushed my current code into the branch at https://github.com/JoeSzymanski/lottie-ios/tree/initFromJSON (with some attempts to improve the existing decodable logic). Let me know if you want me to dig more into that. |
My original problem was that the new page couldn't be presented immediately while the Lottie JSON file was being loaded on the new page, so there was a hiccup on page transition. I've tried loading the JSON file in a different thread and it did help with the transition, but had its problems, because I was still using the main thread. I've tried using a background thread, but Lottie crashed, saying it required the main thread. So, now I can make it so the new page is presented before Lottie loads the JSON file but the user can't leave the page before that loading is finished (and the whole page is unresponsive during the loading). Just to be sure I don't misunderstand something: does Lottie indeed require the main thread when loading/parsing the animation file? Some additional info. I am loading the file from the bundle and this call blocks the main thread: |
Even i faced the same issue, view gets freeze on time of loading the animation since trying to load big json.
|
It helped me! thanks! |
well i face an issue while recording animation, whenever i try to record animationview it will animate with lang and after complete record it seem work perfectly. have you guys ever faced issue like this than let me know please. and i am sure it's issue of main thread so anyone have idea, how to solve it please share me. |
@buba447 Any updates? |
3.4.0 includes a new parsing implementation that is 2x faster than the previous |
Check these before submitting:
This issue is a:
Which Version of Lottie are you using?
Lottie 3.0
What Platform are you on?
What Language are you in?
Expected Behavior
Initializing an AnimationView should not block the main thread for a significant amount of time.
The previous version
LOTAnimationView
did not block the main thread on init.Actual Behavior
Initializing an AnimationView blocks the main thread long enough where it appears that the app has hanged.
Code Example
Animation JSON
treasurechest-animation1.json.zip
The text was updated successfully, but these errors were encountered: