Question

My application gets data every 80 milliseconds (I asked my boss today and he said 80 ms is okay, but perfect would be 2ms - 20ms, so even faster than I thought). I need to work with the messages that are incoming, so I tried to handle them with if clauses and every time the if clause is true there is a new text set in a TextView

like that:

if (data.equalsIgnoreCase(test)) {
    TextView tv = (TextView) findViewById(R.id.textview);
    tv.setText(" 30 % ");
}

The problem is, that the data are incoming that fast and the if clauses seem not "fast" enough to handle it.

the TextView only changes when I stop the transmission of messages, then after a short "waiting" the TextViewchanges.

Is there something to make it more "Realtime" ?

I didn't find something helpful via google and my programming skills are very weak only to prevent more downvotes

EDIT:

I now found out, that I have to check 768 different values (all hexcodes). So there would be 768 if-statements. That would definetly break down the speed.

Problem is, I cant "wait" to do first the if-statement and then get the next message.

The messages just flow in.

I just updated my code and use now ProgressBar instead of a TextView

if (data.equalsIgnoreCase(TEST)){
    mProgressBar.setProgress(0);
}

EDIT2: Added Thread code

class RxThread extends Thread { 
    private static final String TEST =  "0 0 0 0 0 40 0 0 ";
private static final String TEST2 = "0 1 0 0 0 41 0 0 ";
private static final String TEST3 = "2 bb 0 0 2 fb 0 0 ";
private static final String TEST4 = "2 bd 0 0 2 fd 0 0 ";
private static final String TEST5 = "2 be 0 0 2 fe 0 0 ";

Handler myHandler = new Handler();

final Runnable r = new Runnable() {
    public void run() {

        demoRxMsg = new MessageStructure();

        while (rxChannel.receiveMessage(demoRxMsg) == ReturnCode.SUCCESS) {

            String data = "";
            String format = "";

            rxChannel.receiveMessage(demoRxMsg);

            if (demoRxMsg.frameFormat == API_ADK.STANDARD_FRAME) {
                format = "SFF";
            } else {
                format = "EFF";
            }
            for (byte i = 0; i < demoRxMsg.dataLength; i++) {
                data = data + Integer.toHexString(demoRxMsg.data[i]) + " ";
            }

            if (data.equalsIgnoreCase(TEST)){
                mProgressBar.setProgress(0);
            } else if (data.equalsIgnoreCase(TEST2)) {
                mProgressBar.setProgress(1);
            } else if (data.equalsIgnoreCase(TEST3)) {
                mProgressBar.setProgress(94);
            } else if (data.equalsIgnoreCase(TEST4)) {
                mProgressBar.setProgress(95);
            } else if (data.equalsIgnoreCase(TEST5)) {
                mProgressBar.setProgress(96);
            }

            }
        }
    }   
};

public void run() {
    while (true) {
        try {
            Thread.sleep(60);
            myHandler.post(r);
        } catch (InterruptedException e) {
            break;
        }
    }
}

How to make it perform better?

EDIT 3:

For better explanation how fast it has to be:

At the moment I'm receiving every 80 millisecond a message in hex format. The message object has 5 items: frame format, data format, data length, message ID and data. In perfect circumstances I get one every 2-20 ms.

There are 768 different messages I have to differentiate. those messages are devided by 200 (to get 0.5% steps).

What I want is a ProgressBar that changes and runs fluently as the hexcodes "rain" in and the percentage status changes.

One problem is, that I have no influence on how fast the messages are received. Its always the same speed. Is it even possible to process the data that fast?

Was it helpful?

Solution

While I am not certain that this is the primary problem, I do find quite a bit of inefficiency in your code:

  1. you are creating a lot of transient objects with this

        for (byte i = 0; i < demoRxMsg.dataLength; i++) {
            data = data + Integer.toHexString(demoRxMsg.data[i]) + " ";
        }
    

    For each byte you are creating at least two objects: one StringBuilder and one String object (ref here). If you want to get a String, at least make it like below:

        StringBuilder sb=new StringBuilder();
        for (byte i = 0; i < demoRxMsg.dataLength; i++) {
            sb.append(demoRxMsg.data[i]);
        }
        data=sb.toString();
    
  2. Instead of comparing strings, it'll be much faster to compare raw bytes, this way you can skip any object creation altogether.

  3. I assuming between the first and last few blocks of data, there are quite a bit of data in between, but in your current implementation those data that do not affect UI will still be checked on the UI thread, instead only run mProgressBar.setProgress(progress); when you have determined that UI needs to be updated. Untested code:

    class RxThread extends Thread {
    private static final String TEST = "0 0 0 0 0 40 0 0 ";
    private static final String TEST2 = "0 1 0 0 0 41 0 0 ";
    private static final String TEST3 = "2 bb 0 0 2 fb 0 0 ";
    private static final String TEST4 = "2 bd 0 0 2 fd 0 0 ";
    private static final String TEST5 = "2 be 0 0 2 fe 0 0 ";
    
    Handler myHandler = new Handler();
    
    public void run() {
    while (true) {
        try {
            Thread.sleep(60);
    
            demoRxMsg = new MessageStructure();
    
            int progress = -1;
            while (rxChannel.receiveMessage(demoRxMsg) == ReturnCode.SUCCESS) {
    
                String data = "";
                String format = "";
    
                rxChannel.receiveMessage(demoRxMsg);
    
                if (demoRxMsg.frameFormat == API_ADK.STANDARD_FRAME) {
                    format = "SFF";
                } else {
                    format = "EFF";
                }
                for (byte i = 0; i < demoRxMsg.dataLength; i++) {
                    data = data + Integer.toHexString(demoRxMsg.data[i])
                            + " ";
                }
    
                if (data.equalsIgnoreCase(TEST)) {
                    progress = 0;
                } else if (data.equalsIgnoreCase(TEST2)) {
                    progress = 1;
                } else if (data.equalsIgnoreCase(TEST3)) {
                    progress = 94;
                } else if (data.equalsIgnoreCase(TEST4)) {
                    progress = 95;
                } else if (data.equalsIgnoreCase(TEST5)) {
                    progress = 96;
                }
            }
            if (progress != -1) {
                final int newProgress = progress;
    
                myHandler.post(new Runnable() {
                    public void run() {
                        mProgressBar.setProgress(newProgress);
                    }
                });
            }
        } catch (InterruptedException e) {
            break;
        }
    }
    

    } }

OTHER TIPS

Well in your special case there is indeed a possibility to optimize. findViewById() is a very expensive operation and you should try caching to speed up the code you have shown above. Read up on the holder pattern and then implement it somewhat like this:

private TextView tv;

[...]

if (data.equalsIgnoreCase(test)) {
    if (tv == null) {
        tv = (TextView) findViewById(R.id.textview);
    }
    tv.setText(" 30 % ");
}

BUT! having said that this will probably not be enough to have the effect you desire in your application. 80ms is very very very fast and Android tends to block the UI-thread for good if there is heavy work going on

So you will have to think about threading and you will have to redesign a bit probably.

My first idea would be to have the input queue running on a separate thread and only invoking a TextViewchange when you determine that there is somewhat of a pause in between. You could then update the view, knowing that this is probably blazingly fast anyway and would not have been distinguishable for the user even if all the messages would have been there

You could have a variable hold the update information (make its update/read thread safe) and have the UI thread be in charge of the updates. The UI thread should read the data from this and update its Views. The "update" thread should modify this variable when it receives a message.

You can post a Runnable to the UI thread that updates the TextView and then re-schedules itself to be run after that. This way you'll get the most performance, as re-scheduling the Runnable would allow the UI thread to finish rendering the updated info and then get back to updating the info right away and then re-render and so on. A nice side-effect of this is that you allow the UI thread to process the user input events too.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top