我有一個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;
}
Aaarrrgggh!匈牙利符號!我想,匈牙利不存在IDE工具提示。 – jonathanpeppers
說真的,你可以刪除對Thread.Abort()的調用嗎?如果它發生在Dispose()中,我可以看到一些不好的事情。我認爲你可以讓線程完成並創建一種方法讓線程停止(在完成工作後)並用布爾標誌。 – jonathanpeppers
但是,最後,如果新線程創建得足夠快,那麼我最終會在周圍浮現線程的渲染圖像,這些渲染圖像不會在任何地方使用。這是一個通用規則:「不要在MT UI環境中使用Thread.Abort()?」我有很長時間的運行,複雜的進度線程,我不想放一個「if(shouldExit)return」在每一個第二行。 – Krumelur