Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot set text of a TextView inside the read Callback #307

Closed
lhtrevisan opened this issue Apr 22, 2020 · 5 comments
Closed

Cannot set text of a TextView inside the read Callback #307

lhtrevisan opened this issue Apr 22, 2020 · 5 comments

Comments

@lhtrevisan
Copy link

lhtrevisan commented Apr 22, 2020

Hi friends!
Calling myself newbie at Android is too much of a complyment for me, as I don't know Jack s*it about it, but I'm adventuring myself into developing a Self Service Beer Tap sistem using Kotlin language anyways.
After struggling a bit, I've managed to make the layout for the app and somewhat setting up the serial communication with an arduino board using this UsbSerial library.
At this point I was supposed to code serial reading at the app, but I don't know how to do it.
Serial communication is set up in the code exactly as the tutorial made by "Apps in the sky":
Part 1: https://www.youtube.com/watch?v=QHa6HWTmQFs
Part 2: https://www.youtube.com/watch?v=ICjjG1VsZmw&t

The messages/commands that the android will receive will have the following format:
Ixxxxxxx> Vxxxxxx> <xxxxxx>
The first character will tell the Android what is the information being passed:
I = ID of the rfid card read by the Arduino
V = Volume measured
< = General Command or info ,like , <POURING_ENDED>, <AUTHENTICATION_FAILURE>

And the stopbit for every data line or command is ">".

Could someone help me on implementing this on the code?

Just in case someone gives up reading the header: I'm using Kotlin.

Almost forgot to mention: the app template is ItemList/Detail, but the communication will be done all in the main application(ItemListActivity).

And sorry for any bad english(I'm brazilian).

EDIT: I read #37 but couldn't translate it to my code because it's Java and the code wouldnt' use Stopbits as I intend to use.

@lhtrevisan
Copy link
Author

lhtrevisan commented Apr 24, 2020

Ok... I got further on it by myself but I'm still facing some problems...
Here is what I did so far:

1st: I've added a read line to the serial setup, pointing to a callback:

private val broadcastReceiver = object : BroadcastReceiver(){
    override fun onReceive(context: Context?, intent: Intent?) {
        [...]
        m_serial!!.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF)
        m_serial!!.read(mCallback)
        [...]

2nd: Then I wrote the callback to get the data from Serial:

private val mCallback = UsbSerialInterface.UsbReadCallback {
    MyVariables.receivedText = String(it, Charsets.UTF_8)
    understandSerial(MyVariables.receivedText)
}

3rd: I wrote a function to understand the data received trough the callback:

fun understandSerial(msg: String){
    val byteArray = msg.toByteArray(Charsets.UTF_8)
    var prefix : Char = '0'
    var readingMSG: Boolean = false
    var messageRead: String = ""
    for ((index, bytes) in byteArray.withIndex()){
        if (readingMSG){
            if (bytes == '>'.toByte()){
                readingMSG = false
                handleCommand(prefix, messageRead)  //Handle command/information received here
            } else {
                messageRead += bytes.toString()
                //
            }
        } else {
            if (bytes == 'I'.toByte() || bytes == 'V'.toByte() || bytes == '<'.toByte()) {
                prefix = bytes.toChar()
                messageRead = ""
                readingMSG = true
            }
        }
    }
}

4th: Every command/information received will then be handled separately by another function:

fun handleCommand(prefix: Char, msg: String){
    if (prefix == 'I'){
        // Actions for ID Received trough serial
    } else if (prefix == 'V'){
        // Show/update current poured volume on screen
    } else if (prefix == '<'){
        //Actions for commands received:
        if (msg == "INCOMPATIBLE_TOKEN"){

        } else if (msg == "DOC_AUTH_FAIL"){

        } else if (msg == "DOC_READ_FAIL"){

        } else if (msg == "ABORT_COMMAND"){

        } else if (msg == "ABORT_COMMAND2"){

        } else if (msg == "WDOC"){

        } else if (msg == "UNDEF_DATA"){

        } else if (msg == "MAXVOL_END_SERVICE"){

        } else if (msg == "IDLE_END_SERVICE"){

        } else {
            //UNKNOWN COMMAND RECEIVED
        }
    }
}

Everything seems to work fine like this.

Then I tried to show/update the volume poured, measured by the Arduino:

     } else if (prefix == 'V'){
        tvPouredCost.text = msg
    }
  • Volume is received in this format: "Vxxxx>", and at this point of the code, the variable data is supposed to be "xxxx", without the prefix and stopbit;

Right after the RFID card is read, the app stops working.
By the way, the TextView element is declared and initialized right at "onCreate":

private var tvPouredCost: TextView? = null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    context = this
    setContentView(R.layout.activity_item_list)

    tvPouredCost = findViewById<View>(R.id.tvValor) as TextView
    //tvPouredCost.text = "0mL"

    m_usbManager = getSystemService(Context.USB_SERVICE) as UsbManager
    val filter = IntentFilter()
    filter.addAction(ACTION_USB_PERMISSION)
    filter.addAction(UsbManager.ACTION_USB_ACCESSORY_ATTACHED)
    filter.addAction((UsbManager.ACTION_USB_DEVICE_ATTACHED))
    registerReceiver(broadcastReceiver, filter)
    startUsbConnecting()
  • If I uncomment the text setting line right after the initialization, it sets the text correctly.

I tried putting a breakpoint inside the callback and running debug, but I was unable to identify the root of the problem.
What may be happening here?

@lhtrevisan lhtrevisan changed the title Help implementing reading code Cannot set text of a TextView inside the read Callback Apr 24, 2020
@sivaprashanth
Copy link

i can recommend you to add text updates in a separate thread.

@lhtrevisan
Copy link
Author

I tought it'd be better if I posted the update in the same thread because, if someone have the same issue I had, they could benefit from de direct answer that I implemented...
Of course I can open another thread for the new problem, but what if the problem is related to the way I made the code? If that's the case, I think it should be solved here.

@sivaprashanth
Copy link

i am sorry i meant to run textupdates creating a user thread or a timer in the program to update the textview:

private void startTextupdateThread() {
Thread th = new Thread(new Runnable() {

    public void run() {
                       
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                   tvPouredCost.setText();
                }
            });
            try {
                Thread.sleep(1000);
            } 
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
});
th.start();

}

i am not sure this will fix, but u can try as you said it was fine when you commented that line out.

@lhtrevisan
Copy link
Author

It Worked!
I created a new thread:

private fun startTextUpdateThread(){
    val th = Thread(Runnable {
        // try to touch View of UI thread
        this@ItemListActivity.runOnUiThread(java.lang.Runnable {
            this.tvCreds.text = "R$" + MyVariables.actualCredits
            this.tvValor.text = "R$" + MyVariables.actualPouredCost
            this.tvVolume.text = MyVariables.actualPouredVol + "mL"
        })
    }).start()
}

And passed reference to it inside the handleCommand function:

     else if (prefix == 'V'){
        MyVariables.actualPouredVol = msg
        startTextUpdateThread()
        // Show/update current poured volume on screen
    } 
  • Variables are "MyVariables._______" because I put them inside an object, to have access easily everywhere

MyVariables object looks like this:

object MyVariables{
    var tapNum: Int = 1
    var receivedText: String = ""
    var CommandReceived: String = ""
    var actualPouredCost: String = ""
    var actualPouredVol: String = ""
    var actualCredits: String = ""
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants