2012-01-31 108 views
4

我試圖在monoouch中使用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個圖像提前,另一個線程清理所有其他圖像,隱藏它們。

它的工作,記憶是好的,但它不是在設備上的光滑,它在我滾動時「掛起」一點。還有另一種方法來做到這一點?或者,也許我應該改變算法?

+4

也許你應該儘量不要在熱循環中旋轉等待布爾變成假。這消耗整個CPU!至少插入一個Thread.Sleep(10)。 – usr 2012-01-31 20:42:56

+1

此代碼已損壞。您正在從後臺線程(hideInvisibleImages)訪問UIKit元素,這將導致隨機內存損壞。 – 2012-02-01 15:53:47

+0

@ miguel.de.icaza,你是說我必須在img.Image.Dispose()之前使用invokeOnMainThread? – Daniel 2012-02-01 18:40:53

回答

2

你有一個循環,不允許CPU到任何其他線程/進程,並會導致非常高的CPU利用率。當您滾動時,這會使其掛起。

嘗試在refresh_visible方法中使用Thread.Sleep(1)或一個小的休眠時間。

2

我有點困惑你的滾動如何工作,但我認爲下面的代碼可以給你一個體面的起點如何解決這個問題。

隨着USR的註釋部分指出的那樣,你不斷在循環中旋轉並以最快的速度刷新圖像作爲可能的(如果我理解正確的代碼):

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實例的引用,並且會阻止它被垃圾收集。