2011-10-11 41 views
1

我有一個UISlider。它用於快速瀏覽PDF。每當達到下一頁的閾值時,我會在滑塊旋鈕旁邊顯示一個UIView,其中包含目標頁面的小預覽。 滑塊代碼看起來低於這個(一些部分被剝離)。如果到達下一頁,則生成新的預覽,否則,現有的預覽將沿滑塊移動。Monotouch:不時在單獨的線程崩潰中渲染PDF頁面預覽

我得到不同的效果:

  • 如果預覽很多很多的網頁,在

    MonoTouch.CoreGraphics.CGContext.Dispose(布爾)< 0x00047> 10月11日17:21應用程序崩潰: 13未知UIKitApplication:com.brainloop.brainloopbrowser [0x1a2d] [2951]:在MonoTouch.CoreGraphics.CGContext.Finalize()< 0x0002f>

  • 或如果刪除呼叫處置()的叔他最後一個方法:[NSAutoreleasePool release]: This pool has already been released, do not drain it (double release).

從看代碼,是否有人有一個想法有什麼不對?或者是使用線程的整個方法是錯誤的?

this.oScrollSlider = new UISlider(); 
this.oScrollSlider.TouchDragInside += delegate(object oSender, EventArgs oArgs) 
{ 
this.iCurrentPage = (int)Math.Round (oScrollSlider.Value); 
    if (this.iCurrentPage != this.iLastScrollSliderPage) 
    { 
     this.iLastScrollSliderPage = this.iCurrentPage; 
     this.RenderScrollPreviewImage(this.iCurrentPage); 
    } 
}; 
this.oScrollSlider.ValueChanged += delegate 
{ 
    if (this.oScrollSliderPreview != null) 
    { 
     this.oScrollSliderPreview.RemoveFromSuperview(); 
     this.oScrollSliderPreview.Dispose(); 
     this.oScrollSliderPreview = null; 
    } 
    // Go to the selected page. 
}; 

創建預覽的方法正在旋轉一個新的線程。如果用戶更改得到控制而線程仍在網頁,它會被中止,接下來的頁面預覽:

private void RenderScrollPreviewImage (int iPage) 
{ 
// Create a new preview view if not there. 
if(this.oScrollSliderPreview == null) 
    { 
     SizeF oSize = new SizeF(150, 200); 
     RectangleF oFrame = new RectangleF(new PointF (this.View.Bounds.Width - oSize.Width - 50, this.GetScrollSliderOffset (oSize)), oSize); 
     this.oScrollSliderPreview = new UIView(oFrame); 
     this.oScrollSliderPreview.BackgroundColor = UIColor.White; 
     this.View.AddSubview(this.oScrollSliderPreview);  

     UIActivityIndicatorView oIndicator = new UIActivityIndicatorView(UIActivityIndicatorViewStyle.Gray); 
     oIndicator.Center = new PointF(this.oScrollSliderPreview.Bounds.Width/2, this.oScrollSliderPreview.Bounds.Height/2); 
     this.oScrollSliderPreview.AddSubview(oIndicator); 
     oIndicator.StartAnimating(); 
} 
      // Remove all subviews, except the activity indicator. 
      if(this.oScrollSliderPreview.Subviews.Length > 0) 
      { 
       foreach(UIView oSubview in this.oScrollSliderPreview.Subviews) 
       { 
        if(!(oSubview is UIActivityIndicatorView)) 
        { 
         oSubview.RemoveFromSuperview(); 
        } 
       } 
      } 

// Kill the currently running thread that renders a preview. 
      if(this.oRenderScrollPreviewImagesThread != null) 
      { 
       try 
       { 
        this.oRenderScrollPreviewImagesThread.Abort(); 
       } 
       catch(ThreadAbortException) 
       { 
        // Expected. 
       } 
      } 

// Start a new rendering thread. 
      this.oRenderScrollPreviewImagesThread = new Thread (delegate() 
      { 
       using (var oPool = new NSAutoreleasePool()) 
       { 
        try 
        { 
// Create a quick preview. 
         UIImageView oImgView = PdfViewerHelpers.GetLowResPagePreview (this.oPdfDoc.GetPage (iPage), new RectangleF (0, 0, 150, 200)); 
         this.InvokeOnMainThread(delegate 
         { 
          if(this.oScrollSliderPreview != null) 
          { 
           oImgView.Center = new PointF(this.oScrollSliderPreview.Bounds.Width/2, this.oScrollSliderPreview.Bounds.Height/2); 
// Add the PDF image to the preview view.        
this.oScrollSliderPreview.AddSubview(oImgView); 
          } 
         }); 
        } 
        catch (Exception) 
        { 
        } 
       } 
      }); 
// Start the thread. 
      this.oRenderScrollPreviewImagesThread.Start(); 
     } 

要渲染PDF圖像,我用這個:

internal static UIImageView GetLowResPagePreview (CGPDFPage oPdfPage, RectangleF oTargetRect) 
     { 
      RectangleF oPdfPageRect = oPdfPage.GetBoxRect (CGPDFBox.Media); 

      // If preview is requested for the PDF index view, render a smaller version. 
      float fAspectScale = 1.0f; 
      if (!oTargetRect.IsEmpty) 
      { 
       fAspectScale = GetAspectZoomFactor (oTargetRect.Size, oPdfPageRect.Size, false); 
       // Resize the PDF page so that it fits the target rectangle. 
       oPdfPageRect = new RectangleF (new PointF (0, 0), GetFittingBox (oTargetRect.Size, oPdfPageRect.Size)); 
      } 

      // Create a low res image representation of the PDF page to display before the TiledPDFView 
      // renders its content. 
      int iWidth = Convert.ToInt32 (oPdfPageRect.Size.Width); 
      int iHeight = Convert.ToInt32 (oPdfPageRect.Size.Height); 
      CGColorSpace oColorSpace = CGColorSpace.CreateDeviceRGB(); 
      CGBitmapContext oContext = new CGBitmapContext(null, iWidth, iHeight, 8, iWidth * 4, oColorSpace, CGImageAlphaInfo.PremultipliedLast); 

      // First fill the background with white. 
      oContext.SetFillColor (1.0f, 1.0f, 1.0f, 1.0f); 
      oContext.FillRect (oPdfPageRect); 

      // Scale the context so that the PDF page is rendered 
      // at the correct size for the zoom level. 
      oContext.ScaleCTM (fAspectScale, fAspectScale); 
      oContext.DrawPDFPage (oPdfPage); 

      CGImage oImage = oContext.ToImage(); 
      UIImage oBackgroundImage = UIImage.FromImage(oImage); 
      oContext.Dispose(); 
      oImage.Dispose(); 
      oColorSpace.Dispose(); 

      UIImageView oBackgroundImageView = new UIImageView (oBackgroundImage); 
      oBackgroundImageView.Frame = new RectangleF (new PointF (0, 0), oPdfPageRect.Size); 
      oBackgroundImageView.ContentMode = UIViewContentMode.ScaleToFill; 
      oBackgroundImageView.UserInteractionEnabled = false; 
      oBackgroundImageView.AutoresizingMask = UIViewAutoresizing.None; 

      return oBackgroundImageView; 
     } 
+0

Aaarrrgggh!匈牙利符號!我想,匈牙利不存在IDE工具提示。 – jonathanpeppers

+0

說真的,你可以刪除對Thread.Abort()的調用嗎?如果它發生在Dispose()中,我可以看到一些不好的事情。我認爲你可以讓線程完成並創建一種方法讓線程停止(在完成工作後)並用布爾標誌。 – jonathanpeppers

+0

但是,最後,如果新線程創建得足夠快,那麼我最終會在周圍浮現線程的渲染圖像,這些渲染圖像不會在任何地方使用。這是一個通用規則:「不要在MT UI環境中使用Thread.Abort()?」我有很長時間的運行,複雜的進度線程,我不想放一個「if(shouldExit)return」在每一個第二行。 – Krumelur

回答

0

Jonathan建議擺脫Thread.Abort()。

不要爲每個圖像啓動一個新線程,而應該有一個帶有工作隊列的後臺線程。然後,將最重要的頁面放在隊列的前面,以便儘快呈現。您還可以選擇限制隊列的大小或從中刪除不需要的項目。