Android Question [SOLVED] Problem adding menu item

max123

Well-Known Member
Licensed User
Longtime User
Hi all,

I've this piece of code:
B4X:
    Dim job1 As HttpJob
    job1.Initialize("Job1", Me)
    job1.Download(URL)
    Wait For JobDone (job As HttpJob)

    If job.Success = True Then
        WANIP = "192.168.0.1" 'ExtractIP(job.GetString)
        Log ("Adding menu item: " & "WAN IP: " & WANIP)
        'Activity.AddMenuItem2("WAN IP: " & WANIP,"WIPAddress", Null)
        Activity.AddMenuItem3("WAN IP: " & WANIP, "WIPAddress", Null, True)
    Else
        Log("Job failed: " & job.ErrorMessage)
        WANIP = "No WAN Internet connection"
        Log ("Adding menu item: " & "WAN IP: " & WANIP)
        Activity.AddMenuItem3("WAN IP: No Internet", "WIPAddress", Null, True)
    End If
 
    job.Release

This code do an internet request to http://icanhazip.com to get a public IP address.
The request always return the IP address without problems, but after I get it I want to add it to a menu item so the user can see and click on it.

On this code always Job is success, the log is correctly called but it refuses to add the menu Item.
As you can see I even pass a fake ip string to test with, but nothing change.

I have tried to add:
B4X:
Sleep(0)
DoEvents
Activity.Invalidate
but nothing change, I cannot see the menu item.

This code is in Activity_Create sub.

Any suggestion to get it working ?
 
Last edited:

jahswant

Well-Known Member
Licensed User
Longtime User
Use b4xPages and menuitem ! I don’t think it’s possible to add menu items at runtime with activities.
 
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
Thanks for reply,

I want avoid using B4XPages on this project, I add other menu items and that works.
I always used menu items on activities on all my apps.

If I add it without Job and Wait For it works as expected.
 
Last edited:
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
Please help
 
Upvote 0

GMan

Well-Known Member
Licensed User
Longtime User
This is the at least 3rd post from you i read about that you dont want to use B4XPages...is there ANY reason for that ?
 
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
Hi @GMan, the reason is that I have an already working app I wrote in a long time and I don't want convert it to B4XPages. Erel said, it is good to use in new projects, not convenient to convert existing expecially big projects.

In new projects I use B4XPages but depends on project, for simple projects I prefer not to use B4XPages, in many others I use it.

Some time ago I converted one my existing big app to get working it in background some tasks, but I had any sort of problems..... convert it was not too difficult, required just some days, but my app now have strange issues I do not know..... but this is another story, I will eventually discuss it on another dedicated thread.

The main reason is that I don't want convert my existing app that use Activity.

Please did you know because this doed not work ?

Without the web request it succesfully add the menu item, so should be something related to Wait For in Activity Create.

Thanks for your interest ?
 
Last edited:
Upvote 0

GMan

Well-Known Member
Licensed User
Longtime User
I had the same problem some weeks ago: an old app wouldnt run any more.
I spent a lot of time in searching and recoding the parts of the code with issues, but decided then to jump into the old water and made that app new.

Of course its a lot of work and time, but...better invest time in learning the "new way" as wasting time in converting old parts into b4xpages.

Just my 5 cents..l
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
If you look at the Intellisense forAddMenuItem and AddMenuItem2 it says it should only be called in Activity_Create. Strangely it is not in the Intellisense for AddMenuItem3, but it does say 'similar to MenuItem2'. The bottom line is that you can't dynamically change the menu items.
 
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
Maybe I didn't explain myself well, @GMan, it's not a problem of wasting time learning a new method. I did this, the result was that it took me some time to understand how it works, it took me days to convert my app.... I wanted to try because it has so many things running in the background.

Of all this the result is that it took me some time and the app works worse than before and being a complex app it is very difficult to understand where the problem lies.
 
Last edited:
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
If you look at the Intellisense forAddMenuItem and AddMenuItem2 it says it should only be called in Activity_Create. Strangely it is not in the Intellisense for AddMenuItem3, but it does say 'similar to MenuItem2'. The bottom line is that you can't dynamically change the menu items.
Hi @agraham thanks,

I use it in Activity_Create as I wrote in the main post.

The problem here may is that web request take some milliseconds and I add the menu item after that ?

But the log before I add the menu item, show the correct ip address from web request, and all is inside Activity_Create sub.

This worked sometime, but randomly, may depends on web request time.
 
Last edited:
Upvote 0

agraham

Expert
Licensed User
Longtime User
The WaitFor will immediately exit Activity_Create and run Activity_Resume which will then return to the message loop to await the JobDone event. So your WaitFor effectively terminates Activity_Create so you can't add any more menu items after the WaitFor.
 
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
The WaitFor will immediately exit Activity_Create and run Activity_Resume which will then return to the message loop to await the JobDone event. So your WaitFor effectively terminates Activity_Create so you can't add any more menu items after the WaitFor.
Really clear explanation, thanks. ?
And there is no other solution to this anyway ?
 
Upvote 0

toby

Well-Known Member
Licensed User
Longtime User
One solution is to Add menu item before the Wait For and check IP address when user taps the item.

B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Private xui As XUI
    Dim WANIP0 As String= "No WAN Internet connection"
    Dim WANIP As String=""
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("Layout")
   
    Activity.AddMenuItem3("WAN IP: " & WANIP, "WIPAddress", Null, True)
   
    Dim url As String="https://www.google.com"
    Dim job1 As HttpJob
    job1.Initialize("Job1", Me)
    job1.Download(url)
    Wait For JobDone (job As HttpJob)

    If job.Success = True Then
        WANIP = "192.168.0.1" 'ExtractIP(job.GetString)
    Else
        Log("Job failed: " & job.ErrorMessage)
        WANIP =WANIP0
    End If
 
    job.Release
End Sub


Sub WIPAddress_Click
Log("enter WIPAddress_click")
    If WANIP=WANIP0 Then
        ToastMessageShow("no internet", True)
    Else
        ToastMessageShow("WAN IP: " & WANIP, True)  
    End If
End Sub
 
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
One solution is to Add menu item before the Wait For and check IP address when user taps the item.

B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Private xui As XUI
    Dim WANIP0 As String= "No WAN Internet connection"
    Dim WANIP As String=""
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("Layout")
 
    Activity.AddMenuItem3("WAN IP: " & WANIP, "WIPAddress", Null, True)
 
    Dim url As String="https://www.google.com"
    Dim job1 As HttpJob
    job1.Initialize("Job1", Me)
    job1.Download(url)
    Wait For JobDone (job As HttpJob)

    If job.Success = True Then
        WANIP = "192.168.0.1" 'ExtractIP(job.GetString)
    Else
        Log("Job failed: " & job.ErrorMessage)
        WANIP =WANIP0
    End If
 
    job.Release
End Sub


Sub WIPAddress_Click
Log("enter WIPAddress_click")
    If WANIP=WANIP0 Then
        ToastMessageShow("no internet", True)
    Else
        ToastMessageShow("WAN IP: " & WANIP, True)
    End If
End Sub
Not bad as idea, thanks.

May using this:
B4X:
Dim WANIP0 As String = "Please tap here to get WAN IP"
instead of this:
B4X:
Dim WANIP0 As String = "No WAN Internet connection"
.... so the user know to tap it.

I will try that, thanks.
 
Last edited:
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
You cant believe it i see ? ;)
@GMan You always have to find solutions ;) even when you think they don't exist.

@toby has shown that by finding a compromise, things can be done.
Many thanks for this, I will try your idea, it did not occur to me that I can use just a ToastMessageBox to show IP without necessary show it in the menu.
 
Last edited:
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
One solution is to Add menu item before the Wait For and check IP address when user taps the item.

B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Private xui As XUI
    Dim WANIP0 As String= "No WAN Internet connection"
    Dim WANIP As String=""
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("Layout")
 
    Activity.AddMenuItem3("WAN IP: " & WANIP, "WIPAddress", Null, True)
 
    Dim url As String="https://www.google.com"
    Dim job1 As HttpJob
    job1.Initialize("Job1", Me)
    job1.Download(url)
    Wait For JobDone (job As HttpJob)

    If job.Success = True Then
        WANIP = "192.168.0.1" 'ExtractIP(job.GetString)
    Else
        Log("Job failed: " & job.ErrorMessage)
        WANIP =WANIP0
    End If
 
    job.Release
End Sub


Sub WIPAddress_Click
Log("enter WIPAddress_click")
    If WANIP=WANIP0 Then
        ToastMessageShow("no internet", True)
    Else
        ToastMessageShow("WAN IP: " & WANIP, True)
    End If
End Sub
May the right way is to just check for public ip address when menu item is clicked.

My app now just check it when starts...
If there is no WiFi connection here, after WiFi connection is estabilished, the user should close the app and restart again.

Just check if the user tap on the menu item, so any time really need it to use Internet connection instead of local. And show a toast after successful IP address request, this is a better approach I think.

What do you think on this ?
 
Last edited:
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
The problem was solved.

Yes the best approach seem to put a default menu item in Activity_Create:
B4X:
Activity.AddMenuItem3("WAN IP:  Please Tap Here" & WANIP, "WIPAddress", Null, True)

then in the menu click event check if there is a connection, if yes do a request, get IP address and show it with a MessageBox or a Toast. The request here take just some milliseconds, just the ping time.

Extract the public IP address from a web page is really simple, the page only contain it so job.GetString is the IP.

So this is a really simple way to get network Public IP Address on request, just when user click a menu item or a button. If there is no connection a message will appear and the function just return.

I hope this help some peoples that search a simple way to do it.

Here my menu item event.
Thanks to all peoples that helped.
B4X:
Sub WIPAddress_Click
    Activity.CloseMenu
 
    ' Next I will convert Msgbox to MsgboxAsync ...
 
    If ssocket.GetMyIP = "127.0.0.1" Then
        Msgbox("No Internet connection." & CRLF  & CRLF & _
                "Please connect to Internet and try again.","You are offline? ")
        WANIP = "No Internet connection"
        Return
    End If
 
    Dim job1 As HttpJob
    job1.Initialize("Job1", Me)
    job1.Download(URL)  ' "http://icanhazip.com"
    Wait For JobDone (job As HttpJob)

    If job.Success = True Then
        Dim tIp As String = ExtractIP(job.GetString)  ' I use regex to match the pattern just to validate ip pattern, but job.GetString already only contain the public IP address
        If IsValidIp(tIp) Then
            WANIP = tIp
            Msgbox("This is the WAN IP Address of this device to connect over Internet." & CRLF & CRLF & _
               "Change it on Arduino sketch to connect to this app inside or outside local network." & CRLF & CRLF & _
                 "Remember to create Port Forwarding on your router." & CRLF & CRLF & _
                 "Now ESP8266/ESP32/RP2040 or Arduino + Wifi Shield are able to draw and interact over Internet to VirtualDisplay app." & CRLF & CRLF & _
                 "Have fun !!!","Wide Area Network IP Address:  " & WANIP)
        Else
            Msgbox("Request to get WAN IP Address returned wrong result. Try again ...","Wrong Wide Area Network IP Address")
        End If
    Else
        Log("Public IP Address Job failed: " & job.ErrorMessage)
        WANIP = "No Internet connection"
        Msgbox("Request to get WAN IP Address failed. Try again ...", "Server do not respond")
    End If
 
    job.Release
End Sub

Sub IsValidIp(mIP As String) As Boolean  '  Validate IP Address
    Dim m As Matcher
    m = Regex.Matcher("^(\d+)\.(\d+)\.(\d+)\.(\d+)$", mIP)
    If m.Find = False Then Return False
    For i = 1 To 4
        If m.Group(i) > 255 Or m.Group(i) < 0 Then Return False
    Next
    Return True
End Sub
 

Attachments

  • Screenshot_1683036491.png
    Screenshot_1683036491.png
    50.9 KB · Views: 116
  • Screenshot_1683036510.png
    Screenshot_1683036510.png
    45.2 KB · Views: 132
Last edited:
Upvote 0
Top