This is the code of my testing app:
public class MainActivity extends Activity
{
private TextView text;
private Button start;
private Button stop;
private TestThread Points;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
text = (TextView) findViewById(R.id.mainTextView1);
start = (Button) findViewById(R.id.mainButton1);
stop = (Button) findViewById(R.id.mainButton2);
Points = new TestThread();
start.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View p1)
{
if (! Points.isAlive())
{
Points.start();
}
}
});
stop.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View p1)
{
if (Points.isAlive())
{
Points.stop();
}
}
});
}
public class TestThread extends Thread
{
private String points;
#Override
public void run()
{
for (int a = 0; a < 3; a++)
{
try
{
if (a == 0) points = ".";
else if (a == 1) points = "..";
else if (a == 2) {
points = "...";
a = -1;
}
runOnUiThread(new Runnable()
{
#Override
public void run()
{
text.setText(points);
}
});
Thread.sleep(350);
} catch (InterruptedException e) {}
}
}
}
}
When I click on Start button the thread starts successfully but when I click on Stop button the app crashes...
How can i stop the thread successfully without force closing?
Thanks a lot
Thread.stop() function is deprecated and should not be used to stop a thread.
this is according to the java docs.
a good way to stop a thread is make it exit its run method.
a simple way to achive this is by adding a boolean member to your thread class:
public class TestThread extends Thread
{
private String points;
private boolean keepRunning = true;
public cancel(){
keepRunning = false;
}
#Override
public void run()
{
for (int a = 0; a < 3; a++)
{
if(!keepRunning) break;
try
{
if (a == 0) points = ".";
else if (a == 1) points = "..";
else if (a == 2) {
points = "...";
a = -1;
}
runOnUiThread(new Runnable()
{
#Override
public void run()
{
text.setText(points);
}
});
Thread.sleep(350);
} catch (InterruptedException e) {}
}
}
}
call the TestThread.cancel() function in your stop button onClick method.
Other than adding a Boolean to stop it I believe you could catch InterruptException and just call Thread.interrupt(); which would exit the loop this ending the thread
Related
I am trying to use thread wait and notify function, but noticed that notify function not calling my method again. Sharing my code. Please let me know what I'm doing wrong.
public class MainActivity extends AppCompatActivity {
Thread t;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
t = new Thread(new Runnable() {
#Override
public void run() {
List<Parent> threadList = new ArrayList<>();
threadList.add(new Task1(MainActivity.this));
threadList.add(new Task2(MainActivity.this));
for (Parent task : threadList) {
try {
task.execute();
t.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
t.start();
}
public void getResult(int i) {
Log.i("###","Notified"+i);
t.notify();
}
}
class Task1 implements Parent{
public int total;
MainActivity mainActivity;
Task1 (MainActivity c) {
mainActivity = c;
}
#Override
public void execute() {
for(int i=0; i<200 ; i++){
total += i;
Log.i("###1", ""+i);
}
mainActivity.getResult(1);
}
}
Task 2 is not getting executed after Task1
I am trying to do this simple task. I have two buttons called START and STOP, I want to execute some task in loop by clicking on START and want to exit from this loop by clicking STOP.
Code-
public class DrawPath extends Activity implements View.OnClickListener {
ArrayList<LatLng> positions = new ArrayList<LatLng>() ;
static int c=1;
Location location;
GoogleMap mMap;
Button btStart,btStop;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.drawpath);
initializeVar();
btStart.setOnClickListener(this);
btStop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
c = 0;
System.out.println("tested2");
}
});
}
private void initializeVar()
{
btStart=(Button)findViewById(R.id.btStart);
btStop=(Button)findViewById(R.id.btStop);
}
#Override
public void onClick(View v) {
getupdate(1);
}
private void getupdate(int d) {
c = d;
CurrentPosition currentPosition = new CurrentPosition(this);
if (c == 0) {
System.out.println("Done");
} else {
location = currentPosition.getCurrentLocation();
LatLng pos = new LatLng(location.getLatitude(), location.getLongitude());
positions.add(pos);
System.out.println("running");
try {
Thread.sleep(5000);
getupdate(c);
} catch (Exception e) {
}
}
}
}
Somebody please share any idea how to achieve it.
You can use Handler with Runnable to stop your thread after STOP button click.
I am giving you hint use following code according to your requirement
Handler handler = new Handler();
Runnable runable = new Runnable({
#Override
public void run(){
// count
handler.postDelayed(this, 1000);
}
});
Now you can call following line from your btnStop.onClick().
handler.removeCallbacks(runable);
Check this for more details on Handler and Runnable
What I suggest it create a inner class which extends Thread and according to user's action start and stop the thread. here is an example
class DrawPath extends Activity implements View.OnClickListener {
MyThread thread;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.drawpath);
initializeVar(); //not in my code so you add it
btStart.setOnClickListener(this);
btStop.setOnClickListener(this);
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btStart:
if (thread == null) {
thread = new MyThread();
thread.start();
}
break;
case R.id.btStop:
if (thread != null) {
thread.interrupt();
}
break;
}
}
class MyThread extends Thread {
#Override
public void run() {
while (true) {
try {
Thread.sleep(3000);
//your stuff goes here or before sleep
} catch (InterruptedException e) {
e.printStackTrace();
thread = null;
break;
}
}
}
}
//whey interrupt here bcz infinite loop will be running until and unless you stop it.
#Override
protected void onDestroy() {
super.onDestroy();
if (thread != null)
thread.interrupt();
}
}
I saw your code which needs little more improvements that's why I wrote this big file :)
Suggestions :
Checkout the implementation of onClickListener.
Stopping thread at onDestroy() because thread will be running even after you close your application, so you need to stop when you
come out (destroyed) of your main activity.
I'm making an android app where you tap a button to stop a looping counter when it is showing a particular number. I have an array (aNums) holding some int values and want the counter to stop when it is clicked when showing the first number in the array (in this case "2"). For some reason however it decides to stop on "1" when clicked. I'm not sure if my code is just wrong or if there's a timing issue and it's stopping right when it's about to change to the number "2". Here is my code so far:
public class MainActivity extends Activity {
public int a = 0;
private Handler handler = new Handler();
TextView textView2;
Button Stop;
public Runnable myRunnable = new Runnable() {
#Override
public void run() {
updateText();
a = ++a % 10;
if (a < 10) {
handler.postDelayed(this, 1000);
}
}
};
public int aNums[] = { 2, 4, 6, 8, 10, 12 };
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView2 = (TextView) findViewById(R.id.textView2);
loop();
Stop = (Button)findViewById(R.id.Stop);
Stop.setOnClickListener(handler2);
}
View.OnClickListener handler2 = new View.OnClickListener() {
#Override
public void onClick(View v) {
if (a == aNums[0]) {
Stop();
}
}
}
public void loop() {
handler.post(myRunnable);
}
public void updateText() {
textView2.setText("" + a);
}
public void Stop() {
super.onStop();
handler.removeCallbacks(myRunnable);
}
}
Does anyone know what the problem is?
Thanks
You forgot two closing brackets here:
View.OnClickListener handler2 = new View.OnClickListener() {
#Override
public void onClick(View v) {
for (int i = 0; i <= aNums.length; i++) {
if (a == aNums[0]) {
Stop();
} //I added this
}
}
}//and this
but I think there is no need for a for loop here: you want to stop the thread when you click at the moment a equals the number in your array at index 0, right?
View.OnClickListener handler2 = new View.OnClickListener() {
#Override
public void onClick(View v) {
if (a == aNums[0]) {
Stop();
}
}
}
Also, this check is not necessary because a will never be 10 or more:
if (a < 10) {
handler.postDelayed(this, 1000);
}
The last thing: when you quit the thread, the text is not updated. Try adding the updateText() after the click:
View.OnClickListener handler2 = new View.OnClickListener() {
#Override
public void onClick(View v) {
if (a == aNums[0]) {
Stop();
updateText();
}
}
}
So I am writing an Android application which will do a count down when the user presses a button. A thread runs the count down. My problem is that when I pause the application I want the thread to stop counting and then resume once the application is back. My notify is not working correctly. Help thanks!
public class MainActivity extends Activity {
private TextView mText;
private EditText mUserInput;
private CounterThread mCounterThread;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mText = (TextView)findViewById(R.id.text);
mUserInput = (EditText)findViewById(R.id.userInput);
mCounterThread = new CounterThread();
}
#Override
public synchronized void onPause(){
super.onPause();
mCounterThread.running = false;
}
#Override
public synchronized void onResume(){
super.onResume();
mCounterThread.running = true;
notify();//seems like this does nothing!
}
public void startCounterThread(){
mCounterThread.start();
}
public void button_handler(View v){
startCounterThread();
}
public void updateSeconds(final long seconds){
Runnable UIdoWork = new Runnable(){
public void run(){
String time = String.valueOf(seconds);
mText.setText("Your file will open in " + time + " seconds");
}
};
runOnUiThread(UIdoWork);
}
private class CounterThread extends Thread{
int count = 10;
boolean running = true;
#Override
public synchronized void run(){
while(count != 0){
while(!running){
try{
wait();//wait() will wait forever
//I don't want to put a time since
//I have no clue when the user will resume again
}catch(InterruptedException e){
e.printStackTrace();
}
}
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
updateSeconds(count--);
}
}
}
Slightly modified code:
public class MainActivity extends Activity {
private TextView mText;
private EditText mUserInput;
private CounterThread mCounterThread;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_2);
mText = (TextView) findViewById(R.id.text);
mUserInput = (EditText) findViewById(R.id.userInput);
mCounterThread = new CounterThread();
mCounterThread.start();
}
#Override
public synchronized void onPause() {
super.onPause();
mCounterThread.onPause();
}
#Override
public synchronized void onResume() {
super.onResume();
mCounterThread.onResume();
}
public void startCounterThread() {
mCounterThread.start();
}
public void button_handler(View v) {
startCounterThread();
}
public void updateSeconds(final long seconds) {
Runnable UIdoWork = new Runnable() {
public void run() {
String time = String.valueOf(seconds);
mText.setText("Your file will open in " + time + " seconds");
}
};
runOnUiThread(UIdoWork);
}
private class CounterThread extends Thread {
private int count = 10;
private final Object lock = new Object();
private volatile boolean isRunning = true;
public void onResume() {
if(!isRunning){
isRunning = true;
synchronized (lock){
lock.notify();
}
}
}
public void onPause() {
isRunning = false;
}
#Override
public void run() {
while (count != 0) {
synchronized (lock) {
if (!isRunning) try {
lock.wait();
} catch (InterruptedException e) {
//
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//
}
updateSeconds(count--);
}
}
}
}
your field running must be marked as volatile. It basically means that several threads could change it and all threads will see it.
do not expose monitor objects out of a Thread or a Runnable. It's quite bad idea to use activity as a monitor. It's quite bad idea to pass reference of activity anywhere.
you used different monitor objects: Thread and Activity. Use one inside thread.
It makes sense that is not working because wait() and notify() work over an object that is used as a lock. When you run wait() in your run() method, you are using an instance of CounterThread as a lock, but when you run notify() inside your onResume() method, you are using an instance of MainActivity. CounterThread will never get notified. Your alternative is (in your onResume() method):
...
synchronized(mCounterThread) {
mCounterThread.notify();
}
...
Handler hnd = new Handler() {
#Override
public void handleMessage(Message msg) {
int id = sequence.get(msg.arg1);
if(msg.arg1 % 2 == 0) {
sq.get(id-1).setBackgroundResource(R.drawable.square_show);
} else {
sq.get(id-1).setBackgroundResource(R.drawable.square);
}
}
};
#Override
public void onResume() {
super.onResume();
Thread background = new Thread(new Runnable() {
public void run() {
try {
for(int i = 0; i <= sequence.size()-1; i++) {
Thread.sleep(200);
Message msg = hnd.obtainMessage();
msg.arg1 = i;
msg.setTarget(hnd); // EDITED
msg.sendToTarget();
record_tv.setText(""+i);
}
} catch(Throwable t) {
}
}
});
background.start();
}
the code arrives to msg.sendToTarget(), does its things and then never came back
sendToTarget(); throws a null pointer exception it you have no set a receiver with setTarget(Handler).
Also, in your code I see
record_tv.setText(""+i);
this line, inside your thread will throw a
android.view.ViewRoot$CalledFromWrongThreadException