1

I'm trying to dynamically update an android LinearLayout in the main thread.

Unfortunately I'm having a lot of trouble ascertaining anything from the tutorials online. None of them seem to provide a complete picture of how to communicate between threads.

My idea is something like this:

public class MainActivity extends AppCompatActivity {

    private LinearLayout layout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        layout = new LinearLayout(this);
        setContentView(layout);

        Updater updater = new Updater();
        Thread workerThread = new Thread(updater);
        //somehow update layout

The updater class would look something like this:

public class Updater implements Runnable {

    private int count = 0;

    public Updater() {}

    @Override
    public void run()
    {
        for (int i = 0; i < 10; i ++){

            try {
                count++;
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

I know I need a Handler in order to communicate messages between the threads, but I don't know how to set that up.

I would like to avoid anonymous classes, and dynamically create new TextViews whenever Updater has a new message.

Astrum
  • 591
  • 3
  • 12
  • 25
  • You can try `AsyncTask` though if your only job is process a certain thing in the background and pass it back to the MainThread! – Enzokie Jan 10 '18 at 06:06
  • What is `Updater`? Your Runnable class name is `Counter` isn't it ? – ADM Jan 10 '18 at 06:07
  • Yes, I want to avoid that though since I need to continuously update a `View`, and I don't think using the "progress" method would be best for performance. Also, I'd like to know how to properly set up the threading myself. @ADM sorry, it was a typo! – Astrum Jan 10 '18 at 06:08
  • It seems your answer: https://stackoverflow.com/questions/11140285/how-to-use-runonuithread. Or you can use [Handler](https://developer.android.com/reference/android/os/Handler.html) – John Le Jan 10 '18 at 06:09
  • @LQGioan The whole point of this is to spawn a second thread, since my UI thread is extremely slow and unresponsive – Astrum Jan 10 '18 at 06:10
  • Linked question had more useful answers. – Ravindra babu Jan 10 '18 at 17:17

3 Answers3

3
  1. create WorkerThreadListener interface:
public interface WorkerThreadListener {
    void onUpdate(int counter);
}
  1. Change your Updater class:
public class Updater implements Runnable {

    private final WorkerThreadListener mWorkerThreadListener;
    private final Handler mHandler;

    private int count = 0;

    public Updater(final WorkerThreadListener workerThreadListener) {
        this.mWorkerThreadListener = workerThreadListener;
        this.mHandler = new Handler();
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            try {
                count++;
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mWorkerThreadListener.onUpdate(count);
                    }
                });
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  1. Change MainActivity class:
public class MainActivity extends AppCompatActivity {

    private LinearLayout layout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        layout = new LinearLayout(this);
        setContentView(layout);
        Updater updater = new Updater(new WorkerThreadListener() {
            @Override
            public void onUpdate(int counter) {
                //update layout here
            }
        });
        Thread workerThread = new Thread(updater);
        workerThread.start();
    }
}
Zuluft
  • 129
  • 1
  • 5
0

Hi please check my below answer hope it helps you.

public class ProgressTestActivity extends Activity {
    private ProgressBar progress;
    private TextView text;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        progress = (ProgressBar) findViewById(R.id.progressBar1);
        text = (TextView) findViewById(R.id.textView1);

    }

    public void startProgress(View view) {
        // do something long
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <= 10; i++) {
                    final int value = i;
                     doFakeWork();
                    progress.post(new Runnable() {
                        @Override
                        public void run() {
                           // here you can add any view or anyof your logic which is related to UI put it into here.
                            text.setText("Updating");
                            progress.setProgress(value);
                        }
                    });
                }
            }
        };
        new Thread(runnable).start();
    }

    // Simulating something timeconsuming
    private void doFakeWork() {
        SystemClock.sleep(5000);e.printStackTrace();
    }

}

Other ways are also possible.if you have any doubt please comment below post i will explain you in details.

Jyubin Patel
  • 1,373
  • 7
  • 17
0

If you just want to use a tick timer and set progress to ui thread . You can use CountDownTimer.

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView textView;
private CountDownTimer countDownTimer;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_new);
    textView = (TextView) findViewById(R.id.textView);
    findViewById(R.id.b2).setOnClickListener(this);
}

public void processData() {
    countDownTimer = new CountDownTimer(30000, 1000) {
        public void onTick(long millisUntilFinished) {
            textView.setText("seconds remaining: " + millisUntilFinished / 1000);
        }

        public void onFinish() {
            textView.setText("done!");
        }

    }.start();
}

@Override
protected void onStop() {
    super.onStop();
    if (countDownTimer != null) {
        countDownTimer.cancel();
    }
}

@Override
public void onClick(View v) {
    processData();
}
}

Apart from that to post a callback on UI thread you can use Handler .

 Handler mainThreadHandler = new Handler(Looper.getMainLooper());
    mainThreadHandler.post(new Runnable() {
        @Override
        public void run() {

        }
    });
ADM
  • 20,406
  • 11
  • 52
  • 83
  • Unfortunately I used this as an easy example. The problem I'm trying to solve is much more broad than just a timer. I really want to know how to create a separate thread that can be used to update a `View`, updating in real time. – Astrum Jan 10 '18 at 06:23
  • See the updated answer if you are dealing with callback from NonUi thread to UI thread . – ADM Jan 10 '18 at 06:27