How to use runOnUiThread for updating a TextView - java

I have two threads in my main activity from Runner and start them with clicking a button. The only thing thy do is count up. I want to update two TextViews wit the current count from ech thread. When i start my app and click my button, the app crashed.
The code run perfektly in the console.
The class Runner is only used for the counting. I want to Update the two TextViews after each passage in the methode running().
public class Runner extends Activity implements Runnable {
int count = 0;
String name;
public Runner(String name) {
super();
this.name = name;
}
public void warten() throws InterruptedException {
int zahl = (int) (Math.random() * 500) + 500;
Thread.sleep(zahl);
}
public void running() throws InterruptedException {
for(int i = 0; i < 10; i++) {
warten();
count++;
System.out.println(name + " ist bei: " + count);
if(count == 10) {
System.out.println(name + " IST FERTIG");
}
runOnUiThread(new UiThread(name, count));
}
}
public void run() {
try {
running();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The class UiThread should be the main thread for updating the UI.
public class UiThread extends Activity implements Runnable {
String name;
int count;
TextView textView1;
TextView textView2;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
textView1 = findViewById(R.id.textView2);
textView2 = findViewById(R.id.textView3);
}
public UiThread(String name, int count){
this.name = name;
this.count = count;
}
#Override
public void run() {
if(name == "thread1"){
textView1.setText("thread1 ist bei: " + count);
}else{
textView2.setText("thread2 ist bei: " + count);
}
}
}

i would recommend you checkout this guide on android threading docs.
You can't initialize an activity class, you only add it to the manifest, doing so will lead to a null context. So remove the constructor in your UiThread class.
Also you do not need for your runner class to extend Activity. Pass an instance of Activity inorder to use the runOnUiThread() method.
Here is an example of how the UiTHread class should be.
public class UiThread extends Activity {
public TextView textView1;
public TextView textView2;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
textView1 = findViewById(R.id.textView2);
textView2 = findViewById(R.id.textView3);
startThreads();
}
private void startThreads(){
// Initialize the runnable class passing this activity context.
Runner runner = new Runner(this);
Thread thread1 = new Thread(runner, "thread1");
Thread thread2 = new Thread(runner, "thread2");
thread1.start();
thread2.start();
}
}
the runner class
public class Runner implements Runnable {
private int count = 0;
private UiThread context;
public Runner(UiThread activityContext) {
this.context = activityContext;
}
public void warten() throws InterruptedException {
int zahl = (int) (Math.random() * 500) + 500;
Thread.sleep(zahl);
}
public void running() throws InterruptedException {
for(int i = 0; i < 10; i++) {
warten();
count++;
System.out.println(Thread.currentThread().getName() + " ist bei: " + count);
if(count == 10) {
System.out.println(Thread.currentThread().getName() + " IST FERTIG");
}
// update text views from the main thread.
context.runOnUiThread(new Runnable() {
#Override
public void run() {
if(Thread.currentThread().getName().equals("thread1")){
context.textView1.setText("thread1 ist bei: " + count);
}else{
context.textView2.setText("thread2 ist bei: " + count);
}
}
});
}
}
public void run() {
try {
running();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Hope this helps.

Related

ScrollView doesn't scroll programmatically in a Thread

So what i want to do basically is to scroll the scroll view as the client app sends the command. The method handleScrolling() works in the onCreate() but whenever i call it from the Thread, it doesn't scroll. I think that calling it from the Thread is the problem.
public class TeleprompterActivity extends Activity {
static ScrollView mScrollView;
TextView teleprompterTextView;
String message;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_teleprompter);
teleprompterTextView = findViewById(R.id.teleprompter_text_view);
teleprompterTextView.setText(MainActivity.contents);
mScrollView = findViewById(R.id.scroll);
Thread mThread = new Thread(new ServerClass());
mThread.start();
handleScrolling(3, true);
Log.e("TELE", "handleScrolling at start onCrete");
}
void handleScrolling(final int numLines, final boolean next) {
mScrollView.post(new Runnable() {
public void run() {
int currPosition = mScrollView.getScrollY();
int textSize = (int) teleprompterTextView.getTextSize();
if (next) {
int newPos = currPosition + (textSize * numLines);
mScrollView.smoothScrollTo(0, newPos);
}
if (!next) {
int newPos = currPosition - (textSize * numLines);
if (newPos < 0) {
newPos = 0;
}
mScrollView.scrollTo(0, newPos);
}
}
});
}
void handleMessage(String message) {
if (message.contains("NEXT:")) {
try {
int numLine = Integer.parseInt(message.substring(5));
handleScrolling(numLine, true);
return;
} catch (NumberFormatException nFE) {
nFE.printStackTrace();
Toast.makeText(TeleprompterActivity.this, "Number Format Exception", Toast.LENGTH_SHORT).show();
}
}
if (message.contains("BACK:")) {
try {
int numLine = Integer.parseInt(message.substring(5));
handleScrolling(numLine, false);
} catch (NumberFormatException nFE) {
nFE.printStackTrace();
Toast.makeText(TeleprompterActivity.this, "Number Format Exception", Toast.LENGTH_SHORT).show();
}
}
}
public class ServerClass implements Runnable {
ServerSocket serverSocket;
Socket socket;
DataInputStream dataInputStream;
String receivedData;
Handler handler = new Handler();
#Override
public void run() {
try {
serverSocket = new ServerSocket(8080);
Log.e("TELE", "WAITIN FOR CLIENT");
while (true) {
socket = serverSocket.accept();
dataInputStream = new DataInputStream(socket.getInputStream());
receivedData = dataInputStream.readUTF();
handler.post(new Runnable() {
#Override
public void run() {
message = receivedData;
handleMessage(message);
}
});
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
The handleScrolling() method works perfectly when called outside the Thread. Is it any problem of reference or something like that.
Thanks..
Never update UI components from a thread directly ,call Activity's runOnUiThread so you can use code construct like below:
public class TeleprompterActivity extends Activity {
static ScrollView mScrollView;
TextView teleprompterTextView;
String message;
Activity thisActivity;//<--- used for saving reference to this Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_teleprompter);
teleprompterTextView = findViewById(R.id.teleprompter_text_view);
teleprompterTextView.setText(MainActivity.contents);
mScrollView = findViewById(R.id.scroll);
thisActivity = this;//<---- saving a reference to this activity
Thread mThread = new Thread(new ServerClass());
mThread.start();
handleScrolling(3, true);
Log.e("TELE", "handleScrolling at start onCrete");
}
void handleScrolling(final int numLines, final boolean next) {
thisActivity.runOnUiThread(new Runnable()//<--used thisActivity.runOnUiThread here
{
public void run() {
int currPosition = mScrollView.getScrollY();
int textSize = (int) teleprompterTextView.getTextSize();
if (next) {
int newPos = currPosition + (textSize * numLines);
mScrollView.smoothScrollTo(0, newPos);
}
if (!next) {
int newPos = currPosition - (textSize * numLines);
if (newPos < 0) {
newPos = 0;
}
mScrollView.scrollTo(0, newPos);
}
}
});
}

How do I make a CountDown show/start at the same moment my Button gets enabled?

"How do I make a CountDown show at the same moment my Button gets enabled ?"
Additional info regarding the button: the Buttons Job is it to click 5 times through a stringarray displayed in a Textview to then get disabled for 5 seconds to do the same task again.
so ..I would like a CountDown to visually show those 5 seconds(the time the button is enabled) count down for the User to see.
sadly I dont have an idea how to connect my Button with an CountDown to let it know its supposed to count down at that particular time the Button is enabled.
Also I would like for the CountDown to start everytime the Button gets enabled.
I looked into https://developer.android.com/reference/android/os/CountDownTimer
but it doesnt seem to have a solution for that particular case.
thats my Code for the Button as of now :
next_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (currentnumber == list.length) {
currentnumber = 0;
}
if (Curclicks == mod - 1) {
next_button.setEnabled(false);
display.setText(list[currentnumber]);
currentnumber++;
handler.postDelayed(new Runnable() {
#Override
public void run() {
//the button will unlock after the delay specified
next_button.setEnabled(true);
Curclicks = 0;
}
}, delay);
} else {
display.setText(list[currentnumber]);
currentnumber++;
}
Curclicks++;
}
});
UI Thread code can solve that ? :
private void runThread() {
new Thread() {
public void run() {
while (delay == 5000) { //delay = 5000 ( 5 secs)
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
timer.setText("" + delay);//timer=TxtView
}
});
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
Here is an example of how you can use the postDelayed() method of the Handler to create a count down. I have purposefully left the code a bit verbose so you can go through it step-by-step in order to see what is happening.
Create a few class variables and constants.
private static final long COUNT_DOWN_TICKS = 100l;
private static final long COUNT_DOWN_FINISH = 5000l;
private long countdownElapsed = 0l;
private Handler mCountDownHandler = new Handler();
COUNT_DOWN_FINISH is set to 5000 --> 5 sec. But can be changed to anything you need. Also I use COUNT_DOWN_TICKS set to 100 --> 0.1 sec, just in case you want to display a more precise count down.
From your OnClick() method just call startCountDown() to get the count down started.
private void startCountDown() {
try {
countdownElapsed = 0l;
next_button.setEnabled(false);
displayCountDown();
mCountDownHandler.postDelayed(mCountDownRunnable, COUNT_DOWN_TICKS);
}
catch (Exception ex){
Log.e(TAG, ex.getMessage());
}
}
private Runnable mCountDownRunnable = new Runnable() {
#Override
public void run() {
countdownElapsed = countdownElapsed + COUNT_DOWN_TICKS;
if(countdownElapsed >= COUNT_DOWN_FINISH){
releaseCountDownHandler();
next_button.setEnabled(true);
}
else{
mCountDownHandler.postDelayed(mCountDownRunnable, COUNT_DOWN_TICKS);
}
long secFull = countdownElapsed % 1000;
if(secFull == 0){
runOnUiThread(new Runnable() {
#Override
public void run() {
displayCountDown();
}
});
}
}
};
private void releaseCountDownHandler() {
try {
if(mCountDownRunnable != null) {
mCountDownHandler.removeCallbacks(mCountDownRunnable);
}
}
catch (Exception ex){
Log.e(TAG, ex.getMessage());
}
}
private void displayCountDown(){
long t = (COUNT_DOWN_FINISH - countdownElapsed)/1000;
String myTime = String.valueOf(t);
timer.setText(myTime);
}
In order to dispose of the Runnable properly you will want to call releaseCountDownHandler() from the onPause() method. This is just a short running Thread, but it should still not be ignored.
I prefer the Handler with the postDelay() method to the Thread.sleep() method--something about putting any thread to sleep is disconcerting. Also note that it is a good idea to get accustom to checking the elapsed time condition with ">=" RATHER than "==" depending on the implementation (e.g. you use SystemClock.elapsedRealtime() instead) the condition just might miss the exact value!
EDIT
Somewhere under the definition of your Activity class (for this example I will call it MainActivity) you will need to declare a few variables. Since they are being defined inside the class and NOT inside a method the are referred to as "class variables" and they have a scope of entire class when defined "private".
public class MainActivity extends AppCompatActivity {
//class variables
private static final long COUNT_DOWN_TICKS = 100l;
private static final long COUNT_DOWN_FINISH = 5000l;
private long countdownElapsed = 0l;
private Handler mCountDownHandler = new Handler();
private Button next_button;
private TextView timer;
....
}
You probably have declared the onClick() method inside the onCreate() method of the MainActivity class. So just add the following code:
next_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startCountDown();
}
Everything else I provide are method inside the MainActivity class...NOT inside any other method. So below the onCreate() method add all methods that I previously posted.
It will look something like this:
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
//class variables
private static final long COUNT_DOWN_TICKS = 100l;
private static final long COUNT_DOWN_FINISH = 5000l;
private long countdownElapsed = 0l;
private Handler mCountDownHandler = new Handler();
private Button next_button;
private TextView timer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// you must compensate for the actual layout for your activity
setContentView(R.layout.activity_main);
// you must compensate for the actual id of the TextView
timer = findViewById(R.id.tvTimer);
// you must compensate for the actual id of the Button
next_button = findViewById(R.id.btnNext);
next_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startCountDown();
}
});
}
private void startCountDown() {
try {
countdownElapsed = 0l;
next_button.setEnabled(false);
displayCountDown();
mCountDownHandler.postDelayed(mCountDownRunnable, COUNT_DOWN_TICKS);
}
catch (Exception ex){
Log.e(TAG, ex.getMessage());
}
}
private Runnable mCountDownRunnable = new Runnable() {
#Override
public void run() {
countdownElapsed = countdownElapsed + COUNT_DOWN_TICKS;
if(countdownElapsed >= COUNT_DOWN_FINISH){
releaseCountDownHandler();
next_button.setEnabled(true);
}
else{
mCountDownHandler.postDelayed(mCountDownRunnable, COUNT_DOWN_TICKS);
}
long secFull = countdownElapsed % 1000;
if(secFull == 0){
runOnUiThread(new Runnable() {
#Override
public void run() {
displayCountDown();
}
});
}
}
};
private void releaseCountDownHandler() {
try {
if(mCountDownRunnable != null) {
mCountDownHandler.removeCallbacks(mCountDownRunnable);
}
}
catch (Exception ex){
Log.e(TAG, ex.getMessage());
}
}
private void displayCountDown(){
long t = (COUNT_DOWN_FINISH - countdownElapsed)/1000;
String myTime = String.valueOf(t);
timer.setText(myTime);
}
}
This function should do what you want, just call it into OnClickListener
public void countDown(Button yourBtn) {
new Thread() {
public void run() {
try {
int second = 10;
for (int i = second; i >= 1; i--) {
int finalI = i;
yourBtn.post(new Runnable() {
#Override
public void run() {
yourBtn.setText(String.valueOf(finalI))
}
});
Thread.sleep(1000); // Change text every 1s
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
This code is like my code above except this code introduces a "click counter". I have introduced a new class variable to keep track of how many times the button is clicked. I have also introduced a new constant called "NUMBER_OF_BUTTON_CLICKS" which servers as the upper limit of clicks.
The user can now click on the button (in this case) 5 times. On the fifth click the condition to trigger the startCountDown method is met and the button is disabled for 5 seconds.
public class MainActivity extends AppCompatActivity {
//Constant values
private static final String TAG = MainActivity.class.getSimpleName();
private static final int NUMBER_OF_BUTTON_CLICKS = 5;
private static final long COUNT_DOWN_TICKS = 100l;
private static final long COUNT_DOWN_FINISH = 5000l;
//class variables
private int howManyClicks = 0;
private long countdownElapsed = 0l;
private Handler mCountDownHandler = new Handler();
private Button next_button;
private TextView timer;
private TextView clicks;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// you must compensate for the actual layout for your activity
setContentView(R.layout.activity_main);
// you must compensate for the actual id of the TextView
timer = findViewById(R.id.tvTimer);
// Use this only if you want to display the number of clicks
// you might need to add this TextView if you want to display the number of clicks
clicks = findViewById(R.id.tvClicks);
// you must compensate for the actual id of the Button
next_button = findViewById(R.id.btnNext);
next_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
howManyClicks++;
if(howManyClicks >= NUMBER_OF_BUTTON_CLICKS){
startCountDown();
}
//Add this only if you want to see how many clicks were made
String myClicks = String.valueOf(howManyClicks);
clicks.setText(myClicks)
}
});
}
private void startCountDown() {
try {
countdownElapsed = 0l;
next_button.setEnabled(false);
displayCountDown();
mCountDownHandler.postDelayed(mCountDownRunnable, COUNT_DOWN_TICKS);
}
catch (Exception ex){
Log.e(TAG, ex.getMessage());
}
}
private Runnable mCountDownRunnable = new Runnable() {
#Override
public void run() {
countdownElapsed = countdownElapsed + COUNT_DOWN_TICKS;
if(countdownElapsed >= COUNT_DOWN_FINISH){
releaseCountDownHandler();
next_button.setEnabled(true);
// reset the clicks counter
howManyClicks = 0;
}
else{
mCountDownHandler.postDelayed(mCountDownRunnable, COUNT_DOWN_TICKS);
}
long secFull = countdownElapsed % 1000;
if(secFull == 0){
runOnUiThread(new Runnable() {
#Override
public void run() {
displayCountDown();
}
});
}
}
};
private void releaseCountDownHandler() {
try {
if(mCountDownRunnable != null) {
mCountDownHandler.removeCallbacks(mCountDownRunnable);
}
}
catch (Exception ex){
Log.e(TAG, ex.getMessage());
}
}
private void displayCountDown(){
long t = (COUNT_DOWN_FINISH - countdownElapsed)/1000;
String myTime = String.valueOf(t);
timer.setText(myTime);
//Add this only if you want to see how many clicks were made
String myClicks = String.valueOf(howManyClicks);
clicks.setText(myClicks)
}
}

Trying to print even and odd numbers from a shared resource

I am trying to print a synchronized Integer object (mInt) using two threads till 10. However either one of the thread locks the other thread throws the exception pasted below. Can someone point my mistake here. This is more of a Java related question however included "android" tag because I have coded it for android and I need to tryout sometime in it.
09-24 15:24:17.198 10621-11400/com.sameer.android.samplecode
E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-364
Process: com.sameer.android.samplecode, PID: 10621
java.lang.IllegalMonitorStateException: object not locked by thread before notify()
at java.lang.Object.notify(Native Method)
at com.sameer.android.samplecode.MainActivity$Even.run(MainActivity.java:55)
public class MainActivity extends AppCompatActivity {
private Integer mInt;
class Odd extends Thread {
private final String TAG = Odd.class.getSimpleName();
#Override
public void run() {
Log.i(TAG, "Odd() Started....");
synchronized (mInt) {
try {
while (mInt <= 10)
{
while (mInt % 2 != 1) {
Log.i(TAG, "Odd... Looping " + mInt);
mInt.wait();
}
mInt++;
Log.i(TAG, "Odd " + mInt);
mInt.notify();
}
}
catch (InterruptedException e) {
Log.e(TAG, "Odd() " + e.getMessage());
}
}
Log.i(TAG, "Odd() Ended....");
}
}
class Even extends Thread {
private final String TAG = Even.class.getSimpleName();
#Override
public void run() {
Log.i(TAG, "Even() Started....");
synchronized (mInt) {
try {
while (mInt <= 10)
{
while (mInt % 2 != 0) {
Log.i(TAG, "Even... Looping " + mInt);
mInt.wait();
}
mInt++;
Log.i(TAG, "Even " + mInt);
mInt.notify();
}
}
catch (InterruptedException e) {
Log.e(TAG, "Even() " + e.getMessage());
}
}
Log.i(TAG, "Even() Ended....");
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mInt = new Integer(0);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Even even = new Even();
even.start();
Odd odd = new Odd();
odd.start();
}
});
}
}
When you increment mInt, you do not modify the current Integer object but create a new Integer object. Thus, the call to notify is performed on the new (unlocked) object. As notify must be called on the object that is locked, the IllegalMonitorStateException occurs.
Additional Side Remark (not part of answer):
Your code has a fundamental problem. You lock mInt at the beginning of both run methods. Thus, only one of your thread can enter its synchronized block. The second thread, will wait for the lock on mInt until the first thread leaves it synchronized block, ie, terminates. Thus, you end up in a deadlock because the first thread increments only a single time and waits inside its synchronized block for the other thread to do the next increment. However, the second thread cannot perform this operation as it cannot enter its own synchronized block (until the first thread releases the lock on mInt).
Thanks Matthias! Your response (partially) helped me solved the issue which I was suspecting and you nailed it. The issue was with mInt getting newly created and hence losing reference. I fixed the issue by creating a class similar to Integer. I have pasted the code below.
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private Value mInt;
class Odd extends Thread {
private final String TAG = Odd.class.getSimpleName();
#Override
public void run() {
Log.i(TAG, "Odd() Started....");
synchronized (mInt) {
try {
while (mInt.get() < 10)
{
while (mInt.get() % 2 != 1) {
mInt.wait();
}
Log.i(TAG, "Odd " + mInt.get());
mInt.inc();
mInt.notify();
}
}
catch (InterruptedException e) {
Log.e(TAG, "Odd() " + e.getMessage());
}
}
Log.i(TAG, "Odd() Ended....");
}
}
class Even extends Thread {
private final String TAG = Even.class.getSimpleName();
#Override
public void run() {
Log.i(TAG, "Even() Started....");
synchronized (mInt) {
try {
while (mInt.get() < 10)
{
while (mInt.get() % 2 != 0) {
mInt.wait();
}
Log.i(TAG, "Even " + mInt.get());
mInt.inc();
mInt.notify();
}
}
catch (InterruptedException e) {
Log.e(TAG, "Even() " + e.getMessage());
}
}
Log.i(TAG, "Even() Ended....");
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mInt = new Value();
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mInt.set();
Even even = new Even();
even.start();
Odd odd = new Odd();
odd.start();
}
});
}
}
class Value {
private int member;
public Value() {
member = 0;
}
public int get() {
return member;
}
public void inc() {
this.member++;
}
public void set() {
this.member = 0;
}
public void dec() {
this.member--;
}
}

How to get notified each time the value increased

I have two threads.One is for incrementing the value.For each increment i neet to be notified the main thread.
Below is my main Thread which is a activity
public class MainActivity extends Activity {
private ProgressBar progressBar;
private int progressStatus = 1;
private TextView textView;
private Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progressBar = (ProgressBar) findViewById(R.id.progressBar1);
textView = (TextView) findViewById(R.id.textView1);
ProgressUpdate b = new ProgressUpdate();
b.start();
Log.e("SAMEERA", "Satrting ProgressUpdate");
synchronized (b) {
try {
Log.e("SAMEERA", "synchronized synchronized");
Log.e("SAMEERA", "progressStatus is "+b.total);
b.wait();
Log.e("SAMEERA", "progressStatus is "+b.total);
progressBar.setProgress(progressStatus);
textView.setText(progressStatus + "/" + progressBar.getMax());
} catch (InterruptedException e) {
}
System.out.println("Total is: " + b.total);
}
}
}
Below is my increment thread.
package com.example.zwtouch;
import android.util.Log;
public class ProgressUpdate extends Thread {
int total;
public void run() {
total=0;
synchronized (this) {
for (int i = 0; i < 100; i++) {
total += i;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.e("SAMEERA", "run run total is "+i);
notify();
}
}
}
}
I need to notified each time if total is increased.But its not happening.After the for loop is finished it calls the main thread..where is the error ?
Option 1
Use Handler
Populate ProgressUpdate with ProgressBar and Handler objects.
On each progress use the Handler to update the ProgressBar
like this:
public class ProgressUpdate extends Thread {
int total;
ProgressBar mProgressBar;
Handler mHandler;
public ProgressUpdate(Handler h, ProgressBar pb) {
mHandler = h;
mProgressBar = pb;
}
public void run() {
total=0;
for (int i = 0; i < 100; i++) {
// Update the progress bar via a Handler
mHandler.post(new Runnable() {
public void run() {
mProgressBar.setProgress(i);
}
});
}
}
}
setup like this
new ProgressUpdate(handler, progressBar).start();
Option 2 (recommended)
This is another approach, You could use AsyncTask to achieve this aim. The advantage of this way is that both onProgressUpdate and onPostExecute runs on UI-Thread.
Make this class internal of MainActivity
private class ProgressUpdate extends AsyncTask<Void, Integer, Integer> {
protected Integer doInBackground(Void... dummy) {
int total = 0;
for (int i = 0; i < 100; i++) {
total += i;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.e("SAMEERA", "run run total is "+i);
// Notify UI Thread
publishProgress(i);
}
return total;
}
protected void onProgressUpdate(Integer... i) {
// do something with 'i' on UI Thread
progressBar.setProgress(i);
}
protected void onPostExecute(Integer total) {
// do something with 'total' on UI Thread
// for instance
progressBar.setVisibility(View.GONE);
}
}
Setup ProgressUpdate on onCreate like this
#Override
protected void onCreate(Bundle savedInstanceState) {
// ...
new ProgressUpdate().execute();
// ...
}

why handlemessage not working

i have a problem with handler in android, i don't understand not display result, this's code:
public class Main extends Activity implements OnClickListener {
private EditText nhap;
private Button btTinh;
private Button btHuy;
private TextView kq;
private ProgressDialog progress;
private Handler handle = new Handler();
private int count = 0;
private String s = "";
private long n;
handlemessage:
Handler mhandle = new Handler() {
#Override
public void handleMessage(Message msg) {
kq.setText(msg.obj.toString());
}
};
onCreate:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
nhap = (EditText) findViewById(R.id.nhap);
btTinh = (Button) findViewById(R.id.btTinh);
btHuy = (Button) findViewById(R.id.btHuy);
kq = (TextView) findViewById(R.id.kq);
btTinh.setOnClickListener(this);
btHuy.setOnClickListener(this);
}
public boolean checkPrime(long n) {
for (int i = 2; i <= Math.sqrt(n); i++) {
if (n % i == 0)
return false;
}
return true;
}
outprime:
public void outPrime(long t) {
// String s="";
progress.setCancelable(true);
progress.setMessage("File downloading ...");
progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progress.setProgress(0);
progress.setMax(Integer.parseInt(nhap.getText().toString()));
progress.show();
n = t;
new Thread() {
public void run() {
for (int i = 2; i < n; i++) {
count = i;
if (checkPrime(i))
s = s + i + " ";
handle.post(new Runnable() {
public void run() {
// TODO Auto-generated method stub
progress.setProgress(count);
}
});
}
if (count == n - 1) {
progress.dismiss();
Message msg = handle.obtainMessage(1, (String)s);
handle.sendMessage(msg);
}
}
}.start();
}
onclick:
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.btTinh:
progress = new ProgressDialog(this);
outPrime(Long.parseLong(nhap.getText().toString()));
break;
case R.id.btHuy:
nhap.setText("");
break;
}
}}
this's handlemessage:
Handler mhandle = new Handler() {
#Override
public void handleMessage(Message msg) {
kq.setText(msg.obj.toString());
}
};
i don't understand handlemessage don't return value, "kq.setText(msg.obj.toString());" don't display to screen, sorry because my english not good
I think the answer for your question is "Watch out your variable's names!" Look - you've created 2 Handlers - named "mhandle" and "handle". You want to parse message in Handler named "mhandle", but in your Thread send it to "handle", which is doing nothing from your code.
Hope it will help if you still trying to find the answer.

Categories

Resources