FMX : getContentResolver.query Crash und Jnet_Uri getPath
Ich versuche gerade ein ÖffnenDialog für Bilder in meine APP einzubauen.
Dabei bin ich auf 2 Probleme gestoßen. 1. Wenn ich das ActivityResult zurück bekomme und mir den JCursor mit SharedActivity.getContentResolver.query holen möchte, dann stürzt das APP ab, wenn ich im Bilderdialog mehr als ein Bild ausgewählt habe. Den Bilderdialog starte ich mit folgendem Quellcode
Code:
Funktioniert auch soweit, wenn ich nur 1 Datei auswähle. Aber es war ganz praktikabel wenn der Anwender mehr als eine Datei auswählen könnte.
FMessageSubscriptionID := TMessageManager.DefaultManager.SubscribeToMessage (TMessageResultNotification, HandleActivityMessage);
RequestCode := 0; Intent := TJIntent.JavaClass.init(TJIntent.JavaClass.ACTION_PICK); intent.setType(StringToJString('image/*')); intent.setAction(TjIntent.JavaClass.ACTION_GET_CONTENT); Intent.putExtra(TJIntent.JavaClass.EXTRA_ALLOW_MULTIPLE,true); ResolveInfo := SharedActivity.getPackageManager.resolveActivity(Intent, 0); if ResolveInfo <> nil then SharedActivity.startActivityForResult(Intent, RequestCode);
Code:
Da ist noch mehr Quellcode, aber der ist irrelevant.
var
C : JCursor; cols : TJavaObjectArray<JString>; begin if Assigned(Data) then begin cols:= TJavaObjectArray<JString>.Create(1); cols[0] := StringToJString('_display_name'); c:= SharedActivity.getContentResolver.query( data.getData, cols, nil, //StringtoJString(''), nil, nil //StringtoJString('') ); 2. Wenn ich mir mit Data.getData.getPath den Pfad ausgeben lasse steht dort /document/image:1456 Den Pfad gibt es nicht. Wie bekomme ich hier den korrekten Pfad? Ich glaube ich hab hier einen falschen Denkansatz oder? Ich bekomme gar nicht den Pfad raus? Sicherheit? Weil die Document ID ist image:1456. D.h das System verhindert das ich ermitteln kann wo die Datei liegt? |
AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
Hallo,
das was da zurückkommt, soweit ich mich momentan schon eingelesennhabe, ist kein richtiger klassischer Dateipfad sondern eine FILE URI oder so. Schau dir doch mal die Doku zu dem Intent mal an: https://developer.android.com/refere...ON_GET_CONTENT Grüße TurboMagic |
AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
Da bin ich auch gerade dran.
Er gibt Dir eine URI und damit soll man den richtigen Dateipfad ermitteln können. Wenn Du nil statt des JArray cols verwendest fragst Du alle spalten ab die da sind. Um zu sehen welche das sind habe ich das einfach so gemacht und alles in ein Memo schreiben lassen:
Delphi-Quellcode:
Anders als man häufig liest findet sich da aber nirgendwo der korrekte Pfad drin.
for I := 0 to Cursor.getColumnCount - 1 do
begin Memo1.Lines.Add(JStringToString(Cursor.getColumnName(I)) +': ' + JStringToString(Cursor.getString(I))); end; Es soll eine Spalte namens _data existieren wo der richtige Pfad drin steht aber die wird bei mir auch nicht mit ausgegeben, sprich existiert an der Stelle nicht. In Java soll der Name hier stehen MediaStore.Images.Media.DATA was in FMX glaube ich TJImages_ImageColumns.JavaClass.DATA entspricht aber da kommt auhc nichts. Bist Du da eventuell weiter gekommen als ich? LG Mirko |
AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
Hallo,
diese _Data Spalte gab's bei mir auch nicht, aber ich hab' den woanders gefunden:
Delphi-Quellcode:
Nur: ab Android 10 hilft dir der Pfad möglicherweise nicht. Wenn der nämlich auf
function TFileBrowser.HandleIntentAction(const Data: JIntent): boolean;
begin log.d('Pfad: ' + JStringToString(Data.getData.getPath)); end; einen Ordner wie TPath.GetPublicDownloadsPath zeigt hat man da so ohne weiteres keine Zugriffsberechtigung mehr. Was aber seltsamerweise geht ist das hier:
Delphi-Quellcode:
Damit erzeugt man einen input stream aus dem Intent und der Schnippsel oben
InputStream := MainActivity.getContentResolver.openInputStream(Data.getData);
log.d('Zeichen 1: ' + InputStream.read.ToString); InputStream.close; liest das erste Zeichen dieses Streams und schreibt es ins Log. Ich fände es halt toll wenn's doch eine Android 10/11 kompatible Methode gäbe alle Dateien mit einer gewissen Endung die im TPath.GetSharedDownloadsPath liegen und man auf die Lese/Schreibzugriff hätte. AQchließlich ist das ja ein öffentlicher Ordner... |
AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
Hallo,
Data.getData.getPath gibt aber auf meinem Samsung nicht den Pfad aus, den ich z.B. für den Upload auf einen FTP Server brauchen könnte. Ich habe da sowas wie /document/image:6775 . Der InputStream ist aber interessant weil der IndyFTP Client auch einen Stream für den Upload verwendet. Ich habe jetzt folgendes versucht: var ms : TMemoryStream; InputStream : JInputStream; b: TJavaArray<Byte>; InputStream := MainActivity.getContentResolver.openInputStream(Da ta.getData); b := TJavaArray<Byte>.Create(InputStream.available); InputStream.read(b); ms.Write(b.Data^, b.Length); InputStream.close; idftp1.Connect; idftp1.Put(ms,'test.jpg',false,-1); idftp1.Disconnect; Die Galerie wird geöffnet, ich tippe auf das Bild und da hängt sich die App auf. LG Mirko |
AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
Delphi-Quellcode:
InputStream.read(b); geht noch
var
ms : TMemoryStream; InputStream : JInputStream; b: TJavaArray<Byte>; InputStream := MainActivity.getContentResolver.openInputStream(Da ta.getData); b := TJavaArray<Byte>.Create(InputStream.available); InputStream.read(b); ms.Write(b.Data^, b.Length); InputStream.close; idftp1.Connect; idftp1.Put(ms,'test.jpg',false,-1); idftp1.Disconnect; ms.Write(b.Data^, b.Length); geht nicht mehr, hier hängt die App sich auf LG Mirko |
AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
1. Das was da zurück kommt ist tatsächlich kein richtiger Dateiname sondern eine URI.
Das ist ja auch Absicht von denen, denn die wollen für viele Pfade ja nicht mehr, dass du direkt Datei mäßig darauf zugreifst. 2. Warum es bei dir crash weiß ich nicht wirklich, aber was ist denn der Rückgabewert von Read? Ich sehe auch nirgens, wo du deinen ms erzeugst... Grüße TurboMagic |
AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
Ja stimmt ich habe ms := TMemoryStream.Create; hinzugefügt und er stürzt nicht mehr ab.
Jetzt muss ich es nur noch ein wenig verbessern mit Fortschrittsbalken und mehreren Dateien und dann passt das. Die Funktion sieht damit bis jetzt so aus: function TMFORM.HandleIntentAction(const Data: JIntent): Boolean; var C: JCursor; I: Integer; ms : TMemoryStream; InputStream : JInputStream; b: TJavaArray<Byte>; begin Memo1.Lines.Add('URI:' + JStringToString(Data.getData.toString)); // this returns the URI in string perfectly... so I know that I am getting the file path properly InputStream := MainActivity.getContentResolver.openInputStream(Da ta.getData); b := TJavaArray<Byte>.Create(InputStream.available); ms := TMemoryStream.Create; InputStream.read(b); Memo1.Lines.Add('Stream länge:' + inttoStr(b.Length)); ms.Write(b.Data^, b.Length); InputStream.close; idftp1.Connect; ms.Position := 0; idftp1.Put(ms,'test.jpg'); idftp1.Disconnect; end; |
AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
Hinweis für dich:
bevor du das nächste Mal Quellcode postest eifnach mal den "Delphi-Helm" oberhalb des Editors anklicken und den QUellcode dann dazwischen einfügen. Dann wird er sauber formatiert angezeigt! |
AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
Hey,
ja ich weiß aber ich habe den Betrag editiert und da hatte ich die Option nicht auf den Helm zu klicken. So habe ich es jetzt für mehrere Dateien ohne Fortschrittsbalken gelöst. Hier ist noch das Problem, dass der Bildschirm schwarz wird bis der Upload abgeschlossen ist.
Delphi-Quellcode:
function TMFORM.HandleIntentAction(const Data: JIntent): Boolean;
var C: JCursor; I, count: Integer; ms : TMemoryStream; InputStream : JInputStream; b: TJavaArray<Byte>; begin count := Data.getClipData().getItemCount(); for i := 0 to count-1 do begin Memo1.Lines.Add('URI:' + JStringToString(Data.getClipData().getItemAt(i).getUri.toString)); InputStream := MainActivity.getContentResolver.openInputStream(Data.getClipData().getItemAt(i).getUri); b := TJavaArray<Byte>.Create(InputStream.available); ms := TMemoryStream.Create; InputStream.read(b); Memo1.Lines.Add('Stream länge:' + inttoStr(b.Length)); ms.Write(b.Data^, b.Length); InputStream.close; if not idftp1.Connected then idftp1.Connect; ms.Position := 0; idftp1.Put(ms,'test'+InttoStr(i)+'.jpg'); ms.Free; b.Free; end; idftp1.Disconnect; end; |
AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
Tja, der Bildschirm wird vermutlich schwarz, weil das vermutlich eine blockierende Operation ist.
Indy arbeitet glaube ich mehrheitlich blockierend. Kann das evtl. in einen Thread/Task gepackt werden? |
AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
Ja hab es in einen Task gepackt und er blockiert nicht mehr.
Muss noch Upload Progress machen usw. Wenn ich fertig bin poste ich den Code. LG Mirko |
AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
So weit so gut.
Ich habe jetzt folgenden Code für den Upload
Delphi-Quellcode:
Der Upload zeigt ab und zu die Meldung "keine Duplikate zulässig" und der Fortschrittsbalken steht direkt nach beginn des Uploads bei 100%.
function TMFORM.HandleIntentAction(const Data: JIntent): Boolean;
var C: JCursor; count: Integer; InputStream : JInputStream; ms : TMemoryStream; b: TJavaArray<Byte>; wfilter: TJavaObjectArray<JString>; filename : String; begin count := Data.getClipData().getItemCount(); ProgressBar1.Min := 0; ProgressBar1.Max := count; TTask.Run( Procedure var i,m : Integer; begin for i := 0 to count-1 do begin C := MainActivity.getContentResolver.query(Data.getClipData().getItemAt(i).getUri,nil,StringToJString(''),nil,StringToJString('')); C.moveToFirst; for m := 0 to C.getColumnCount - 1 do begin if JStringToString(C.getColumnName(m)) = '_display_name' then begin filename := JStringToString(C.getString(m)); break; end; end; InputStream := MainActivity.getContentResolver.openInputStream(Data.getClipData().getItemAt(i).getUri); ms.Free; b.Free; b := TJavaArray<Byte>.Create(InputStream.available); ms := TMemoryStream.Create; InputStream.read(b); ms.Write(b.Data^, b.Length); InputStream.close; ms.Position := 0; if not idftp1.Connected then idftp1.Connect; idftp1.Put(ms,filename); end; idFTP1.Disconnect; end); end; Hier hätte ich gerne etwas das die geladenen kBytes pro Datei anzeigt. Geht sowas? Und der Fortschrittsbalken ist sehr dünn, kann man den etwas breiter machen? In Firemonkey kann ich zwar die Höhe mit der Maus ziehen, wird aber direkt wieder zurück gestellt.
Delphi-Quellcode:
Ich wollte die Bilder vor dem Upload auch noch verkleinern denn ich brauche die Vollauflösung der Kamera nicht und der Upload geht wesentlich schneller.
procedure TMFORM.IdFTP1Work(ASender: TObject; AWorkMode: TWorkMode;
AWorkCount: Int64); begin TTask.Run( Procedure begin //Aktualisieren der Fortschrittsanzeige: ProgressBar1.Value:= AWorkCount; end); end; Gibt überhaupt eine praktikable Lösung auf dem Handy oder kommt man da schnell an die Leistungsgrenze? LG Mirko |
AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
Guten Morgen,
wenn du den Prozentbalken etwas breiter haben willst, musst du dich mit den FMX Stilen beschäftigen. Du brauchst einen eigenen Stil für den Prozentbalken. Schau doch mal, ob du nicht mit der rechten Maustaste auf deinen Prozentbalken klicken kannst und dort eine Option findest um einen eigenen Stil anzulegen. Den kannst du dann im Stildesigner bearbeiten. Die meisten Stile sind eine Mischung aus einem Bereich einer Bitmap und aus graphischen Objekten. Grüße TurboMagic |
AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
Hast Du eventuell eine Idee, woher die Meldung "keine Duplikate zulässig" kommt?
LG Mirko |
AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
Keine Ahnung, verwende normalerweise kein Indy...
|
AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
Hallo,
habe mich heute auch wieder mit dem Datei Auswählen Thema beschäftigt. Leider mit weniger Erfolg als du. Eine einzelne bekomme ich und kann sie auslesen über Data.getData, sobald ich aber das EXTRA_ALLOW_MULTIPLE hinzufüge und im HandleIntentAction auf Data.getClipData().getItemCount() zugreife erhalte ich eine Segmentverletzung (11). Außerdem löst er dieses HandleIntentAction bereits beim Tippen auf eine Datei aus. In meinem Fall hab' ich als MIME Type gerade Text/* angegeben. Ich nutze Delphi 10.4.1 und ein Android 10 Gerät. Woran kann das liegen? Grüße TurboMagic |
AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
Ursache gefunden: liegt am MIME type!
Mit image/* geht sowas, da stürzt ClipData nicht ab und man bekommt die Chance mehrere Bilder auszuwählen, mit */* geht's nicht. Da geht nur einzelauswahl. Mist! |
AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
Hey danke für eure weitere Diskussion.
Ich habe das Thema damals zur Seite gelegt weil ich nicht weiterkam. Ich habe das ganze nun auch gelöst für EINE Datei
Code:
Ich habe allerdings immernoch das Problem mit mehreren Dateien.
InputStream := SharedActivity.getContentResolver.openInputStream(Data.getData);
b := TJavaArray<Byte>.Create(InputStream.available); ms := TMemoryStream.Create; InputStream.read(b); ms.Write(b.Data^, b.Length); ms.SaveToFile( filename ); ms.Free; b.Free; InputStream.close; Sobald ich auf Data zugreife knallt es.
Code:
addlog schreibt mir das in ein Memo und in eine ASCII Datei.
function TFmain.OnActivityResult(RequestCode, ResultCode: Integer; Data: JIntent): Boolean;
begin if RequestCode = ScanRequestCode then begin if ResultCode = TJActivity.JavaClass.RESULT_OK then begin if Assigned(Data) then begin addlog(data.getData.getPath); Mit einer Datei kein Problem. Sobald 2 oder mehr Dateien selektiert wurden stürzt das ganze ab. Wenn ich den Code umschreibe was ihr nutzt also Data.getClipData().getItemCount(); JStringToString(Data.getClipData().getItemAt(i).ge tUri.toString) Dann funktioniert es mit 2 Dateien, aber nicht mehr wenn ich eine Datei auswähle. Ich vermute es ligt am Aufruf der Auswahl. Wie schaut bei euch der der Quellcode aus? Meiner ist noch wie auf Seite 1. EDIT : Hab das soweit nun alles hinbekommen. Musste eine Kombination aus beidem einbinden und ganz oben abprüfen
Code:
Was ich nun nur noch habe ist das die Datei nach Tmemorystream.savetofile(); nicht direkt vorhanden ist.
if assigned(data.getClipData) then begin
. . else begin . . end; Also ein fileexist danach gibt false aus. Das dauert eine Zeit bis die Datei vorhanden ist und man diese öffnen kann. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:16 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz