Bonnev
Bonnev

Reputation: 987

Function and Runnable Working at the Same Time (How To?) (Android, Java)

I have an Android app that after pressing a button starts a function (outside onCreate()). This function changes a global String variable 5 times using a for loop. I want to see every variable shown on the screen (i.e. in a TextView). I understood I have to use a Runnable and a Handler, but..

in MainActivity (extends Activity) / onCreate():

button1.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View arg0) {
        handler.post(timedTask);
        Start();
    }
});

Start() runs, but nothing went on the screen until it had finished.

In MainActivity (extends Activity):

private Runnable timedTask = new Runnable()
{
      @Override
      public void run()
      {
          textView1 = (TextView) findViewById(R.id.textView1);
          textView1.append(globalMessage);
          handler.postDelayed(this, 100);
      }};

in MainActivity (extends Activity) / Start():

for(int j = 0; j < 5; j++)
{
    ...
    globalMessage = message[j];
    ...
}

Upvotes: 2

Views: 1126

Answers (2)

Bonnev
Bonnev

Reputation: 987

I got it! The trick is putting all the code from the method/function to the Runnable, then everything is working fine and every text is updating on the spot. So this code:

private Runnable timedTask = new Runnable()
{
      @Override
      public void run()
      {
          textView1 = (TextView) findViewById(R.id.textView1);
          textView1.append(globalMessage);
          handler.postDelayed(this, 100);
      }};

becomes:

private Runnable timedTask = new Runnable()
{
    @Override
    public void run()
    {
        textView1 = (TextView) findViewById(R.id.textView1);
        for(int j = 0; j < 5; j++)
        {
        ...
        globalMessage = message[j];
        textView1.setText(globalMessage);
        ...
        }
    }
};

There are some things I changed though:

  1. Thanks to Tala I changed handler.post(timedTask); with Thread thread1 = new Thread(timedTask1); and then thread1.start(); or simply with one line (new Thread(timedTask)).start();

  2. I had some issues with some exceptions:

android.view.ViewRoot$ CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

This accured with textView1.setText(globalMessage); and textView1.append(globalMessage); and surely more methods of that type and which are not in onCreate(). If you want to use them out of onCreate then read this answer which suggests replacing that line with:

runOnUiThread(new Runnable() {
    @Override
    public void run()
    {
        button1.append(globalMessage);
    }
});

Another exception you should look out for is java.lang. NullPointerException which means you should initialise some variables in the current method/runnable/scope

If someone has questions: feel free to comment here!

Upvotes: 0

Tala
Tala

Reputation: 8928

First of all, you're accessing variable from different threads. You should declare it as volatile.

So you want your timedTask to display 5 values of globalMessage?

Make sure to synchronized timedTask with your loop so that after every modification timedTask executes.

for(int j = 0; j < 5; j++)
{
    ...
    globalMessage = message[j];
    ...// wait sometime here or make sure it is a long operation that is enough for synchronization
}

EDIT

Your handler.post might not be starting runnable immediately. You can start your runnable yourself:

(new Thread(timedTask)).start(); // instead of handler.post

Or do it the easiest way: just update text in your for loop in the same thread.

Upvotes: 2

Related Questions