Lazy loading and multithreading

I am trying to use the iCarousel library in monotouch. I have successfully ported the library, everything works fine, but the application crashes if you enter too many UIImageView with images inside, which is normal, because iCarousel is like UIScrollView.

I definitely should use a lazy loading system somehow from the secondary stream and display only 3-4 images at a time, but I don't know how to make this work smooth.

At this point, I installed this in the iCarousel delegate:

bool threadsAlive = true; public cDelegate() { ThreadPool.QueueUserWorkItem( delegate { refresh_visible(); } ); } public override void DidScroll (iCarousel carousel) { scrolling = true; } public override void DidEndScrollingAnimation (iCarousel carousel) { scrolling = false; //show images that are currently on the screen ThreadPool.QueueUserWorkItem( delegate { ShowCurrent(); } ); //hides images that are not on the screen ThreadPool.QueueUserWorkItem( delegate { hideInvisibleImages(); } ); } void refresh_visible() { while( threadsAlive ) { while( scrolling ) { ShowCurrent(); } } } void refresh_hidden() { while( threadsAlive ) { while( scrolling ) { hideInvisibleImages(); } } } public void ShowCurrent() { var ds = _carousel.DataSource as cDataSource; var left_index = _carousel.CurrentItemIndex - 1; var right_index = _carousel.CurrentItemIndex + 2; if( left_index < 0 ) left_index = 0; if( right_index >= ds.Lista.Count ) right_index = ds.Lista.Count - 1; // for( var i = left_index; i < right_index ; i++ ) { var img = ds.Lista[i]; if( img.Image == null ) { BeginInvokeOnMainThread( delegate{ img.Image = UIImage.FromFile( img.UserObject.ToString() ); }); } } } void hideInvisibleImages() { Console.WriteLine("ascund!"); var ds = _carousel.DataSource as cDataSource; var left_index = _carousel.CurrentItemIndex - 1; var right_index = _carousel.CurrentItemIndex + 2; if( left_index < 0 ) left_index = 0; if( right_index >= ds.Lista.Count ) right_index = ds.Lista.Count - 1; // for( var i=0; i<left_index; i++ ) { var img = ds.Lista[i]; if( img.Image != null ) { img.Image.Dispose(); img.Image = null; } } for( var i=right_index; i<ds.Lista.Count; i++ ) { var img = ds.Lista[i]; if( img.Image != null ) { img.Image.Dispose(); img.Image = null; } } } 

The code is actually very simple: there is a main thread that shows only 1 image to the left of the current index and two images in front, and another thread that clears all other images hides them.

It works, the memory is fine, but it is not smooth on the device, it hangs a little when I scroll. Is there any other way to do this? Or maybe I should change the algorithm?

+4
source share
2 answers

You have a loop that will not allow the processor to work with another thread / process and will result in very high CPU utilization. This makes it freeze while scrolling.

Try using Thread.Sleep (1) or a short sleep time in the refresh_visible method.

+2
source

I'm a little confused about how your scrolling works, but I think the code below can give you a decent starting point on how to fix this problem.

As stated in the comments section, you constantly rotate in a loop and update the image as quickly as possible (if I understand your code correctly):

 void refresh_visible() { while( threadsAlive ) { while( scrolling ) { ShowCurrent(); } } } void refresh_hidden() { while( threadsAlive ) { while( scrolling ) { hideInvisibleImages(); } } } 

It seems nice to have an appropriate refresh rate, regardless of scrolling. You must implement an update rate that is somewhere between 24 and 30 frames per second.

Something like this might be ok:

 using System.Threading; class YourClass { // Tick every 42 millisecond or about 24 times per second private readonly int _refreshRate = 42; private volatile bool _scrolling; private Timer _timer; YourClass() { _timer = new Timer(TimerTick, null, 0, _refreshRate); } public void TimerTick(object state) { if (_scrolling) { ShowCurrent(); HideInvisibleImages(); } } void ShowCurrent() { //... } void HideInvisibleImages() { //... } } 

Note that if you create and destroy many instances of YourClass , you must also get rid of the Timer object when you are done with it. The Timer delegate will contain a reference to an instance of YourClass , and this will prevent garbage collection.

+2
source

Source: https://habr.com/ru/post/1394057/


All Articles