Android Question List of Arrays or Array of Arrays

TheWind777

Active Member
Licensed User
Longtime User
I am trying to create, either, an two-dimensional string array, or a List of arrays.

I would like to load in 4 different sentences for 365 different days from a text file, then access them like:

Day(235,1) would equal the first sentence of the 235th day... Day(365, 3) would equal the 3rd sentence of the 365th day. (Day(365, 0) might equal the total number of sentences for that day... because maybe in the future they might be more than 4 sentences per day).

I have tried both methods.

I have tried declaring a list in the Global area, then populating it in a Sub.

I have tried declaring the list in the Global area and populating it in the global area.

I have tried declaring a two-dimensional array in the Global area and populating it in Sub.

I have even succeeded, if one were to count using Log(Day(365,3))

However, whenever I try an actually use that string or return it as a value, or even print it in a StringFunction message Box... it always gives me an error of java.lang.NullPointerException

I'm figuring that the problem has to do with the original definition being just a reference pointer to a string which isn't really there later.

What is the proper way of declaring (either a list which will be a list of string arrays) or a two-dimensional string array so I can fill them in either at the beginning and then access them later, or fill them in from a Sub later without getting that annoying "NullPointrException" error?

365 x 4 real strings need to be created, globally.

Then, in some fashion, either a List of Array pointers has to point to those strings.

And, after they have been declared... how does one access them?

When I was doing experiments using a list of arrays, I seemed to be setting-up the list of arrays properly... but I could then never access the arrays, and thus those string array items properly.

Sub Globals
'These global variables will be redeclared each time the activity is created.
'These variables can only be accessed from this module.

Dim ListOfArrays As List
Dim sf As StringFunctions
Dim TimingArray(5) As String
End Sub

Sub Activity_Create(FirstTime AsBoolean)

'Do not forget to load the layout file created with the visual designer. For example:
Activity.LoadLayout("main")


Dim z As Short
Dim sf As StringFunctions

ListOfArrays.Initialize ' (I've also tried putting this in the Globals area)

For z = 0 To 365

Dim TimingArray(5) As String

TimingArray(0) = "4"
TimingArray(1) = "A" & NumToStr(z)
TimingArray(2) = "B" & NumToStr(z)
TimingArray(3) = "This is a test of the emergency broadcast system" & NumToStr(z)
TimingArray(4) = "D" & NumToStr(z)
ListOfArrays.Add(TimingArray)
Next

' Creates a string pointer called GetArray?

Dim GetArray() AsString



' Points the GetArray string pointer to the 25th Array in the ListOfArrays List and accesses the 25th

GetArray = ListOfArrays.Get(25)
Log(GetArray(3)) ' And, it shows "This is a test of the emergency broadcast system25"

TheString = GetArray(3) ' Doesn't cause problem to assign it. Must be a string pointer.
sf.MB(TheString) 'Gives null pointer error any time I try actually using that value

End Sub


The same exact thing happened when I tried to create a two-dimensional array.

What's the right way of doing it?
 

TheWind777

Active Member
Licensed User
Longtime User
How many versions of b4a do you have installed? Do a clean project from the menu options and then recompile.

Only one version of b4a; the full version.

This java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.Boolean error comes up all the time. It seems to always be related to a comparison that evaluates to a boolean.

I have eliminated all references to both string libraries... but still am getting that exception.

It doesn't ever seem to be related to an actual fault with the variable being compared.

At the moment it is happening at If TheString = "" Then

It seems to be related to time. If I delay by showing a message box, for example, the error goes away. Take away the message box delay (even though it isn't doing anything different than being slowed-down by the message box) it crashes with that error at a Boolean if statement.

Hate when there's a hard-to-figure out problem. My problems are never easy ones, otherwise I would figure them out myself... ;)

I can't really upload the project, either, because it is half-in-a-broken state and I haven't yet verified that the timing.txt file is all proper and complete with data on every line as it should be.

Will add more error checks.

If you think of anything else, let me know.
 
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
Yes, that's it. The x is just an icon. Click that and resave, then recompile and see if it helps.

You are all so very helpful. Thank you.

I have passed all my broken bridges for the moment and everything is now working fine (until the next time). Heh.

I stopped using the String Functions. Was just using them as a crutch, anyways. I really had to rebuild my own subs for what I needed.

Anyways. Thanks so much.
 
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
Yes, that's it. The x is just an icon. Click that and resave, then recompile and see if it helps.

Completely different question... but do you know how to spawn-off a MsgBox() without the process you called it from waiting until the person closes it?

At the moment I'm loading a bunch of text into boxes, then calling the MsgBox() routine, and it doesn't go to that page (show the text) until they have clicked on OK.

I want the panel to refresh as the MsgBox is being dealt with.
 
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
You will have to write a Modeless MsgBox function to do this. The default MsgBox is Modal and pauses the code until it's removed.

I fixed the problem by moving the MsgBox function to the very end of the Subroutine.

I'll look up "modeless MsgBox. That sounds handy.

One more question before I go. ;)

I will need to have a completely modeless MsgBox... because I will be timing something (variable up to many hours) and when the time arrives, I need to open up a MsgBox which has been waiting (you might say). The people might have switched to one of four different layouts on one of four different panels by then.

First, what function would I use to set up a timed interrupt (so it wouldn't drain their battery), which can be set to come up by ticks, or the real time, etc. and trigger a Subroutine which brings up MsgBox?

I will be setting that timer to go-off x times per hour, or x times per day and it will have to call itself again once it has triggered (stopping after a certain time of day).

So, you set the timer, you tell it to go. Then you go about you business (possibly even running some other App as long as mine is still running in the background). Then, POP. They read the thing click OK. It goes away and resets for the next period of time
 
Upvote 0

margret

Well-Known Member
Licensed User
Longtime User
1.. Are your other 4 layout in other activities or just on a different layout that was loaded?

2..Set a timer like:
B4X:
Dim YourVar As Timer
YourVar.Initialize("YourVar", 1000) '1000 = 1 second
YourVar.Enabled = True 'or False
 
Sub YourVar_Tick
    'When you set YourVar.Enabled = True, it calls this sub at the interval you have set
    YourVar.Enabled = False
    Msgbox("The Timer Has Triggered", "NOTICE")
    'Reset the timer here if you need to
End Sub
 
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
1.. Are your other 4 layout in other activities or just on a different layout that was loaded?

2..Set a timer like:
B4X:
Dim YourVar As Timer
YourVar.Initialize("YourVar", 1000) '1000 = 1 second
YourVar.Enabled = True 'or False

Sub YourVar_Tick
    'When you set YourVar.Enabled = True, it calls this sub at the interval you have set
    YourVar.Enabled = False
    Msgbox("The Timer Has Triggered", "NOTICE")
    'Reset the timer here if you need to
End Sub

Yep, that's what I have, currently. However, Timer stops whenever a modal dialog is open... but even worse - it stop when the program is paused. I have to have the timer be able to not be stopped by anything. I will be getting rid of the modal problem (hopefully) by building a panel-based non-modal (do you know of any library-based non-modal dialog). But, even better do you know of any timer that can wake-up an App an bring it back to life when it triggers? I will be setting a timer to trigger one-time-per-hour, or every half-hour, or three times a day, or many times an hour. It has to be able to work whether they have run another app, or not (as long as my App is still there, and paused).
 
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
1.. Are your other 4 layout in other activities or just on a different layout that was loaded?

2..Set a timer like:
B4X:
Dim YourVar As Timer
YourVar.Initialize("YourVar", 1000) '1000 = 1 second
YourVar.Enabled = True 'or False

Sub YourVar_Tick
    'When you set YourVar.Enabled = True, it calls this sub at the interval you have set
    YourVar.Enabled = False
    Msgbox("The Timer Has Triggered", "NOTICE")
    'Reset the timer here if you need to
End Sub

No, I am loading four panels, then loading the panels into my activity. I only have visible turned-on on one panel at a time. To switch between them I use the Options menu (but could just as easily do it with a button). I can't see why I can't make a fifth panel and use it as a non-modal MsgBox. I'll just make it look like a MsgBox. I'll also be able to size it relative to how much text it is to display (sometimes it will be showing one line... sometimes many paragraphs).

pnlLayoutACIMWB.Initialize("")



Activity.AddView(pnlLayoutACIMWB,0,0,100%x,100%y)



pnlLayoutACIMWB.Top=0

pnlLayoutACIMWB.Left=0

pnlLayoutACIMWB.LoadLayout("left")

pnlLayoutACIMWB.Visible=True



' Set-up the ACIM Text panel using "acimtext" Layout



pnlLayoutACIM.Initialize("")



Activity.AddView(pnlLayoutACIM,0,0,100%x,100%y)

pnlLayoutACIM.Top=0

pnlLayoutACIM.Left=0

pnlLayoutACIM.LoadLayout("acimtext")

pnlLayoutACIM.Visible=False





' Set-up the Settings panel using "settings" Layout



pnlLayoutSettings.Initialize("")

Activity.AddView(pnlLayoutSettings,0,0,100%x,100%y)



pnlLayoutSettings.Top=0

pnlLayoutSettings.Left=0

pnlLayoutSettings.LoadLayout("settings")

pnlLayoutSettings.Visible=False





' Set-up the "About" panel using "about" Layout

pnlLayoutAbout.Initialize("")



Activity.AddView(pnlLayoutAbout,0,0,100%x,100%y)

pnlLayoutAbout.Top=0

pnlLayoutAbout.Left=0

pnlLayoutAbout.LoadLayout("about")

pnlLayoutAbout.Visible=False
 
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
That sounds like it should work just fine.:)

Yeah, that part has been working, nicely, for quite some time now.

It appears that I might be able to create a timer that remains active after the App has gone to Pause by declaring it in the Process Globals area?

When it triggers, will it resume the App and run the App, returning to the proper Subroutine?

Sub Timer1_tick

End Sub

Right now I am declaring the timer in Process Globals... but I am initializing it in Activities Sub.

Sub Process_Globals

Dim Timer1 As Timer

End Sub


Sub Activity_Create(FirstTime AsBoolean)
Timer1.Initialize("Timer1", 60000)
Timer1.Enabled = True
End Sub

I will have two timers... one longer-term 1 or 2 per-hour and a second that is a 5-minute 10-minute, etc. I will arbitrate between the two timers with flags showing whether the other timer is currently working, or not. They will both use the same dialog box, and the longer one will overpower the frequent one if they ever bump into each other. However, Timer will make a pitiful thing if they can't run other apps while they wait the hours for the timer to trigger.
 
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
I think you will need a littlemore than that. Look at this. I think this will help:

http://www.b4x.com/android/forum/threads/auto-starting-your-app.37723

I'll, first, create the two timers so they work outside the paused state. Make sure it works correctly when my MsgBox is up, or not... make sure it resumes properly after being paused... Then I imagine I can create some overlord function which can keep the time going in-between when the program is paused, and call the program to resume from the overlord. That will form the last part of the bridge, if I can succeed. But I won't have to be smarter than I currently am to make it work (minus that little while-it-is-paused-it-won't-work glitch).

I can imagine what the overlord would look like. It would just be a stay-resident version of the timer, probably running automatically using a modified version of what you just showed me, which then checks to see if my App is currently paused (I'm sure there's a flag for that, just got to know how to access it. Possibly something like "if [module name].main.paused = TRUE"

Then, if it is paused, have it store some public global variables which contain the timer details, then run the timer from the module and wait, catching the timer at the Overlord with a "sub OverlordTime_tick" subroutine. That routine would then trigger the App to resume. The normal resume would then take effect and that would already be working properly. The Overlord then would set it's own timer that would put itself to sleep and wake up every ten seconds, seeing whether the main App has gone paused again... if not, set the Overlord timer again, go to sleep another ten seconds... etc.
 
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
Yes, that's it. The x is just an icon. Click that and resave, then recompile and see if it helps.


I am still being haunted by that strange 'long can't be cast to boolean' error when it hits the If File.Exists(File.DirInternal,"Init.txt") line.

I just compiled it (after having deleted-out the init.txt file) and the debugger tried to start, then failed and disappeared. I got this error with no more details:

An error occurred:


(Line: 1472) If File.Exists(File.DirInternal,"Init.txt") Then
java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.Boolean

When I Immediately clicked on the play button to compile it again, with nothing else being done, ... no error. The App loads with no problem.

---------------


Line 1472 Is the "If File.Exists(File.DirInternal,"Init.txt") Then" line of ReadInitFile(), which reads-in the init.txt file.

I have gone through every Put and every .Get looking for some boolean value. I am only writing strings, only reading strings. Here are all the functions which pertain to the Init.txt file...

All parameters being sent to the map file are strings, all that are coming from the map file are strings.

When I delete the init.txt file, sometimes it seems to run just fine for a time. Once it starts to give me that error, it will keep giving me the error until I delete out the init.txt file.

Obviously, the problem seems to be the init.txt file. When I look at the contents of init.txt, it looks fine.


Next thing I need to do is make a project with just this code in it and see if I can recreate the error.

Maybe you'll see something that I don't, or be able to suggest something that might resolve the problem.

Remember that the same problem would appear when I tried the two String function libraries; and the same thing I was doing on my end which raised an error ran fine on your side...



ALL SUBROUTINES WHICH RELATE TO THE init.txt FILE:


Sub ReadInitFile(BlankString As String) As Map

' Read the Init.txt File and return the Map



Dim TheMapFile As Map


If File.Exists(File.DirInternal,"Init.txt") Then

TheMapFile = File.ReadMap(File.DirInternal, "Init.txt")

Return TheMapFile

Else

TheMapFile = CreateInitFile("")

Return TheMapFile

End If



Return TheMapFile

End Sub


Sub GetWBNumberAsText(BlankString As String) As String
Dim ReturnValue As String

ReturnValue = TheMapFile.Get("WBNumber")

Return ReturnValue
End
End Sub


Sub GetACIMNumberAsText(BlankString As String) As String
Dim ReturnValue As String

ReturnValue = TheMapFile.Get("ACIMNumber") ' returned As Map

Return ReturnValue

End Sub


Sub StoreWBNumberAsText(TheNumber As String) As Long

AddToInitFile("WBNumber", TheNumber)

End Sub


Sub StoreACIMNumberAsText(TheString As String) As Long
AddToInitFile("ACIMNumber", TheString)
End Sub


' Is only jumped-to from StoreACIMNumberAsText() and StoreWBNumberAsText()

Sub AddToInitFile(InitItemName As String, InitItemValue As String) As Long

' Write InitItemName with InitItemValue in Init.txt File

Dim TheMapFile As Map


TheMapFile = ReadInitFile("")

TheMapFile.Put(InitItemName, InitItemValue)


File.WriteMap(File.DirInternal,"Init.txt", TheMapFile)

End Sub


Sub GetWBLastLesson(BlankString As String) As String()

Dim TheMapFile As Map
Dim ReturnArray(2) As String



TheMapFile = ReadInitFile("")

ReturnArray(0) = TheMapFile.Get("LastLesson")

ReturnArray(1) = TheMapFile.Get("LastType")



Return ReturnArray

End Sub


Sub GetACIMLastChapter(BlankString As String) As String()

Dim TheMapFile As Map
Dim ReturnArray(3) As String



TheMapFile = ReadInitFile("")

ReturnArray(0) = TheMapFile.Get("LastChapter")

ReturnArray(1) = TheMapFile.Get("LastSection")

ReturnArray(2) = TheMapFile.Get("LastChapterType")



Return ReturnArray

End Sub


' This routine is jumping to function with two Strings
' Jumped to from EditTextWBNumber_EnterPressed
' But, this can't be the routine that crashes it, because you'd have to pressed the Enter Button
' Dim TheInputNumber As Short

' Dim TheCurrentType As String
' NumToStr() As String
' StoreWBLastLesson(NumToStr(TheInputNumber), TheCurrentType)

' This routine is jumping to function with two Strings
' Jumped to from GetWBText(Direction As Int) As Long
' Dim TheFileName As String
' LessonTxt from Globals

' StoreWBLastLesson(TheFileName, LessonTxt)

Sub StoreWBLastLesson(TheLesson As String, TheType As String) As Long

Dim TheMapFile As Map

TheMapFile = ReadInitFile("")

TheMapFile.Put("LastLesson", TheLesson)

TheMapFile.Put("LastType", TheType)


File.WriteMap(File.DirInternal,"Init.txt", TheMapFile)

End Sub


' Only jumped to from: Sub GetACIMText(Direction As Int) As Long
' Dim CurrentChapterNum As Short
' Dim CurrentChapterSection As Short
' ChapterTxt is String from Globals

' StoreACIMLastChapter(NumToStr(CurrentChapterNum), NumToStr(CurrentChapterSection), ChapterTxt)


Sub StoreACIMLastChapter(TheChapter As String, TheSection As String, TheType As String) As Long

Dim TheMapFile As Map



ReadInitFile("")

TheMapFile.Put("LastChapter", TheChapter)

TheMapFile.Put("LastSection", TheSection)

TheMapFile.Put("LastChapterType", TheType)


File.WriteMap(File.DirInternal,"Init.txt", TheMapFile)

End Sub


( From Globals:

Sub Globals
Dim LessonTxt, LastLessonText, LessonIntro, LessonTheme, ChapterIntro As String

LessonTxt = "0"
LessonIntro = "1"
LessonTheme = "2"
ChapterIntro = "0"
End Sub
)


Sub CreateInitFile(BlankString As String) As Map



Dim TheMapFile As Map


TheMapFile.Initialize

TheMapFile.Put("WBNumber", "1")

' Current Workbook Lesson Number

TheMapFile.Put("ACIMNumber", "1") 'Current Chapter Number

TheMapFile.Put("LastLesson", "1")

TheMapFile.Put("LastType", LessonTxt)

TheMapFile.Put("LastChapter", "1")
TheMapFile.Put("LastSection", ChapterIntro)
TheMapFile.Put("LastChapterType", ChapterTxt)

File.WriteMap(File.DirInternal,"Init.txt", TheMapFile)



Return TheMapFile

End Sub
 
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
The TXT file might preserve the formatting. Boy, this editor is horrible. I am a fast touch-typer and every other letter get lost.

After you post, it double-spaces everything. When you try editing stuff, a backspace turns into a carriage return. All tabs disappear. Frustrating.
 

Attachments

  • Init Subroutines.txt
    6.4 KB · Views: 305
Upvote 0

margret

Well-Known Member
Licensed User
Longtime User
Every file in the File.DirAssets folder should be lower case. Change this line: If File.Exists(File.DirInternal,"Init.txt") so it say "init.txt" not "Init.txt". That should help. Make sure all your files in the files folder are all lower case names. Also, make sure your code that looks for any file in Assets is looking for lower case as well.
 
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
Every file in the File.DirAssets folder should be lower case. Change this line: If File.Exists(File.DirInternal,"Init.txt") so it say "init.txt" not "Init.txt". That should help. Make sure all your files in the files folder are all lower case names. Also, make sure your code that looks for any file in Assets is looking for lower case as well.
Every file in the File.DirAssets folder should be lower case. Change this line: If File.Exists(File.DirInternal,"Init.txt") so it say "init.txt" not "Init.txt". That should help. Make sure all your files in the files folder are all lower case names. Also, make sure your code that looks for any file in Assets is looking for lower case as well.

Huh. why would it ever work, then? That would cause a problem with casting Boolean as Long?
 
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
Every file in the File.DirAssets folder should be lower case. Change this line: If File.Exists(File.DirInternal,"Init.txt") so it say "init.txt" not "Init.txt". That should help. Make sure all your files in the files folder are all lower case names. Also, make sure your code that looks for any file in Assets is looking for lower case as well.

Yeah, checked... all files are lower-case in my Files folder.
 
Upvote 0

TheWind777

Active Member
Licensed User
Longtime User
Every file in the File.DirAssets folder should be lower case. Change this line: If File.Exists(File.DirInternal,"Init.txt") so it say "init.txt" not "Init.txt". That should help. Make sure all your files in the files folder are all lower case names. Also, make sure your code that looks for any file in Assets is looking for lower case as well.

I knew that... but back when I began the program I didn't. That's a leftover from back when I was really stumbling (not to say I'm not still stumbling).

By the way, the DateTime Utility library is broken. I've downloaded it twice and both times it is a corrupted zip archive. Do you have a good archive of it, or check the one in the library?
 
Upvote 0
Top