Android Question [Solved]Blank activity page under some conditions

DataMiser

Member
Licensed User
I have been testing my app and I see that in one case one of my screens does not draw the views under some conditions.
All looks fine under normal conditions but in testing I ran across a case where I just get a blank page.

The activity starts, sets some text on a couple of labels then attempts an IP connection back to the PC.
Once connected if begins to send a data stream to the pc. That part is working well.

In the receiver code on the pc I added a beak point to see what would happen should something odd happen on the pc side or connection issues.
So the device connects, sends the first record and is waiting for a response from the PC. At this time I am seeing a blank screen on the device. None of the views have been drawn nor any text displayed.

So I am wondering is there a method I can use to get it to update the display before going into the connect code and/or get it to update during the loop that sends the data stream?

Also is there a way to set a timeout on the IPReader.Readline method it seems the program is currently just going to sit there showing a blank page forever waiting for a response.
If I resume the pc code then the transfer completes and the screen displays. If I close the PC program I get an error reported on the device due to loss of connection as expected.

I need to be able to handle a case where the pc does not respond in a reasonable time or the pc responds with an unexpected result that could cause the device to appear to hang as when a break point was hit on the pc.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
You should never use TextReader with a network connection.

Use AsyncStreams and nothing will be blocked.

I recommend you to switch to B4XPages and it will make many things much simpler. This is especially true in apps that deal with communication.
 
Upvote 0

DataMiser

Member
Licensed User
Ok, but the text reader does not even come into play until after the connection is made successfully and some data is sent.
Why are the views not being displayed?
Should I assume that there is no way to set a time out on the readline method?
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Why are the views not being displayed?
You haven't posted any code so we can't really say.

I can say that you should never have code that blocks the main thread and this means never use TextReader with a network connection. You will not find any example based on TextReader since 2011.

Should I assume that there is no way to set a time out on the readline method?
Once the main thread is blocked your program is frozen and will then be killed. No point in adding timers or anything as there is a simple and good solution: AsyncStreams.
 
Upvote 0

DataMiser

Member
Licensed User
B4X:
Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    If FirstTime Then
        'IP.Initialize("TCP")
    End If
    IP.Initialize("TCP")
    Activity.LoadLayout("scrUpload")
    ModCommon.ResetUserFontScale(Activity)
    lblresult.Text=""
    btnOK.Visible=False
    Activity.RequestFocus
    lblStatus.Text="Connecting"           
    IP.Connect(Main.server,Main.port,5000)
End Sub
Sub TCP_Connected(Successful As Boolean)
    If Successful = False Then
        lblStatus.Text="Connection Failed"
        lblresult.Text="Insure that Droid Server is running on PC" & Chr(10) & "Check Settings in app"        
        btnOK.visible=True
        Return        
    End If
    UploadData
    Return
End Sub

In the upload routine I have a bit of processing code
for the i/o I am using
B4X:
IPReader.Initialize(IP.InputStream)
 IPWriter.Initialize(IP.OutputStream)

I also have some code in that upload routine to update some test on the screen and a progress bar but like I said I am getting a blank page on the device, None of the views have been draw before the connection attempt is made, none are drawn when the connection is successful and none appear to be drawn in the upload routine.
 
Upvote 0

DataMiser

Member
Licensed User
Is there anything I can do in that activity_create that will have it insure the screen is displayed before more code is executed?

I will look at the details on the async streams and incorporate those in the future, for now this app is working fine and that blank page is not likely to ever appear to the end user. I just would like to make sure that it does not. The connection and the transfer are both very fast and the errors they are most likely to get would be PC program not running, settings on the device pointed to the wrong IP or port or they do not have a network connection back to the PC. All of these things do display the proper messages on the screen for the user.
 
Upvote 0

DataMiser

Member
Licensed User
Looks like I managed to get it to work by moving around a couple of lines of code and inserting a couple of sleep statements.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
I also have some code in that upload routine to update some test on the screen and a progress bar but like I said I am getting a blank page on the device, None of the views have been draw before the connection attempt is made, none are drawn when the connection is successful and none appear to be drawn in the upload routine.
I can only repeat my same statement: as long as you are using TextReader / TextWriter with a network stream, your app will be unresponsive and unreliable.
Adding Sleep will not really help. The layout will appear but it will become unresponsive afterward.

There are many other mistakes in this short code. Worth learning the example referred above.
 
Upvote 0

DataMiser

Member
Licensed User
Thanks, I'll take a look and see what I can do with it.

I had not used b4a for a while. Most of my work is in Visual Studio either VB or C#. I bought b4a a few years ago and created that code to send the stream from one of the examples that were included back then then adapted it into the new project I was working on.

The issue for me at this point is that the program is done and working well, I would gladly change it if there is a problem but don't really want to rewrite it if I do not need to.
 
Upvote 0

DataMiser

Member
Licensed User
So I had a look at the example linked above. It only appears to have the one page and is created dynamically.
Does this async code have to go into the mainb4x page or can it go into a different activity?
If it does have to go into the main page can it be called from and interact with a different activity?

I notice that several of the vars are defined under class globals but that doesn't exist under other activities.

So I am not sure how I would start trying to add this into my project which does have a separate activity to handle the upload to the server.
 
Upvote 0

DataMiser

Member
Licensed User
Ok so I had a bit of a go with it added the asyncstreamstext to the example and was able to send data my server picked up and processed.
I have added some of the code from the project to my upload activity and have it connecting to my server and proper display.

Now I just have to figure out how to break that upload routine into working with the text received event. Currently it is reading data from a file line by line and sending it one line at a time to the server, waiting for a response then on to the next line and repeat. I am thinking that will need to be broken up into more than one routine to work in async mode.
 
Upvote 0

DataMiser

Member
Licensed User
Upvote 0

DataMiser

Member
Licensed User
Here is a bit of code I am using now, just wondering if there is any potential problems with the way this is coded that may jump out and bite me later.
B4X:
Sub SendNextLine()
    Log("Send Next Line")
    Dim dRecord As String
    If DataReader.Ready Then
        dRecord=DataReader.ReadLine
        If dRecord.Length>0 Then
            fProcessed=fProcessed+dRecord.Length
            ProgressBar1.Progress=Round(fProcessed/fTotal*100)
            ast.Write("R1," & dRecord & Chr(10))
        Else
            SendNextLine
        End If
    Else
        lblStatus.text="Upload Complete"
        lblresult.Text=(IntGood) & " good Records" & Chr(10) & (intBad) & " Bad Records"
        btnOK.Visible=True
        Log("no more data to send?")
        DataReader.close
    End If
End Sub

When an upload is called for another routine initializes the TextReader which will be reading from a local data file, sets a few vars then calls this routine.
When new text comes in from the server the routine above is called again.

The main thing I am wondering about is would there be any issue with that one line in the else condition which calls this routine again. Normally there are no blank lines in the data so it will likely never execute but I like to make sure that case in handled just in case an extra line feed finds its way into the file.
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
As it is a recursive call I don't see how conditions can change when it re-enters itself - that looks like a potential infinite loop to me if it ever gets triggered. I assume this is all running on the main thread so if it loops it will never get back to the message queue to process further events.
 
Upvote 0

DataMiser

Member
Licensed User
As it is a recursive call I don't see how conditions can change when it re-enters itself - that looks like a potential infinite loop to me if it ever gets triggered. I assume this is all running on the main thread so if it loops it will never get back to the message queue to process further events.
The thought is that if it does call itself then it should read the next line from the file so it should be working with different data or it should be at the end of the file.
Of course that is an assumption on my part but I would think that would be the result given that the textreader pointer should have moved to the next line after it was called early in the routine.
 
Upvote 0

DataMiser

Member
Licensed User
Well the datareader is actually a text reader that is reading within that routine from an open file so yes I would expect the conditions to change when it gets called again.
That said I am thinking that even it that is the case if by some remote chance there were to be multiple blank lines in a row it could potentially go several levels deep into the recursion and I do not like the thought of that so I found a different way to handle it without using recursion.
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
Well the datareader is actually a text reader that is reading within that routine from an open file
What if the empty line is at the end of the file and DataReader.Ready can never be True again?

I never like recursion - it always has the potential for infinite looping and is hardly ever necessary. Any recursive algorithm can always be expressed in a non-recursive form. The OCCAM language expressly disallowed recursion for these reasons. Personally I find recursion non-intuitive and in over fifty years of writing software the only time I find it convenient is for traversing tree structures. But then I'm probably expressing my own particular bias. Your, no doubt younger, brain may be wired differently. :)
 
Upvote 0

DataMiser

Member
Licensed User
Yep I do not like it either and rarely use it, never used it before in B4A so I had my doubts as to if it was a good idea. I changed it to return false when the line was blank and have the caller call it again to get the next line. I feel much more comfortable with that.
 
Upvote 0
Top