我做了一個應用程式只是為了拍照并將它們發送到服務器。在這些照片中,我在右下角編輯日期。如果用戶拍攝超過 9 張照片,應用程式會在此程序中凍結并詢問您是否要關閉應用程式。您可以選擇關閉應用程式或等待。單擊等待,該程序將處理保存到服務器的所有照片。但是收到此訊息很煩人且不專業。下面是代碼,也許你們中的一些人可以發現我犯的錯誤。
我使用 Tcamera 組件來制作照片。用于在應用程式中顯示照片的 TMSFMXtableview(TV1)。我使用 Timage 鏈接到 Tcamera 組件。
這是保存按鈕 onclick 的代碼。
procedure TFMmain.Button10Click(Sender: TObject);
VAR
B: TBitmap;
R : TRectf;
LMemStream: TMemoryStream;
i2,I,AN, NewWidth, NewHeight : Integer;
lExtensie : string;
Scale : double;
Fid : Integer;
begin
Cameracomponent1.Active := false;
button11.Visible := false;
button10.Visible := true;
if TV1.Items.Count>0 then
begin
for I := 0 to tv1.Items.Count-1 do
begin
B:= TV1.Items.Items[i].Bitmap;
R.Create(B.Width - 250, B.Height - 100, B.Width, B.Height);
B.Canvas.BeginScene;
try
B.Canvas.Font.Size := 40;
b.Canvas.Fill.Color := TAlphaColorRec.red;
B.Canvas.FillText(
R, DateToStr(Now), False, 100, [TFillTextFlag.RightToLeft],
TTextAlign.Center);
finally
B.Canvas.EndScene;
end;
LMemStream := TMemoryStream.Create;
try
TV1.Items.Items[i].Bitmap.SaveToStream(LMemStream);
storedprocFotoUp.Params[0].AsStream :=LMemStream;
LMemStream.Position := 0;
storedprocFotoUp.ExecProc;
finally
Lmemstream.Free;
end;
end;
tv1.Items.Clear;
button11.Visible := true;
button10.Visible := true;
Cameracomponent1.Active := true;
end
else
begin
button11.Visible := true;
button10.Visible := true;
Cameracomponent1.Active := true;
end;
end;
end;
storedprocfotoup 是服務器端的程序。
Procedure TServermodule.SavePhotoToServer(Stream: TStream);
const
BufSize = $8000;
var
Today : TDateTime;
Mem: TMemoryStream;
BytesRead, Vnr,Fnr: Integer;
Buffer: PByte;
fFilename, lExtensie, DT, Time: String;
begin
Today := NOW;
Flocation:= 'C:\test\';
lExtensie := '.jpg';
Time:= IntToStr(Yearof(Today)) IntToStr(Monthof(Today)) IntToStr(Dayof(Today)) IntToStr(Hourof(Today)) IntToStr(Minuteof(today)) IntToStr(MilliSecondof(today));
fFilename := 'F' Tijd lExtensie;
// save file to server
Mem := TMemoryStream.Create;
Mem.Position :=0;
GetMem(Buffer, BufSize);
try
repeat
BytesRead := Stream.Read(Pointer(Buffer)^, BufSize);
if BytesRead > 0 then
Mem.WriteBuffer(Pointer(Buffer)^, BytesRead);
until BytesRead < BufSize;
Mem.SaveToFile(Flocation fFilename);
finally
FreeMem(Buffer, BufSize);
Mem.Free;
end;
end;
我希望我提供了足夠的資訊。
uj5u.com熱心網友回復:
首先,評論一下您的服務器端處理可能更簡單并且消耗更少的記憶體。
SavePhotoToServer有一個TStream引數,因此您可以將該流保存到檔案中,而無需將資料復制到另一個流。
Procedure TServermodule.SavePhotoToServer(Stream: TStream);
var
...
f: TFileStream;
begin
...
f := TFileStream.Create(Flocation fFilename, fmCreate or fmShareExclusive);
try
f.CopyFrom(Stream, 0);
finally
f.Free;
end;
end;
您不需要的下一件事是檢查TV1.Items.Count>0然后在 for 回圈中執行所有操作。如果沒有專案,則 for 回圈中不會執行任何內容,因此此檢查是多余的。
最后,如果您確實想檢查是否有一些作業要做,更簡單的方法是首先檢查并在禁用按鈕之前退出該程序。
procedure TFMmain.Button10Click(Sender: TObject);
begin
if TV1.Items.Count>0 then
Exit;
Cameracomponent1.Active := false;
...
end;
現在到了最難的部分。您需要在后臺執行緒中呼叫上傳到服務器的代碼。否則您的應用程式將凍結。
發送單個影像很簡單,即使發送多個影像也不會那么復雜,但是您想知道該作業何時完成,以便再次啟用您的 UI。
為此,我將使用額外的 Boolean 標志Processing來使代碼更清晰,并使用兩個單獨的程序StartProcessing來EndProcessing包裝所有 UI 初始化和終結代碼。
額外的問題之一是確定代碼的哪些部分可以安全地放在后臺執行緒中,哪些不可以。
使用TBitmap后臺執行緒通常不是執行緒安全的,但據我所知,它在 Android 上應該是執行緒安全的。這意味著您可以將位圖保存到后臺執行緒中的流。這也將簡化其余的代碼。
處理邏輯將分為兩部分。首先將在位圖上繪制所需的內容,后臺執行緒將處理保存位圖以流式傳輸并發送它們。
請不要,從后臺執行緒觸摸 UI 不是執行緒安全的。在這種情況下,我將直接訪問 UI 組件,因為其余代碼將確保在執行緒運行時不會修改此串列。
通常,適當的執行緒安全代碼會在主執行緒中創建位圖的副本(我們不能只獲取參考,因為位圖可以同時修改或釋放),存盤在單獨的非 UI 集合中,然后將該集合傳遞給發送的后臺執行緒。復制位圖需要時間,并且在這種情況下制作快捷方式應該可以作業。
Android 特有的另一個問題是用戶可以隨時從您的應用程式切換到另一個應用程式,這也會干擾您的應用程式邏輯。對于這一部分,我將使用FormCloseQuery,但我必須注意,我不確定它在 Android 上的可靠性如何,因為作業系統無論如何都會殺死你的應用程式。
因此,當應用上述所有內容時,您的代碼作業流程將如下所示:
procedure TFMmain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
CanClose := not Processing;
end;
function TFMmain.StartProcessing: Boolean;
begin
Result := not Processing;
if Result then
begin
Processing := True;
// other UI logic
Cameracomponent1.Active := False;
...
end;
end;
procedure TFMmain.EndProcessing;
begin
Processing := False;
// other UI logic
Cameracomponent1.Active := True;
end;
procedure TFMmain.Button10Click(Sender: TObject);
begin
if not StartProcessing then
Exit;
try
// prepare bitmaps
for I := 0 to tv1.Items.Count-1 do
begin
B:= TV1.Items.Items[i].Bitmap;
R.Create(B.Width - 250, B.Height - 100, B.Width, B.Height);
B.Canvas.BeginScene;
try
B.Canvas.Font.Size := 40;
b.Canvas.Fill.Color := TAlphaColorRec.red;
B.Canvas.FillText(
R, DateToStr(Now), False, 100, [TFillTextFlag.RightToLeft],
TTextAlign.Center);
finally
B.Canvas.EndScene;
end;
end;
// run in background thread
TTask.Run(
procedure
var
I: Integer;
LMemStream: TMemoryStream;
begin
try
// iterating through UI component is not
// generally thread-safe and this kind of code
// can work only in limited scenario
for I := 0 to tv1.Items.Count-1 do
begin
LMemStream := TMemoryStream.Create;
TThread.Synchronize(nil,
procedure
begin
TV1.Items.Items[i].Bitmap.SaveToStream(LMemStream);
end);
storedprocFotoUp.Params[0].AsStream :=LMemStream;
LMemStream.Position := 0;
storedprocFotoUp.ExecProc;
end;
finally
TThread.Queue(nil,
procedure
begin
EndProcessing;
end);
end;
end);
except
EndProcessing;
raise;
end;
end;
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/418502.html
標籤:
