I’m trying to use the iCarousel library in monotouch. I successfully ported the library, everything works perfectly but the application crashes if you enter too many UIImageViews with images inside, which is normal because iCarousel is just like a UIScrollView.
I definitely have to use lazy loading system somehow from a secondary thread and display only 3-4 images at once but I do not know how to make this work smooth.
At this point, I set 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 only shows 1 image from the left of the current index and two images in advance, and another thread that cleans all other images, hides them.
It’s working, memory is ok, but it’s not smooth on the device, it “hangs” a little when I scroll. There is another way of doing this ? Or maybe I should change the algoritm?
You are having a loop that won’t allow CPU to any other thread/process and will lead to a very high CPU utilization. This is making it hang when you scroll.
Try using Thread.Sleep(1) or a small sleep time in the refresh_visible method.