Android Tutorial [B4X] TextEditor - Save and load external files

This is a B4i and B4A example, which demonstrates various external files related tasks.

1626784777442.png
1626784790557.png


The behavior is not exactly the same as the platforms capabilities and behavior are different.

B4A
Note that no permission is needed. The minimum version was set to 7 (API 24), though it will probably work in older versions as well.
Don't miss the manifest editor additions and ime in the main module.

B4i
Don't miss the main module PListExtra attributes and OpenUrl event.

A bit related B4J example: https://www.b4x.com/android/forum/threads/class-recent-files-manager.104633/post-822842


Updates:

- 9/2023 - Fixed an issue in B4A where overwriting existing files didn't trim file. Thanks @noeleon for reporting!
 

Attachments

  • TextEditor.zip
    184.2 KB · Views: 2,260
Last edited:

LucaMs

Expert
Licensed User
Longtime User
Where is the code used and the full stacktrace? I don´t think anyone can help without.
The source code is in my post; also, it uses the FileHandler class which is part of the Erel's example project.
You can see the data of the selected file (log).
The only code that is missing is the one about the MediaPlayer:
B4X:
    mMediaPlayer.Load(Result.FileName, Result.RealName)
    mMediaPlayer.Play
I also tried:
B4X:
    mMediaPlayer.Load(Result.Dir, Result.RealName)
    mMediaPlayer.Play
although it seems to me that neither could have worked and indeed it is.

DIR: ContentDir
FN : content://com.android.providers.media.documents/document/audio%3A2247
RN : Dream_It_Possible.flac
Error occurred on line: 85 (B4XMainPage)
java.io.IOException: Prepare failed.: status=0x1
at android.media.MediaPlayer._prepare(Native Method)
at android.media.MediaPlayer.prepare(MediaPlayer.java:1313)
at anywheresoftware.b4a.objects.MediaPlayerWrapper.loadAfterReset(MediaPlayerWrapper.java:101)
at anywheresoftware.b4a.objects.MediaPlayerWrapper.Load(MediaPlayerWrapper.java:66)
at b4a.example.b4xmainpage$ResumableSub_pnlKey_LongClick.resume(b4xmainpage.java:274)
at anywheresoftware.b4a.shell.DebugResumableSub$DelegatableResumableSub.resumeAsUserSub(DebugResumableSub.java:48)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:732)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:348)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:255)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:157)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:201)
at anywheresoftware.b4a.shell.DebugResumableSub$DelegatableResumableSub.resume(DebugResumableSub.java:43)
at anywheresoftware.b4a.BA.checkAndRunWaitForEvent(BA.java:275)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:150)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:201)
at anywheresoftware.b4a.keywords.Common$15.run(Common.java:1804)
at android.os.Handler.handleCallback(Handler.java:808)
at android.os.Handler.dispatchMessage(Handler.java:101)
at android.os.Looper.loop(Looper.java:166)
at android.app.ActivityThread.main(ActivityThread.java:7529)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)
 
Last edited:

Erel

B4X founder
Staff member
Licensed User
Longtime User
- 9/2023 - Fixed an issue in B4A where overwriting existing files didn't trim file. Thanks @noeleon for reporting!

The change is in FileHandler.SaveAs:
B4X:
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
 

ivan.tellez

Active Member
Licensed User
Longtime User
Tunning the example as is, it works if a file is selected directly in the Android chooser but if you select the "file from other apps", (for example a file explorer app like Solid explorer, My Files, Drive, etc) the app cant load the file.

This is shown in the Log:

Sub ExtractInformationFromURI
Log(LastException)::
error extracting information from file provider

Full error log::
Error occurred on line: 63 (FileHandler)
java.lang.RuntimeException: Object should first be initialized (Cursor).
    at anywheresoftware.b4a.AbsObjectWrapper.getObject(AbsObjectWrapper.java:67)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:732)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:348)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:255)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:157)
    at anywheresoftware.b4a.debug.Debug.delegate(Debug.java:262)
    at b4a.example.filehandler._extractinformationfromuri(filehandler.java:413)
    at b4a.example.filehandler$ResumableSub_Load.resume(filehandler.java:203)
    at anywheresoftware.b4a.shell.DebugResumableSub$DelegatableResumableSub.resumeAsUserSub(DebugResumableSub.java:48)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:732)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:351)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:255)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:157)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:201)
    at anywheresoftware.b4a.shell.DebugResumableSub$DelegatableResumableSub.resume(DebugResumableSub.java:43)
    at anywheresoftware.b4a.BA.checkAndRunWaitForEvent(BA.java:275)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:150)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:201)
    at anywheresoftware.b4a.phone.Phone$ContentChooser$1.ResultArrived(Phone.java:906)
    at anywheresoftware.b4a.BA$4.run(BA.java:593)
    at anywheresoftware.b4a.BA.setActivityPaused(BA.java:467)
    at b4a.example.main$ResumeMessage.run(main.java:313)
    at android.os.Handler.handleCallback(Handler.java:959)
    at android.os.Handler.dispatchMessage(Handler.java:100)
    at android.os.Looper.loopOnce(Looper.java:257)
    at android.os.Looper.loop(Looper.java:342)
    at android.app.ActivityThread.main(ActivityThread.java:9634)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:619)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:929)

Any Idea on how to improve the example?
 

ivan.tellez

Active Member
Licensed User
Longtime User
Does it actually crash or this error is caught in the Catch block?
Right, it is caught in the Catch block.

Doing tests on other examples, looks like it needs the READ_EXTERNAL_STORAGE permission to open the file choosed using another app. I tried to implement CheckAndRequest but the dialog doesnt show and Result is allways false. Can you update the example to use READ_EXTERNAL_STORAGE ?
 
Top