I currently have an app which when a button is pressed starts a service and within the service a thread is created.
I then have a second button (which appears once the first it pressed) that should shut down the service and in turn kill the thread, below is my current code however the service seems to stop but the thread keeps going.
public class MainActivity extends Activity {
private static Button lock = null;
private static Button unlock = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lock = (Button) this.findViewById(R.id.lock);
unlock = (Button) this.findViewById(R.id.unlock);
lock.setOnClickListener(btn_lock);
unlock.setOnClickListener(btn_unlock);
unlock.setVisibility(View.VISIBLE);
lock.setVisibility(View.GONE);
text.setVisibility(View.GONE);
startService(new Intent(this, MainService.class));
}
private OnClickListener btn_lock = new OnClickListener() {
public void onClick(View v) {
unlock.setVisibility(View.VISIBLE);
lock.setVisibility(View.GONE);
startService(new Intent(MainActivity.this, MainService.class));
}
};
private OnClickListener btn_unlock = new OnClickListener() {
public void onClick(View v) {
unlock.setVisibility(View.GONE);
lock.setVisibility(View.VISIBLE);
stopService(new Intent(MainActivity.this, MainService.class));
}
};
}
And then my service class looks like:
public class MainService extends Service {
Thread 1Thread;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
1Thread = new Thread() {
public void run() {
while(true){
try {
Thread.sleep(180000); // 3 minutes
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.i("TEST", "Thread is still here!");
}
}
};
}
#Override
public void onDestroy() {
1Thread.interrupt();
}
#Override
public void onStart(Intent intent, int startId) {
1Thread.start();
}
}
Hope someone can help and if you need any more info let me know!
boolean mStatus = true;
#Override
public void onCreate() {
1Thread = new Thread() {
public void run() {
while (mStatus) {
try {
Thread.sleep(180000); // 3 minutes
} catch (InterruptedException e) {
e.printStackTrace();
continue;
}
Log.i("TEST", "Thread is still here!");
}
};
}
#Override
public void onDestroy() {
mStatus = false;
1Thread.interrupt();
}
Your thread is not handling interrupt, in while loop in each iteration check if thread is interrupted, if so then do not continue the loop:
while(!Thread.currentThread().isInterrupted()){
try {
Thread.sleep(180000); // 3 minutes
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
break; //BREAK here, as thread was interrupted
}
Log.i("TEST", "Thread is still here!");
}
Also on click of second button, you should interrupt this thread:
1Thread.interrupt();
Related
Sir Please help me to add a thread that starts on a button click and ends the thread with another button click. In between I have a sound playing till the thread stops.
You can try this simple code:
final volatile boolean toExit = false;
final Thread t = new Thread(new Runnable() {
#Override
public void run() {
while(!toExit){
// Your code
Thread.sleep(100);
}
}
});
findViewById(R.id.button1).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
t.start();
}
});
findViewById(R.id.button2).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
toExit = true;
}
});
The thread will stop after button2 clicked and run to while(!toExit).
Threads stop method is deprecated.
The best solution will be having a boolean variable in the run method.
Your Thread:
public class MyThread implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);
private volatile boolean running = true;
public void terminate() {
running = false;
}
#Override
public void run() {
while (running) {
try {
//Your code that needs to be run multiple times
LOGGER.debug("Processing");
} catch (InterruptedException e) {
LOGGER.error("Exception", e);
running = false;
}
}
}
}
In your Activity:
MyThread t=new Thread();
findViewById(R.id.button1).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
t.start();
}
});
findViewById(R.id.button2).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
t.terminate();
}
});
Use Below Code
public class SomeBackgroundProcess implements Runnable {
Thread backgroundThread;
public void start() {
if( backgroundThread == null ) {
backgroundThread = new Thread( this );
backgroundThread.start();
}
}
public void stop() {
if( backgroundThread != null ) {
backgroundThread.interrupt();
}
}
public void run() {
try {
Log.i("Thread starting.");
while( !backgroundThread.interrupted() ) {
doSomething();
}
Log.i("Thread stopping.");
} catch( InterruptedException ex ) {
// important you respond to the InterruptedException and stop processing
// when its thrown! Notice this is outside the while loop.
Log.i("Thread shutting down as it was requested to stop.");
} finally {
backgroundThread = null;
}
}
Hope this will help you
I got 3 activities ( A , B ,C ) and a service that I call to check if I got new messages from DB. It's a HTTP request . I need to make the request each 15 sec.
Thread t = new Thread() {
#Override
public void run() {
try {
while (!isInterrupted()) {
Thread.sleep(15000);
runOnUiThread(new Runnable() {
#Override
public void run() {
// Here i call
}
});
}
} catch (InterruptedException e) {
}
}
};
t.start();
How to make it work when i am changing activities ?
Option: Consider changing setup to have three fragments as your original activities, and a MainActivity that controls the repeat polling for messages to DB, as well as controlling the fragments.
#SuppressLint("SimpleDateFormat")
public class AlarmService extends Service {
private PendingIntent pendingIntent;
Handler mHandler;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
}
public void f() {
Toast t = Toast.makeText(this, "Service is still running",
Toast.LENGTH_SHORT);
t.show();
};
}
#Override
#Deprecated
public void onStart(Intent intent, int startId) {
Toast t = Toast.makeText(this, "Service started", Toast.LENGTH_SHORT);
t.show();
// TODO Auto-generated method stub
super.onStart(intent, startId);
mHandler = new Handler();
Runnable r = new Runnable() {
#Override
public void run() {
f();
mHandler.postDelayed(this, 20000);
}
};
mHandler.postDelayed(r, 20000);
}
}
and in manifest use this
<service android:name="com.example.yourservice"></service>
In my application I have a button and when it gets clicked I start a new thread and change the text of button. If I press the button again it will start changing its text faster.
I would like to interrupt the thread when the button is pressed in the second time. What's the correct way to do it?
public class TestActivity extends Activity {
Button btn;
int i = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
runThread();
}
});
}
private void runThread() {
new Thread() {
public void run() {
while (i++ < 1000) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
btn.setText("#" + i);
}
});
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
In this case, just keep a reference to your thread and use Thread.interrupt():
private Thread runThread() {
return new Thread() {
public void run() {
while (i++ < 1000) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
btn.setText("#" + i);
}
});
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Then:
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (myThread != null) myThread.interrupt();
myThread = runThread();
myThread.start();
}
});
Read this post for more info and options:
How to properly stop the Thread in Java?
In my opinion, the best way would be using a variable to control this.
Something like:
while(i++ < 1000 && keepRunning)
I see that as a good solution because it cant cause unexpected behavior, as you are sure the exactly moment your thread would exit.
extra--
As a suggestion, I also would recommend you to set your thread non-Damon (setDaemon(false)) because it makes layout changes
Also it is a good practice to give thread a name (setName()) to make it easy on debugging.
Right now you start a new Thread each time you press the button.
Something like this should work.
public class TestActivity extends Activity {
Button btn;
int i = 0;
Thread countThread = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
countThread = new Thread() {
public void run() {
while (i++ < 1000) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
btn.setText("#" + i);
}
});
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
runThread();
}
});
}
private void runThread() {
if(countThread != null) {
if(countThread.isAlive()) {
countThread.stop();
} else {
countThread.start();
}
}
}
I only had a text editor so I can't guarantee if this solves your problem.
You can use thread.interrupt() to interrupt the thread.
Try this, Just take another variable j and it will handle your code:-
public class TestActivity extends Activity {
Button btn;
int i = 0,j=0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
j=1;
runThread();
}
});
}
private void runThread() {
new Thread() {
public void run() {
while (i++ < 1000) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
if(j==1){
btn.setText("#" + i);
j=0;
}
else
Thread.interrupted();
}
});
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
You can use normal Thread in Android (and call interrupt() for your use case) but frameworks provides other better options by providing helper classes around Threads. You can refer to official documentation page for other options.
HandlerThread is preferred option. You can call quitSafely() or quit() for your use case if you go for HandlerThread
Related post:
Why use HandlerThread in Android
I'm developing an application. When i exit from the application, it will be opened again (The first activity is called again and again). So i couldn't able to exit from it.
In some other activities I use EXIT button and proper code to exit. Even when I click the EXIT button on those activities, it will start login activity. (login page is opened)
In my application, I use
1) Main
2) ScreenActivity
3) Login
flow: (from main->screenActivity->login)
The start page (1st activity) is posted below
public class main extends Activity {
static ConnectivityManager conMgr;
BackgroundThread backgroundThread;
TextView myText;
boolean myTextOn = true;
Cursor cursor;
String response="";
public SQLiteAdapter mySQLiteAdapter;
private SQLiteDatabase sqLiteDatabase;
SimpleCursorAdapter cursorAdapter;
public class BackgroundThread extends Thread {
boolean running = false;
void setRunning(boolean b){
running = b;
}
#Override
public void run() {
// TODO Auto-generated method stub
//super.run();
while(running){
try {
sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch(Exception e)
{
}
handler.sendMessage(handler.obtainMessage());
}
}
}
Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
//super.handleMessage(msg);
if (myTextOn){
myTextOn = false;
myText.setVisibility(View.GONE);
}
else{
myTextOn = true;
myText.setVisibility(View.VISIBLE);
}
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.thread);
myText = (TextView)findViewById(R.id.mytext);
}
#Override
protected void onStart() {
conMgr = (ConnectivityManager)getSystemService(CONNECTIVITY_SERVICE);
// TODO Auto-generated method stub
super.onStart();
if(isInternetAvailable())
{
Toast.makeText(this, "online", Toast.LENGTH_LONG).show();
startActivity(new Intent(main.this, ScreenActivity.class));
}
else{
startActivity(new Intent(main.this, splashscreen.class));
Toast.makeText(this, "offline", Toast.LENGTH_LONG).show();
}
backgroundThread = new BackgroundThread();
backgroundThread.setRunning(true);
backgroundThread.start();
}
private boolean isInternetAvailable() {
ConnectivityManager cm=(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnectedOrConnecting()) {
return true;
}
return false;
}
#Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
boolean retry = true;
backgroundThread.setRunning(false);
while(retry){
try {
backgroundThread.join();
retry = false;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch(Exception e)
{
}
}
}
public void onDEstroy()
{
super.onDestroy();
}
}
ScreenActivity:
public class ScreenActivity extends Activity implements AnimationListener {
private TextView animatedView3;
//ImageView image;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
/* Animation animation1 = AnimationUtils.loadAnimation(this,
R.anim.anima);
animation1.setAnimationListener(this);
View animatedView1 = findViewById(R.id.aet1);
animatedView1.startAnimation(animation1);
/** set time to splash out */
final int welcomeScreenDisplay = 9000;
/** create a thread to show splash up to splash time */
Thread welcomeThread = new Thread() {
int wait = 0;
#Override
public void run() {
try {
super.run();
/**
* use while to get the splash time. Use sleep() to increase
* the wait variable for every 100L.
*/
while (wait < welcomeScreenDisplay) {
sleep(100);
wait += 100;
}
} catch (Exception e) {
System.out.println("EXc=" + e);
} finally {
/**
* Called after splash times up. Do some action after splash
* times up. Here we moved to another main activity class
*/
startActivity(new Intent(ScreenActivity.this,
login.class));
}
}
};
welcomeThread.start();
}
public void onAnimationStart(Animation animation) {
}
public void onAnimationEnd(Animation animation) {
//Toast.makeText(this, "Animation ended", Toast.LENGTH_SHORT).show();
if (animatedView3.getVisibility() == View.VISIBLE) {
animatedView3.setVisibility(View.INVISIBLE);
} else {
animatedView3.setVisibility(View.VISIBLE);
}
}
public void onAnimationRepeat(Animation animation) {
// Toast.makeText(this, "Animation rep", Toast.LENGTH_SHORT).show();
}
}
Please can anyone explain about the problem and how to solve it? I didn't understand.
Place finish() in your loginActivity and for other Activities as well else stack will store the list of visited Activities.
I'm having trouble STOPPING the StimulationService , I'm not sure if i'm calling the stopservice method correctly from my activity.
Any help will be much appreciated.
Activity to start and stop Service
public class Stimulation extends Activity implements OnClickListener {
private static final String TAG = "StimulationActivity";
Button buttonStart, buttonStop;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(com.someapp.Activities.R.layout.stimulation);
buttonStart = (Button) findViewById(com.someapp.Activities.R.id.ButtonStart);
buttonStop = (Button) findViewById(com.someapp.Activities.R.id.ButtonStop);
buttonStart.setOnClickListener(this);
buttonStop.setOnClickListener(this);
}
public void onClick(View src) {
switch (src.getId()) {
case com.someapp.Activities.R.id.ButtonStart:
Log.d(TAG, "onClick: starting service");
startService(new Intent(this, StimulationService.class));
break;
case com.someapp.Activities.R.id.ButtonStop:
Log.d(TAG, "onClick: stopping service");
stopService(new Intent(this, StimulationService.class));
break;
}
}
}
}
Service
public class StimulationService extends Service {
private static final String TAG = "StimulationService";
private IOIO ioio_;
private DigitalOutput led
private volatile IOIOThread ioio_thread_;
public IBinder onBind(Intent intent) {
return null;
}
public void onCreate() {
Toast.makeText(this, "My Service Created", Toast.LENGTH_LONG).show();
Log.d(TAG, "onCreate");
}
public void onDestroy() {
Toast.makeText(this, "My Service Stopped", Toast.LENGTH_LONG).show();
Log.d(TAG, "onDestroy");
ioio_thread_.stop();
}
public void onStart(Intent intent, int startid) {
Toast.makeText(this, "My Service Started", Toast.LENGTH_LONG).show();
Log.d(TAG, "onStart");
ioio_thread_ = new IOIOThread();
ioio_thread_.start();
}
public void onStop(Intent intent, int stopid) {
Log.d(TAG, "stop()");
ioio_thread_ = null;
}
class IOIOThread extends Thread {
private IOIO ioio_;
private DigitalOutput led;
/** Thread body. */
public void run() {
Thread thisThread = Thread.currentThread();
super.run();
while (ioio_thread_ == thisThread) {
ioio_ = IOIOFactory.create();
try{
Log.d(TAG, "Wait for IOIO Connection");
ioio_.waitForConnect();
Log.d(TAG, "IOIOConnected");
while (true) {
intializePins();
Log.d(TAG, "Pins Intialized");
while(true){
led.write(false);
sleep(2000);
led.write(true);
sleep(2000);
}
}
}
catch (ConnectionLostException e) {
} catch (Exception e) {
Log.e("Hello", "Unexpected exception caught", e);
ioio_.disconnect();
break;
} finally {
try {
ioio_.waitForDisconnect();
} catch (InterruptedException e) {
}
}
}
}
}
First, as #Waqas notes, there is no onStop() method. There is an onDestroy() method, which will be called after stopService() is called.
Second, you are not stopping the background thread ever. Simply setting the ioio_thread_ data member to null does not stop the thread. That thread will keep running forever. Please do not do this. If nothing else, use an AtomicBoolean instead of a hardwired true in your while() loop, and flip that AtomicBoolean to false in onDestroy().
Your activity is OK. The problem is that the service is not killing the IOIOThread.
Thread.stop() is deprecated and will not do what you want anyway.
What you want is to call ioio_.disconnect() from the service's onStop() (through a method on your thread class), and then join() the thread.
See AbstracIOIOActivity as an example. With minor modifications it can be turned into AbstractIOIOService, and will enable you to leave you application-specific logic in a subclass.