我正在尝试在monotouch中使用iCarousel库。我成功地移植了库,一切都运行得很好但是如果你输入太多带有图像的UIImageViews应用程序会崩溃,这是正常的,因为iCarousel就像一个UIScrollView。
我必须以某种方式从辅助线程使用延迟加载系统,并且一次只显示3-4张图像,但我不知道如何使这项工作顺利进行。
此时,我在iCarousel代表中设置了这个:
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;
}
}
}
代码实际上非常简单:主线程只显示当前索引左侧的1个图像,提前显示两个图像,另一个清除所有其他图像的线程隐藏它们。
它正常工作,内存还可以,但它在设备上并不流畅,当我滚动时它会“挂起”一点。还有另一种方法吗?或许我应该改变算法?
答案 0 :(得分:2)
您正在拥有一个不允许CPU进入任何其他线程/进程的循环,并且会导致非常高的CPU利用率。滚动时会使它挂起。
尝试在refresh_visible方法中使用Thread.Sleep(1)或小睡眠时间。
答案 1 :(得分:2)
我对你的滚动工作方式有些困惑,但我认为下面的代码可以为你解决这个问题提供一个不错的起点。
正如我们在评论部分指出的那样,你会不断旋转并尽快刷新图像(如果我理解你的代码正确的话):
void refresh_visible()
{
while( threadsAlive )
{
while( scrolling )
{
ShowCurrent();
}
}
}
void refresh_hidden()
{
while( threadsAlive )
{
while( scrolling )
{
hideInvisibleImages();
}
}
}
似乎无论滚动还是适当的刷新率都可能是个好主意。您应该实现一个介于每秒24到30帧之间的刷新率。
这样的事情可能是有序的:
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()
{
//...
}
}
请注意,如果您正在创建和销毁大量YourClass
个实例,那么在完成后,您还应该处理Timer
个对象。 Timer
的委托将保留对YourClass
实例的引用,它将阻止它被垃圾回收。