![]() |
Versuch: TFileBrowser für Android, geht das ohne globale Variable?
Ich habe versucht, einen Ersatz für TFileOpenDialog zu bauen, der möglichst einfach für Android aufrufbar ist. Das geht aber nur, indem der Benutzer eine Callback-Funktion definiert, also ein "OnExecute", jedenfalls fällt mir nichts anderes ein. Damit der Aufruf möglichst zusammenhängend ist, kann man das Callback anonym definieren.
Hier ist ein Beispiel für den Aufruf:
Delphi-Quellcode:
Dafür ist TFileBrowser.BrowseForFile eine class procedure. Bisher habe ich das nur ans Laufen bekommen, indem ich im Interface eine globale Variable vom Typ TFileBrowser definiere. Kann man das irgendwie schlauer machen?
procedure TForm1.BrowseForVideoFile;
begin {$IFDEF ANDROID} TFileBrowser.BrowseForFile(ctVideo, // This procedure is called when the user has picked an item procedure(var filename: string; var success: boolean) begin if success then begin fVideoFilename := filename; Edit2.text := fVideoFilename; ProcessVideoFile; end else TDialogService.ShowMessage ('Pick the file by opening the Documents folder. Don''t use any of the other apps.'); end); {$ELSE} ... end; Hier ist der source code für TFileBrowser, ist nicht so lang:
Delphi-Quellcode:
Gruß, Renate
unit UAndroidTools;
interface uses System.Messaging, AndroidAPI.Helpers, AndroidAPI.Jni.Os, AndroidAPI.Jni.GraphicsContentViewText, AndroidAPI.Jni.Net, FMX.Platform.Android, AndroidAPI.JNIBridge, AndroidAPI.Jni.JavaTypes; type TContentEnum = (ctVideo, ctImages, ctAudio, ctText, ctAll); TFileBrowseEvent = reference to procedure(var Filename: string; var Success: boolean); TFileBrowser = class private fOnExecute: TFileBrowseEvent; fFilename: string; function HandleIntentAction(const Data: JIntent): boolean; procedure DoExecute(Success: boolean); protected fMessageSubscriptionID: integer; procedure HandleActivityMessage(const sender: TObject; const M: TMessage); public ///<summary> Use Android API to have the user pick a file with a certain content type </summary> /// <param OnExecute> Event occuring when the user has picked a file. Write a (anonymous) procedure(var Filename: string; var Success: boolean) to handle the event. <param> class procedure BrowseForFile(Content: TContentEnum; OnExecute: TFileBrowseEvent); end; implementation const ContentStrings: array [TContentEnum] of string = ('video/*', 'image/*', 'audio/*', 'text/*', '*/*'); { TFileBrowser } var //Wie schafft man das ohne globale Variable? _TheFileBrowser: TFileBrowser; class procedure TFileBrowser.BrowseForFile(Content: TContentEnum; OnExecute: TFileBrowseEvent); var Intent: JIntent; begin _TheFileBrowser := TFileBrowser.Create; //Das ist doch irgendwie doof. With _TheFileBrowser do begin fOnExecute := OnExecute; fMessageSubscriptionID := TMessageManager.DefaultManager.SubscribeToMessage (TMessageResultNotification, HandleActivityMessage); Intent := TJIntent.Create; Intent.setType(StringToJString(ContentStrings[Content])); Intent.setAction(TJIntent.JavaClass.ACTION_GET_CONTENT); MainActivity.startActivityForResult(Intent, 0); end; end; procedure TFileBrowser.DoExecute(Success: boolean); begin if assigned(fOnExecute) then fOnExecute(fFilename, Success); self.disposeof; end; procedure TFileBrowser.HandleActivityMessage(const sender: TObject; const M: TMessage); begin if M is TMessageResultNotification then begin DoExecute(HandleIntentAction(TMessageReceivedNotification(M).Value)); end; end; function TFileBrowser.HandleIntentAction(const Data: JIntent): boolean; var C: JCursor; I: integer; begin C := MainActivity.getContentResolver.query(Data.getData, nil, StringToJString(''), nil, StringToJString('')); C.moveToFirst; Result := false; for I := 0 to C.getColumnCount - 1 do begin if JStringToString(C.getColumnName(I)) = '_data' then // '_data' column contains the path begin fFilename := JStringToString(C.getString(I)); Result := true; Break; end; end; if not Result then fFilename := ''; end; end. |
AW: Versuch: TFileBrowser für Android, geht das ohne globale Variable?
Ich empfinde das with als deutlich schlimmer als die globale Variable. ;-)
Da du um eine Instanz ja wohl nicht herumkommst, kannst du die Referenz aber als
Delphi-Quellcode:
in der Klasse unter private deklarieren. Dann hängt die nicht lose als globale Variable herum. Und zur Freigabe der Instanz gibt es einen
class var
Delphi-Quellcode:
. Dann musst du die Instanz vermutlich gar nicht immer neu erstellen.
class destructor
|
AW: Versuch: TFileBrowser für Android, geht das ohne globale Variable?
Wenn das eine globale Variable sein kann, dann könntest Du im TFileBrowser eine class var anlegen.
Normalerweise wird sowas über z.B. Instance gemacht. Nur mal so grob hingeschrieben, ohne Gewähr:
Delphi-Quellcode:
type TMyClass = class class var FInstance; class function Instance : TMyClass; class constructor Create; class destructor Destroy; procedure CallWhatever; end; class constructor TMyClass.Create; begin FInstance := nil; end; class destructor TMyClass.Destroy; begin FInstance.Free; end; class function TMyClass.Instance : TMyClass; begin if not Assigned( FInstance ) then begin FInstance := TMyClass.Create; end; Result := FInstance; end; ... ... ... TMyClass.Instance.CallWhatever; //<== geht jederzeit, wird beim ersten Aufruf erzeugt, und lebt bis zum Programmende in einer Instanz .... Je nachdem sollte man das aber noch threadsafe absichern, bei Bedarf. Edit: @jaenicke, völlig richtig mit dem destruktor, jetzt isser drin. |
AW: Versuch: TFileBrowser für Android, geht das ohne globale Variable?
Vielen Dank an euch beide, so wirds gemacht. Mal wieder dazugelernt.
Also, ohne das "with" finde ich, dass es noch doofer aussieht :) Gruß, Renate |
AW: Versuch: TFileBrowser für Android, geht das ohne globale Variable?
Zitat:
|
AW: Versuch: TFileBrowser für Android, geht das ohne globale Variable?
Zitat:
Zitat:
So etwas ist dann teilweise sehr schwer zu finden, da es oft problemlos weiter kompiliert, an anderer Stelle aber plötzlich Fehler auftreten, die man dann ewig sucht. Von daher macht man sich damit nur unnötigerweise Probleme. |
AW: Versuch: TFileBrowser für Android, geht das ohne globale Variable?
So funktioniert's prima, und ganz ohne with:
Delphi-Quellcode:
Danke nochmal.
class function TFileBrowser.Instance: TFileBrowser;
begin if not assigned(FInstance) then FInstance := TFileBrowser.Create; Result := FInstance; end; class constructor TFileBrowser.Create; begin //Ist doch eigentlich unnötig, oder? FInstance := nil; end; class destructor TFileBrowser.Destroy; begin fInstance.free; end; class procedure TFileBrowser.BrowseForFile(Content: TContentEnum; OnExecute: TFileBrowseEvent); begin Instance.Initialize(Content, OnExecute); end; procedure TFileBrowser.Initialize(Content: TContentEnum; OnExecute: TFileBrowseEvent); var Intent: JIntent; begin fOnExecute := OnExecute; fMessageSubscriptionID := TMessageManager.DefaultManager.SubscribeToMessage (TMessageResultNotification, HandleActivityMessage); Intent := TJIntent.Create; Intent.setType(StringToJString(ContentStrings[Content])); Intent.setAction(TJIntent.JavaClass.ACTION_GET_CONTENT); MainActivity.startActivityForResult(Intent, 0); end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:33 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz