2014-12-10 4 views
3

Это мой код, который пытается не блокировать приложение в Android при загрузке одного или нескольких изображений.Delphi Bitmap in Thread

Каждый раз замерзает или не загружается должным образом.

Если кто-то знает способ сделать то, что мне нужно, был бы вам признателен.

Это моя процедура:

uses 

    System.IOUtils, 
    System.Threading, 
    System.SyncObjs, 

    FMX.Surfaces, 

    MyTasks; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 

    AniIndicator1.Enabled := True; 
    AniIndicator1.Visible := True; 
    Button1.Enabled := False; 

    TTask.Run(

    procedure 
    var 
     VBitmapSurface: TBitmapSurface; 
     VFiles: TStringDynArray; 
     VFilesIndexes: TArray<NativeInt>; 
     VFile: String; 
     VIndex: Integer; 
     VBitmapData: TBitmapData; 
     VMapped: Boolean; 
     VCriticalSection: TCriticalSection; 
    begin 
     VCriticalSection := TCriticalSection.Create; 
     VCriticalSection.Acquire; 

     VFiles := SearchFiles([ TPath.GetPicturesPath, TPath.GetCameraPath, TPath.GetSharedPicturesPath, TPath.GetSharedCameraPath ], [ '*.jpg', '*.jpeg' ]).Value; 
     VFilesIndexes := Randomizer(Length(VFiles)).Value; 
     VFile := VFiles[ VFilesIndexes[ 0 ] ]; 

     VBitmapSurface := TBitmapSurface.Create; 
     try 
     if TBitmapCodecManager.LoadFromFile(VFile, VBitmapSurface) then 
     begin 
      VMapped := False; 
      TThread.Synchronize(nil, 
      procedure 
      begin 
       Image1.Bitmap.SetSize(VBitmapSurface.Width, VBitmapSurface.Height); 
       VMapped := Image1.Bitmap.Map(TMapAccess.Write, VBitmapData); 
      end 
     ); 
      if VMapped then 
      try 
      if VBitmapData.Pitch = VBitmapSurface.Pitch then 
       Move(VBitmapSurface.Bits^, VBitmapData.Data^, VBitmapSurface.Pitch * VBitmapData.Height) 
      else 
       for VIndex := 0 to VBitmapSurface.Height - 1 do 
       Move(VBitmapSurface.Scanline[ VIndex ]^, Pointer(NativeInt(VBitmapData.Data) + VIndex * VBitmapData.Pitch)^, VBitmapData.Width * VBitmapSurface.BytesPerPixel); 
      finally 
      TThread.Synchronize(nil, 
       procedure 
       begin 
       Image1.Bitmap.Unmap(VBitmapData); 
       end 
      ); 
      end; 

     end; 
     finally 
     VBitmapSurface.DisposeOf; 
     end; 

     VCriticalSection.Release; 
     VCriticalSection.DisposeOf; 

     TThread.Synchronize(nil, 
     procedure 
     begin 
      AniIndicator1.Enabled := False; 
      AniIndicator1.Visible := False; 
      Button1.Enabled := True; 
     end 
    ); 

    end 

); 

end; 
+5

Да, вы можете загрузить растровое изображение в потоке. Однако вы не можете отображать его на своем интерфейсе ** в потоке. Это визуальная часть, которая не является потокобезопасной. Поскольку вы не предоставили никакого кода, практически невозможно сказать вам, почему вы получаете «авария и пустые или черные изображения». –

+2

@KenWhite По-видимому, растровое изображение Delphi VCL не является потокобезопасным, даже если вы его не отобразите. Действительно странно. Похоже, что сторонние библиотеки выглядят так. –

+0

@David: Это FMX, если VCL не был перенесен на Android. (Четвертый абзац.) –

ответ

0

К сожалению FMX растровых изображений не поточно, вы можете использовать их только в главном потоке (или в синхронном части другой поток).

+0

Документация напрямую заявляет, что растровые изображения FMX могут быть созданы/использованы/deleted в любом потоке: http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Multi-Threading_for_TBitmap,_TCanvas,_and_TContext3D Если они этого не делают, то это либо ошибка в FM-каркасе, либо в вашем коде. Если вы предоставите какой-либо пример, чтобы продемонстрировать проблему, мы можем попытаться выяснить, что не так. В противном случае ваш ответ кажется не очень полезным. –

+0

+ andrei galatyn, вы должны сначала посмотреть даты, мой комментарий - три года, и многое изменилось с тех пор, как в FMX. –

+0

Три года назад у вашего ответа также не было никаких подробностей/примеров. –