当前位置:网站首页>The solution to the problem of the first screen picture loading flicker

The solution to the problem of the first screen picture loading flicker

2022-06-22 08:07:00 Shake half a bottle of vinegar

Antecedent description :

Recently, I received a task to optimize the loading of home page pictures , The picture is displayed on the home page RecyclerView in . The problem is that even if there is a cache , The display of pictures will still jump with the naked eye , I can't open the home page , The picture is displayed there .

Problem location :

RecyclerView The picture in is in onBindViewHolder In the method , Use glide Loaded network pictures , Used glide The cache of . In order to make the picture refresh frequently without flickering , We used glide Load as bitmap, then bitmap Set to ImageView Plan in . Time consuming for locating log output is added to each line of code , Find web pictures glide Caching is done , The time to load the cache is actually very short , The real time-consuming is after the application starts , The main thread is busy ,glide Child thread loading completed bitmap after , Set the main thread to ImageView This operation is blocked because the main thread is busy .

Solution :

At this time, a coquettish idea suddenly appeared in my mind , take bitmap Set to ImageView The operation of is thrown into the sub thread to operate . Speaking of this , Some students may be surprised ,UI How can an operation be thrown into a child thread ? Don't throw an exception ?

Let's revisit that error message ,“Only the original thread that created a view hierarchy can touch its views.”, This error message does not say that only the main thread can handle ui operation , It says that only when you create that View Thread can operate this view, So if you are an independent owner window (Window) Displayed View, Its UI Threads can be independent of App The main thread ( For a detailed explanation of this scheme and principle, see :Android Sub thread UI Operation is really not allowed ?).

But the situation here certainly does not apply to this scheme , Are there any other conditions that can bypass this thread check ? Where the above exception is thrown is ViewRootImpl Inside checkThread Method , This method will basically be used in all view Call... In the update method , To prevent multithreading UI operation , however , If one View Not yet associated ViewRootImpl Object time , It won't trigger checkThread Method , It doesn't throw an exception .

see ImageView The call chain of , stay requestLayout in , Will trigger checkThread, But if not ViewRootImpl Words , It won't trigger , Does not throw an exception .ViewRootImpl When was the assignment made ?

mAttachInfo Is in View By attach When the assignment of , stay detach When the time is empty . Source code is as follows :

Back to our situation , So it should be done in the sub thread UI operation , So it needs to be in holder By attach Complete the loading and setting of pictures before .RecyclerView Of Adapter in ,ViewHolder When is it finished attach What about ?Adapter There is a method called onViewAttachedToWindow, Will be in View By attach Called when , Override this method , We will find that ,Adapter Will call first onBindViewHolder, And then call onViewAttachedToWindow, So we can onBindViewHolder We try to use sub threads in the implementation of UI operation . However, when the child thread sets the picture , Main thread continues to move down , Therefore, it is impossible to accurately ensure that the settings and onViewAttachedToWindow The order of priority , We use rxjava Switching thread , Can be received by CalledFromWrongThreadException after , Re set the image in the main thread for protection .

However, the above scheme consists of the following problems : Due to sub thread update UI add Try catch after ,requestLayout The process of , Will View Of itself and its parent classes PFLAG_FORCE_LAYOUT The location of the sign is 1 . however , because ViewRootImpl.scheduleTraversals() unexecuted , therefore , Not trigger View.layout() Reset PFLAG_FORCE_LAYOUT Sign a , Lead to , Then there are others UI operation , because View Of itself and its parent classes PFLAG_FORCE_LAYOUT The sign position is still 1 , Not trigger ViewRootImpl.requestLayout() Conduct scheduleTraversals() , and scheduleTraversals It will trigger View Of measure 、layout 、draw Refresh the process interface , The interface display is abnormal , need Manual call window.decorView.requestLayout() To recover . But manually invoking recovery can lead to other unpredictable problems , Therefore, the scheme is not recommended .

There's another way , It's a direct call updateDrawable(Drawable d) How to give ImageView Preload the picture , Next trigger ImageView Of requestLayout() and invalidate() The image will be loaded directly . unfortunately updateDrawable(Drawable d) Annotated as @UnsupportedAppUsage, So although this scheme has been tested for feasibility using reflection , But it still can't be used .

Through the measured , The main thread is busy after the application is started , The sub thread loads the image and sets the operation in onViewAttachedToWindow Before , So it can obviously improve the picture loading speed of the home page , However, there is no good solution for various problems , This scheme cannot be officially launched for the time being .

原网站

版权声明
本文为[Shake half a bottle of vinegar]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/173/202206220806388506.html