Android Code Snippet SaveAs - Let the user select a target folder + list of other related methods

Status
Not open for further replies.
B4A + B4i example: https://www.b4x.com/android/forum/t...e-and-load-external-files.132731/#post-838166
List of classes or libraries that can be used to access secondary storages:

ContentChooser (Phone libray) - allows the user to select a resource or file using external providers. Very useful and doesn't require permissions.

ExternalStorage - Allows accessing external (secondary) storages. Requires the user to first select the target folder. Once the user selected a folder, your app can read and write from that folder. Doesn't require any permission.
Not all folders are accessible with ExternalStorage in Android 11+. Specifically, root, Android/data and Download are not accessible: more information.

SaveAs- this code, the opposite of ContentChooser or the simpler version of ExternalStorage. Allows the user to choose the place where the file will be saved. Simple to work with and doesn't require permissions. Possible alternative to the external storage permission, which is mostly no longer available.

RuntimePermissions.GetSafeDirDefaultExternal - A folder on the secondary storage, where you app can access without permissions. The path is a bit cumbersome (Log it to see). Note that other apps can't access this folder.

Special MANAGE_EXTERNAL_STORAGE permission - mostly relevant to non-Google Play apps: https://www.b4x.com/android/forum/t...cess-internal-external-storage-sdk-30.130411/


B4X:
Sub SaveAs (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 ContentResolver As JavaObject = ctxt.InitializeContext.RunMethodJO("getContentResolver", Null)
        Dim out As OutputStream = ContentResolver.RunMethod("openOutputStream", Array(jo.RunMethod("getData", Null), "wt")) 'wt = Write+Trim
        File.Copy2(Source, out)
        out.Close
        Return True
    End If
    Return False
End Sub

Sub StartActivityForResult(i As Intent)
    Dim jo As JavaObject = GetBA
    ion = jo.CreateEvent("anywheresoftware.b4a.IOnActivityResult", "ion", Null)
    jo.RunMethod("startActivityForResult", Array(ion, i))
End Sub

Sub GetBA As Object
    Dim jo As JavaObject = Me
    Return jo.RunMethod("getBA", Null)
End Sub

Usage example:
B4X:
Private Sub Button1_Click
    File.WriteString(File.DirInternal, "test.txt", "test") 'just for the example.
    Wait For (SaveAs(File.OpenInput(File.DirInternal, "test.txt"), "application/octet-stream", "test.txt")) Complete (Success As Boolean)
    Log("File saved successfully? " & Success)
End Sub

If not using B4XPages, replace GetBA with:
B4X:
Sub GetBA As Object
   Dim jo As JavaObject
   Dim cls As String = Me
   cls = cls.SubString("class ".Length)
   jo.InitializeStatic(cls)
   Return jo.GetField("processBA")
End Sub

Supported in Android 5+ (21+).
Note that the user can change the file name. No simple way to get the chosen name.
 
Last edited:

asales

Expert
Licensed User
Longtime User
Do I need to change any parameter if I will save an image, instead a text file?
 

asales

Expert
Licensed User
Longtime User
I want to put this code in a class and call it from others activities (I don't will migrate my app to b4xpages).

Is just to create a class, left the Initialize sub empty, put this code and call this way?:

B4X:
Sub Globals
    Public clsSave As clsSaveAs
End Sub

Sub Activity_Create(FirstTime As Boolean)   
    Activity.LoadLayout("1")

    clsSave.Initialize
    (...)
End Sub

Sub SaveMyImage
    (...)
    Wait For (clsSave.SaveAs(File.OpenInput(File.DirInternal, "img1.jpg"), "application/octet-stream", "img1.jpg")) Complete (Success As Boolean)
    (...)
End Sub

Thanks in advance.
 

Xfood

Expert
Licensed User
is there a way using this class / Lib to read an articles.csv file from the externalroot / download folder?
 

Xfood

Expert
Licensed User
Good morning,
Thanks Erel
I wanted to use this library,
but i don't know how to open a file in the download folder
maybe I have the wrong post?
1619939625961.png

EF as ExternalFile ????
1619939728863.png

could you correct this code please
Thank you
B4X:
Private Sub Button1_Click
    Private cNomeFileArticoli As String = "download/articoli.csv"
    Dim ReaderFileTxt As TextReader

    If File.Exists(File.DirRootExternal, cNomeFileArticoli)= True Then
        'ReaderFileTxt.Initialize(File.OpenInput(File.DirRootExternal, cNomeFileArticoli))
        
        ReaderFileTxt.Initialize(Storage.OpenInputStream(cNomeFileArticoli))
    End If

End Sub
 
Status
Not open for further replies.
Top