Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Cross-Platform-Entwicklung (https://www.delphipraxis.net/91-cross-platform-entwicklung/)
-   -   Delphi FMX : getContentResolver.query Crash und Jnet_Uri getPath (https://www.delphipraxis.net/205002-fmx-getcontentresolver-query-crash-und-jnet_uri-getpath.html)

stalkingwolf 22. Jul 2020 15:32

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:
            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);
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.

Code:
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('')
);
Da ist noch mehr Quellcode, aber der ist irrelevant.

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?

TurboMagic 26. Jan 2021 09:13

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

oakley 30. Jan 2021 12:42

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:
for I := 0 to Cursor.getColumnCount - 1 do
begin
  Memo1.Lines.Add(JStringToString(Cursor.getColumnName(I)) +': ' + JStringToString(Cursor.getString(I)));
end;
Anders als man häufig liest findet sich da aber nirgendwo der korrekte Pfad drin.
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

TurboMagic 30. Jan 2021 12:53

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:
function TFileBrowser.HandleIntentAction(const Data: JIntent): boolean;
begin
  log.d('Pfad: ' + JStringToString(Data.getData.getPath));
end;
Nur: ab Android 10 hilft dir der Pfad möglicherweise nicht. Wenn der nämlich auf
einen Ordner wie TPath.GetPublicDownloadsPath zeigt hat man da so ohne weiteres
keine Zugriffsberechtigung mehr.

Was aber seltsamerweise geht ist das hier:

Delphi-Quellcode:
  InputStream := MainActivity.getContentResolver.openInputStream(Data.getData);
  log.d('Zeichen 1: ' + InputStream.read.ToString);
  InputStream.close;
Damit erzeugt man einen input stream aus dem Intent und der Schnippsel oben
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...

oakley 30. Jan 2021 13:30

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

oakley 30. Jan 2021 14:27

AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
 
Delphi-Quellcode:
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;
InputStream.read(b); geht noch
ms.Write(b.Data^, b.Length); geht nicht mehr, hier hängt die App sich auf

LG

Mirko

TurboMagic 30. Jan 2021 14:37

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

oakley 30. Jan 2021 15:03

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;

TurboMagic 30. Jan 2021 15:17

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!

oakley 30. Jan 2021 15:46

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;

TurboMagic 30. Jan 2021 16:00

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?

oakley 30. Jan 2021 16:34

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

oakley 30. Jan 2021 23:09

AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
 
So weit so gut.

Ich habe jetzt folgenden Code für den Upload

Delphi-Quellcode:
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;
Der Upload zeigt ab und zu die Meldung "keine Duplikate zulässig" und der Fortschrittsbalken steht direkt nach beginn des Uploads bei 100%.
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:
procedure TMFORM.IdFTP1Work(ASender: TObject; AWorkMode: TWorkMode;
  AWorkCount: Int64);
begin
  TTask.Run(
  Procedure
  begin
    //Aktualisieren der Fortschrittsanzeige:
    ProgressBar1.Value:= AWorkCount;
  end);
end;
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.
Gibt überhaupt eine praktikable Lösung auf dem Handy oder kommt man da schnell an die Leistungsgrenze?

LG

Mirko

TurboMagic 31. Jan 2021 08:21

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

oakley 31. Jan 2021 12:48

AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
 
Hast Du eventuell eine Idee, woher die Meldung "keine Duplikate zulässig" kommt?

LG

Mirko

TurboMagic 31. Jan 2021 21:46

AW: FMX : getContentResolver.query Crash und Jnet_Uri getPath
 
Keine Ahnung, verwende normalerweise kein Indy...

TurboMagic 16. Feb 2021 13:10

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

TurboMagic 16. Feb 2021 14:36

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!

stalkingwolf 1. Mär 2021 15:16

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:
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;
Ich habe allerdings immernoch das Problem mit mehreren Dateien.
Sobald ich auf Data zugreife knallt es.
Code:
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);
addlog schreibt mir das in ein Memo und in eine ASCII Datei.
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:
if assigned(data.getClipData) then begin
.
.
else begin
.
.
end;
Was ich nun nur noch habe ist das die Datei nach Tmemorystream.savetofile(); nicht direkt vorhanden ist.
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