即使调用Cancel
,TTask仍在运行。
我有一个网格,我用键盘箭头滚动,每次更改行时,我都会销毁旧的TAsyncImage(如果有),并为新行创建一个新的TAsyncImages并加载图像。如果我滚动得足够快,看来被破坏的TAsyncImages中的旧TTasks仍在运行,并且以某种方式更改了新创建的TAsyncImages。
type
TAsyncImage = class(TImage)
private
FTask: ITask;
FOnFinish: TNotifyEvent;
FOnLoaded: TNotifyEvent;
procedure SetOnFinish(const Value: TNotifyEvent);
procedure SetOnLoaded(const Value: TNotifyEvent);
public
destructor Destroy; override;
property Async: Boolean read FAsync write FAsync;
property OnThumbLoaded: TNotifyEvent read FOnLoaded write SetOnLoaded;
property OnFinish: TNotifyEvent read FOnFinish write SetOnFinish;
end;
implementation
{ TAsyncImage }
destructor TAsyncImage.Destroy;
begin
if Assigned(FTask) and (FTask.Status = TTaskStatus.Running) then
begin
FTask.Cancel;
CheckSynchronize;
end;
FPicture.Free;
inherited Destroy;
end;
procedure TAsyncImage.LoadFromJPEG(AFileName: string; Scale: TJPEGScale);
var
J: TJPEGImage;
begin
if FAsync then
begin
FTask := TTask.Run(
procedure
var
B: TBitmap;
J: TJPEGImage;
begin
J := TJPEGImage.Create;
B := TBitmap.Create;
try
J.LoadFromFile(AFileName);
TThread.Synchronize(nil,
procedure
begin
if Assigned(FOnLoaded) then
FOnLoaded(Self);
end
);
J.Scale := jsEighth;
B.Assign(J);
if TTask.CurrentTask.Status = TTaskStatus.Canceled then
Exit;
TThread.Synchronize(nil,
procedure
begin
if Assigned(Picture) then
Picture.Assign(B);
end);
if TTask.CurrentTask.Status = TTaskStatus.Canceled then
Exit;
if Scale <> jsEighth then
begin
J.Scale := Scale;
B.Assign(J);
TThread.Synchronize(nil,
procedure
begin
if Assigned(Picture) then
Picture.Assign(B);
if Assigned(FOnFinish) then
FOnFinish(Self);
end);
end;
finally
J.Free;
B.Free;
end;
end
);
end
else
begin
J := TJPEGImage.Create;
J.LoadFromFile(AFileName);
if Assigned(FOnFinish) then
FOnFinish(Self);
J.Scale := Scale;
Picture.Assign(J);
J.Free;
end;
end;
或者,如果有更好的异步加载图像的解决方案。