Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie

Android UI thread issue

Options
  • 18-01-2013 11:33am
    #1
    Moderators, Science, Health & Environment Moderators, Social & Fun Moderators, Society & Culture Moderators Posts: 60,092 Mod ✭✭✭✭


    I am connecting to a terminal emulator using a library in android, this connects to a serial device (a switch) and shows me sent/received data. I send data over the connection via a text box below the terminal or by typing in the terminal itself and hitting enter on the keyboard in both cases. I can also send commands by pressing buttons.

    My problem is whenever the terminal itself is highlighted the UI does not update, as in the commands sent with the buttons, or data received from the serial device. I can type in the terminal itself and the characters come up. If the editText is selected everything updates fine. So if I select the terminal and send a command, it will only be displayed to the screen once I select the editText. A lot of the time after I select the editText it still does not update until I press the terminal again. Very strange. So my invalidate is not working well? Or is it this notifyUpdate method that I am using and don't really understand?

    What I currently do is call a method when data is received, this method calls a handler which updates the screen every 1000ms. This however does not work when the terminal is selected, why is this? I am getting the error: “Only the original thread that created a view hierarchy can touch its views.”

    Screenshot: http://i.imgur.com/s4mTt.png
    //terminal view
            EmulatorView view = (EmulatorView) findViewById(R.id.emulatorView);
            mEmulatorView = view;
        
            public void onDataReceived(int id, byte[] data)
            {
            dataReceived = new String(data);
            ((MyBAIsWrapper) bis).renew(data);
            mSession.write(dataReceived);
            mSession.notifyUpdate();
            viewHandler.post(updateView);
            }
        
            Handler viewHandler = new Handler();
            Runnable updateView = new Runnable() {
            @Override
            public void run() {
            mEmulatorView.invalidate();
            viewHandler.postDelayed(updateView, 1000);
        
                }
            }
        };
    


    Relevant code from library I'm using:
    protected void notifyUpdate() {
                if (mNotify != null) {
                    mNotify.onUpdate();
                }
            }
    
    and
    /**
         * Generic callback to be invoked to notify of updates.
         */
        public interface UpdateCallback {
            /**
             * Callback function to be invoked when an update happens.
             */
            void onUpdate();
        }
    

    This is the description of the method notifyUpdate() - Method in class jackpal.androidterm.emulatorview.TermSession Notify the UpdateCallback registered by setUpdateCallback that the screen has changed.


    I thought it might be mSession.notifyUpdate(); in my code, but apparently if I comment that out the same error occurs, that line seems to be doing nothing for me anyway. I'm not sure where the error is to fix it so that my screen is always being updated no matter where I am pressing.


Comments

  • Registered Users Posts: 4,443 ✭✭✭robbiezero


    Dont know much about it,
    But do you need to

    activity.runOnUiThread(new Thread() {
    @Override
    public void run() {
    .....
    }
    });

    where activity is an instance of the class where the view was created?


  • Moderators, Science, Health & Environment Moderators, Social & Fun Moderators, Society & Culture Moderators Posts: 60,092 Mod ✭✭✭✭Tar.Aldarion


    Heya, thanks, I'll try and do that and see if it works. i was just under the impression I was already in the UI thread because I made the handler there.


  • Moderators, Science, Health & Environment Moderators, Social & Fun Moderators, Society & Culture Moderators Posts: 60,092 Mod ✭✭✭✭Tar.Aldarion


    Running on ui thread aint doing much different for me. I commented out the line I use to write to the terminal mSession.write(dataReceived); and I dont get the error. But of course nothing is then written to the screen.


  • Moderators, Science, Health & Environment Moderators, Social & Fun Moderators, Society & Culture Moderators Posts: 60,092 Mod ✭✭✭✭Tar.Aldarion


    Got it working, I just had to run that write line in a UI thread, even though I thought it was?!
    runOnUiThread(new Runnable(){
    
    			@Override
    			public void run() {
    				
    				mSession.write(dataReceived);
    				
    			}});
    


  • Registered Users Posts: 18,272 ✭✭✭✭Atomic Pineapple


    Got it working, I just had to run that write line in a UI thread, even though I thought it was?!

    Doesn't look like it, aren't you creating and running a new thread using the Runnable class which will be run off the UI thread? The correct way to handle this is to create the thread and then use the handler to communicate between this new thread and the UI thread.


  • Advertisement
  • Moderators, Science, Health & Environment Moderators, Social & Fun Moderators, Society & Culture Moderators Posts: 60,092 Mod ✭✭✭✭Tar.Aldarion


    That is what is happening I think, yes. I made the new thread in Runnable and ran it from the UI thread. Are you saying my solution is not ideal then? What would you have changed?


  • Registered Users Posts: 2,021 ✭✭✭ChRoMe


    That is what is happening I think, yes. I made the new thread in Runnable and ran it from the UI thread. Are you saying my solution is not ideal then? What would you have changed?

    You should really be looking at http://developer.android.com/reference/android/os/AsyncTask.html

    Doing "traditional" threading on the main UI thread is bad karma.


  • Moderators, Science, Health & Environment Moderators, Social & Fun Moderators, Society & Culture Moderators Posts: 60,092 Mod ✭✭✭✭Tar.Aldarion


    So I'd make a separate class, subclass AsyncClass and write the functionality in there, calling it from my activity. This would completely replace handlers/Thread?
    Currently my screen doesn't update correctly unless I get a handler to invalidate it every second, and I also need to pass bytes of data received to the handler. Could this be replicated with Async, I image so, I'd just have to pass it the bytes but can you make it invalidate views in a different class? I'll have a look anyway thanks.

    What is the reason that this is the proper way?


  • Registered Users Posts: 2,021 ✭✭✭ChRoMe


    So I'd make a separate class, subclass AsyncClass and write the functionality in there, calling it from my activity. This would completely replace handlers/Thread?
    Currently my screen doesn't update correctly unless I get a handler to invalidate it every second, and I also need to pass bytes of data received to the handler. Could this be replicated with Async, I image so, I'd just have to pass it the bytes but can you make it invalidate views in a different class? I'll have a look anyway thanks.

    What is the reason that this is the proper way?

    Yes pretty much, instantiate the Async class, and call execute on it.

    The reason this is considered the correct way is, Android does some stuff under the hood to optimise these threads and manage them. I'll be completely honest and say I dont know the exact details, but I do know its a good thing ;)


  • Registered Users Posts: 18,272 ✭✭✭✭Atomic Pineapple


    You can use your AsyncTask class as an inner class too. You can also spawn a thread off the UIThread and then use a handler to react to different messages from that thread and update your UI in the UIThread. Asynctask is best though.


  • Advertisement
  • Registered Users Posts: 2,021 ✭✭✭ChRoMe


    draffodx wrote: »
    You can use your AsyncTask class as an inner class too. You can also spawn a thread off the UIThread and then use a handler to react to different messages from that thread and update your UI in the UIThread. Asynctask is best though.

    Yeah... I'm a bit worried seeing other people's Android code that has a lot of private inner classes. These are used in the tutorials for the sake of illustration. Its pretty bad design to be doing it.

    Separation. of. concern.


  • Registered Users Posts: 18,272 ✭✭✭✭Atomic Pineapple


    ChRoMe wrote: »
    Yeah... I'm a bit worried seeing other people's Android code that has a lot of private inner classes. These are used in the tutorials for the sake of illustration. Its pretty bad design to be doing it.

    Separation. of. concern.

    Indeed, I meant to say use it as an inner class for initial testing purposes. Best to keep it separate and use an observer to update your UI.


Advertisement