2012-01-31 4 views
4

모노크롬에서 iCarousel 라이브러리를 사용하려고합니다. 라이브러리를 성공적으로 포팅했는데 모든 것이 완벽하게 작동하지만 이미지가있는 UIImageViews를 너무 많이 입력하면 응용 프로그램이 충돌합니다. 이는 iCarousel이 UIScrollView와 유사하기 때문에 정상입니다.지연로드 및 멀티 스레딩

필자는 보조 스레드에서 시스템을 느리게로드하고 3-4 개의 이미지 만 한 번에 표시해야하지만이 작업을 원활하게 수행하는 방법을 모르겠습니다. 이때

, I는 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

아마도 bool이 거짓이 될 때까지 기다리는 핫 루프에서 회전하지 않도록 노력해야합니다. 이것은 전체 CPU를 소모합니다! 최소한 Thread.Sleep (10)을 거기에 삽입하십시오. – usr

+1

이 코드는 깨졌습니다. 백그라운드 스레드 (hideInvisibleImages)에서 UIKit 요소에 액세스하고 있으며 이로 인해 임의의 메모리 손상이 발생합니다. –

+0

@ miguel.de.icaza, 당신은 img.Image.Dispose() 전에 invokeOnMainThread를 사용해야한다는 것을 의미합니까? – Daniel

답변

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 인스턴스에 대한 참조를 보유하며 가비지 수집을 방지합니다.