1

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?

Fraggles
  • 433
  • 4
  • 20

3 Answers3

1

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

Community
  • 1
  • 1
avalancha
  • 1,148
  • 1
  • 19
  • 38
1

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;
        }
    }
    

    } }

Community
  • 1
  • 1
Kai
  • 14,428
  • 6
  • 46
  • 78
  • on No.1) the value of data gives me a 12-char string back and this string is much more work to compare than a hex char (due to the whole project I'm working on – Fraggles Feb 03 '14 at 10:27
  • @Fraggles it's a quick psudo code to convey the basic idea, you can simply change it to `sb.append(Integer.toHexString(demoRxMsg.data[i])`, but as briefly mentioned in the first line, I think the main problem is probably somewhere else, perhaps you are doing something time-consuming in `new MessageStructure()` or in `rxChannel.receiveMessage(demoRxMsg)` – Kai Feb 03 '14 at 10:29
  • that could be possible, but `MessageStructure()` and `rxChannel.receiveMessage(demoRxMsg)` are part of the API and I cant change it – Fraggles Feb 03 '14 at 10:33
  • @Fraggles then I think your best bet is #3, moving everything out of UI thread except `mProgressBar.setProgress(progress);` that _has_ to execute on UI thread. – Kai Feb 03 '14 at 10:37
  • 1
    @Fraggles added sample for #3 – Kai Feb 03 '14 at 10:50
  • so #3 works much better, but not faster enough, but a very big thanks to you for your time :) – Fraggles Feb 03 '14 at 11:05
  • I don't see how it can be further improved on the UI side, can you define how fast it should be, and probably need to check the amount of time you spend in while (rxChannel.receiveMessage(demoRxMsg) == ReturnCode.SUCCESS) – Kai Feb 03 '14 at 11:12
  • when I call `receiveMessage(msg)`, I have no possibility to influence whats going in the background, cause its part of the API – Fraggles Feb 03 '14 at 13:34
  • If that's the case I don't see how we can help you – Kai Feb 03 '14 at 14:04
  • but you helped me a lot to where I'm standing now. Thank you very much – Fraggles Feb 03 '14 at 14:59
0

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.

lucian.pantelimon
  • 3,513
  • 4
  • 27
  • 45