1

我有一个UISlider. 它用于快速浏览 PDF。每当达到下一页的阈值时,我UIView会在滑块的旋钮旁边显示一个,其中包含目标页面的小预览。滑块代码看起来在此下方(某些部分已剥离)。如果到达下一页,则生成新的预览,否则,沿滑块移动现有的预览。

我得到各种效果:

  • 如果预览许多页面,应用程序会崩溃

    MonoTouch.CoreGraphics.CGContext.Dispose (bool) <0x00047> Oct 11 17:21:13 unknown UIKitApplication:com.brainloop.brainloopbrowser[0x1a2d][2951] : 在 MonoTouch.CoreGraphics.CGContext.Finalize () <0x0002f>

  • 或者如果我在最后一个方法中删除对 Dispose() 的调用:[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;
        }
4

2 回答 2

0

避免Thread.Abort()

是的,这里有一些讨论它的链接:

http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation

http://haacked.com/archive/2004/11/12/how-to-stop-a-thread.aspx

如果您可以使用 .Net 4.0 功能,请改用它们。在您的情况下,使用 aTask<T>可能更容易使用。

另外,我认为创建一些限制并仅在用户不活动 25-100 毫秒后才启动新线程会很有帮助。

于 2011-10-11T21:52:46.560 回答
0

正如乔纳森建议的那样,摆脱 Thread.Abort() 。

Don't start a new thread for each image and instead have one background thread with a work queue. Then simply put the most important page to the front of the queue so it renders as soon as possible. You can also optionally limit the size of the queue or remove unneeded items from it.

于 2012-11-15T13:15:17.663 回答