Android Question Save issue

giggetto71

Active Member
Licensed User
Longtime User
Hi,
I am having issue with this simple code I took from the Erel's TextEditor example.

B4X:
Private Sub btnBackup_Click
      
    Wait For (SaveFile(File.OpenInput(File.DirInternal, "BinaryFileToSave"), "application/octet-stream", "BinaryFileToSave")) Complete (Success As Boolean)
    If Success Then
      ToastMessageShow("File successfully saved  to the selected folder",False)
    
    Else
         ToastMessageShow("File not saved to the selected folder",False)               
      
    End If


End Sub

basically if I simply press "save" button when the file manager comes up, it works fine. If I select an existing file it works ok most of the time (I know it does not make sense but I have the impression that it works better if I do it "quickly", if I do it "slowly" it does not work and it does not even get to the "Success" evaluation.). I type the file name molst of the times it does not work again no messages. and if I retry, I see that the file is actually created but with size 0.
Any idea?
thanks
 

teddybear

Well-Known Member
Licensed User
What is the sub SaveFile, you'd better to upload a small project
 
Upvote 0

giggetto71

Active Member
Licensed User
Longtime User
sorry....I forgot to attach the save file. here it is.

B4X:
Sub SaveFile (Source As InputStream, MimeType As String, Title As String) As ResumableSub
    Dim intent As Intent
    intent.Initialize("android.intent.action.CREATE_DOCUMENT", "")
    intent.AddCategory("android.intent.category.OPENABLE")
    intent.PutExtra("android.intent.extra.TITLE", Title)
    intent.SetType(MimeType)
    StartActivityForResult(intent)
    Wait For ion_Event (MethodName As String, Args() As Object)
    If -1 = Args(0) Then 'resultCode = RESULT_OK
        Dim result As Intent = Args(1)
        Dim jo As JavaObject = result
        Dim ctxt As JavaObject
        Dim out As OutputStream = ctxt.InitializeContext.RunMethodJO("getContentResolver", Null).RunMethod("openOutputStream", Array(jo.RunMethod("getData", Null)))
        File.Copy2(Source, out)
        out.Close
        Return True
    End If
    Return False
End Sub
 
Upvote 0

zed

Well-Known Member
Licensed User
Your problem is very common with ACTION_CREATE_DOCUMENT on Android, and it doesn't really stem from your code but from how Android handles the output stream when the user selects an existing file, types a new name, or takes too long to submit.

What you're seeing (file created but size = 0, no callback, random behavior) corresponds exactly to an OutputStream that is never actually opened or is closed by Android before File.Copy2 starts.

StartActivityForResult + ion_Event is too fragile. The ion_Event callback isn't always triggered depending on the Android version, launcher, or file explorer. When the user types a name, Android creates a virtual document and then submits. But the callback might arrive before the stream is ready, or not arrive at all.

File.Copy2(Source, out) can fail silently. If OUT is Null (which happens when Android can't open the stream), File.Copy2 copies nothing. Result: a 0-byte file and no error.

Check that out is not Null. Otherwise, Android hasn't opened the stream. Use Try/Catch to capture silent errors.

Here's a version that should work better.

Ex.:
Sub SaveFile (FileName As String, MimeType As String, Title As String) As ResumableSub
    Dim intent As Intent
    intent.Initialize("android.intent.action.CREATE_DOCUMENT", "")
    intent.AddCategory("android.intent.category.OPENABLE")
    intent.PutExtra("android.intent.extra.TITLE", Title)
    intent.SetType(MimeType)
    StartActivityForResult(intent)

    Wait For ion_Event (MethodName As String, Args() As Object)
    If Args(0) = -1 Then
        Try
            Dim result As Intent = Args(1)
            Dim jo As JavaObject = result
            Dim ctxt As JavaObject
            Dim uri As Object = jo.RunMethod("getData", Null)

            Dim out As OutputStream = ctxt.InitializeContext.RunMethodJO("getContentResolver", Null).RunMethod("openOutputStream", Array(uri))
            If out = Null Then Return False

            'Open the source file now, not before !
            Dim Inp As InputStream = File.OpenInput(File.DirInternal, FileName)

            File.Copy2(Inp, out)
            Inp.Close
            out.Close

            Return True
        Catch
            Return False
        End Try
    End If

    Return False
End Sub

The source stream is opened at the last moment, so it never times out.
The output stream is checked before copying.
Silent errors are captured.
The behavior remains stable even if the user types a name, replaces a file, or takes 10 seconds to submit.


It would be better to use FileProvider
 
Last edited:
Upvote 0
Top