1

私は持っていUISliderます。PDF 内をすばやくナビゲートするために使用されます。次のページのしきい値に達するとUIView、スライダーのノブの横に、ターゲット ページの小さなプレビューを含む が表示されます。スライダーのコードはこの下にあります (いくつかの部分が取り除かれています)。次のページに到達すると、新しいプレビューが生成されます。それ以外の場合は、既存のプレビューがスライダーに沿って移動します。

さまざまな効果が得られます。

  • 多くのページをプレビューすると、アプリがクラッシュします

    MonoTouch.CoreGraphics.CGContext.Dispose (ブール値) <0x00047> 10 月 11 日 17:21:13 不明な 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

Jonathanが提案するように、Thread.Abort()を削除します。

画像ごとに新しいスレッドを開始せず、代わりにワークキューを持つ1つのバックグラウンドスレッドを用意します。次に、最も重要なページをキューの先頭に配置するだけで、できるだけ早くレンダリングされます。オプションで、キューのサイズを制限したり、キューから不要なアイテムを削除したりすることもできます。

于 2012-11-15T13:15:17.663 に答える
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 の機能を使用できる場合は、代わりに使用してください。あなたのケースでは、 a を使用するTask<T>方がおそらく簡単に操作できます。

また、スロットリングを作成し、ユーザーが 25 ~ 100 ミリ秒非アクティブになった後にのみ新しいスレッドを開始すると役立つと思います。

于 2011-10-11T21:52:46.560 に答える