Stopping a Android service in an Activity - java

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.

Related

How can one thread tell another thread to stop?

I'm making a Service that creats a thread in the Oncreate methed. this thread is a endless loop thAT PLAYS A MP3 FILE, GOES TO SLEEP FOR 30 SECONDS.
i'M TRYING TO FIGURE OUT HOW TO stop this in the onDestroy methed
code
public void onCreate() {
Toast.makeText(this, "Service Created", Toast.LENGTH_LONG).show();
mediaPlayer = MediaPlayer.create(this, R.raw.nysound);
mThread=new myThread();
mThread.start();
}
public class myThread extends Thread {
public void run() {
do{
mediaPlayer.start();
try
{
Thread.sleep(1000*20);
} catch(Exception e)
{
ted++;
}
} while(true);
} // end methed
} // end class
#Override
public void onDestroy() {
Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
}
You could use a boolean flag for that
public class myThread extends Thread {
private volatile boolean running = true;
public void run() {
do{
mediaPlayer.start();
try
{
Thread.sleep(1000*20);
} catch(Exception e)
{
ted++;
}
} while(running);
} // end methed
public void setRunning(boolean newValue) {
this.running = newValue;
}
} //
And then do the following in main thread
#Override
public void onDestroy() {
mThread.setRunning(false);
Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
}
Calling onDestroy() is not the right way to stop Service
public void onDestroy () is called by the system to notify a Service that it is no longer used and is being removed. The service should clean up any resources it holds (threads, registered receivers, etc) at this point. Upon return, there will be no more calls in to this Service object and it is effectively dead. Do not call this method directly.
if you are in service class please call method
stopSelf();
if you are in another class, like your MusicPlayerActivity call below code
Intent i = new Intent(this, ServiceName.class);
stopService(i);
Both of these will stop your service.
You should consider using higer-level object ScheduledExecutorService to handle thread execution :
public void onCreate() { Toast.makeText(this, "Service Created", Toast.LENGTH_LONG).show();
mediaPlayer = MediaPlayer.create(this, R.raw.nysound);
ScheduledExecutorService ses =
Executors.newScheduledThreadPool(1);
scheduledFuture = ses.scheduleWithFixedDelay(new MyThread(), 0, 20, TimeUnit.SECONDS);
}
public class myThread extends Thread {
public void run() {
mediaPlayer.start();
} // end methed
} // end class
#Override
public void onDestroy() {
Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
scheduledFuture.cancel(true);
}

Android work in background

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>

Running toast in at certain interval in a service

I am trying to show a toast at 2 seconds interval from a service.
This normal code works fine. This one is just a test to show toast.
public int onStartCommand(Intent intent, int flags, int startId) {
// Let it continue running until it is stopped.
new Thread(new ToastRunner(this)).start();
return START_STICKY;
}
But the below code crashes...
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Let it continue running until it is stopped.
new Thread(new ToastRunner(this)).start();
return START_STICKY;
}
class ToastRunner implements Runnable{
Context context;
public ToastRunner(Context context){
this.context = context;
}
#Override
public void run() {
try {
while (true) {
Toast.makeText(context, "Service Started", Toast.LENGTH_SHORT).show();
Thread.sleep(2000);
}
}catch (Exception e){
Log.d("tag", e.toString() );
}
}
}
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
Try this code,
while (true) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Toast.makeText(context, "Service Started", Toast.LENGTH_SHORT).show();
}
});
Thread.sleep(2000);
}
That mean you cannot access ui element from one another thread. You must use uiThred. Try this code,
while (true) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(context, "Service Started", Toast.LENGTH_SHORT).show();
Thread.sleep(2000);
}
}
}
try like this...
#Override
public void run() {
try {
// preparing a looper on current thread
// the current thread is being detected implicitly
Looper.prepare();
// now, the handler will automatically bind to the
// Looper that is attached to the current thread
// You don't need to specify the Looper explicitly
handler = new Handler();
// After the following line the thread will start
// running the message loop and will not normally
// exit the loop unless a problem happens or you
// quit() the looper (see below)
Looper.loop();
}
catch (Throwable t) {
Log.e(TAG, "halted due to an error", t);
}
}

Stop threads created by Android Service

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();

cannot touch view from another thread, how to make it possible?

I cant figure out why i cant set text to my textView tv.
getting:
E/AndroidRuntime(686): android.view.ViewRoot$CalledFromWrongThreadException:
Only the original thread that created a view hierarchy can touch its views.
I tried many ways to make it right.
As you can see i tried Handler because i had the same problem with toasts. Now toast works but setText doesnt :((
Please someone help me, how should i configure this handler?
public class calculate extends Activity implements OnClickListener {
private myService myService; //bound service instance
private boolean serviceStarted;
View show_map;
View data;
View start;
View stop;
public TextView tv;
private Location loc;
private boolean initiated=false;
private float distance=0;
UIHandler uiHandler;
route_calc rc;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.calculate);
tv=(TextView)findViewById(R.id.textView1);
show_map=findViewById(R.id.button1);
show_map.setOnClickListener(this);
data=findViewById(R.id.button2);
data.setOnClickListener(this);
start=findViewById(R.id.button3);
start.setOnClickListener(this);
stop=findViewById(R.id.button4);
stop.setVisibility(View.INVISIBLE);
stop.setOnClickListener(this);
HandlerThread uiThread = new HandlerThread("UIHandler");
uiThread.start();
uiHandler = new UIHandler( uiThread.getLooper());
}
public void onDestroy(){
super.onDestroy();
}
#Override
public void onClick(View v) {
Intent i;
switch(v.getId()){
case R.id.button1:
i=new Intent(this,Map.class);
startActivity(i);
break;
case R.id.button2:
i=new Intent(this,data.class);
startActivity(i);
break;
case R.id.button3:
startService();
break;
case R.id.button4:
stopService();
break;
}
}
//connection between this activity and service myService
ServiceConnection myServConn = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName arg0) {
myService = null;
}
#Override
public void onServiceConnected(ComponentName arg0, IBinder binder) {
myService = ((myService.MyBinder)binder).getMyService();
}
};
private void startService() {
Intent intent = new Intent(this, myService.class);
startService(intent);
//Bind MyService here
bindService(intent, myServConn, BIND_AUTO_CREATE);
stop.setVisibility(View.VISIBLE);
serviceStarted = true;
rc = new route_calc();
rc.start();
}
private void stopService() {
if(serviceStarted) {
Intent intent = new Intent(this, myService.class);
//Unbind MyService here
unbindService(myServConn);
stopService(intent);
stop.setVisibility(View.INVISIBLE);
serviceStarted = false;
}
}
void showToast(String s){
handleUIRequest(s);
}
void setText(){
handleUISetText();
}
class route_calc extends Thread{
Location begin;
public void run() {
float temp;
while(!initiated){
try{
loc=myService.getLocation();
}
catch(Exception e){
}
if(loc!=null){
begin=loc;
initiated=true;
showToast("zadzialalo");
}
}
while(true){
loc=myService.getLocation();
temp=begin.distanceTo(loc);
distance=distance+temp;
tv.setText("przejechales "+distance+" m");
System.err.println(distance);
begin=loc;
try {
this.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private final class UIHandler extends Handler
{
public static final int DISPLAY_UI_TOAST = 0;
public static final int TV_SET_TEXT = 1;
public UIHandler(Looper looper)
{
super(looper);
}
public void handleMessage(Message msg)
{
switch(msg.what)
{
case UIHandler.DISPLAY_UI_TOAST:
{
Context context = getApplicationContext();
Toast t = Toast.makeText(context, (String)msg.obj, Toast.LENGTH_LONG);
t.show();
}
case UIHandler.TV_SET_TEXT:
{
tv.setText("przejechałeś "+distance+" m");
}
default:
break;
}
}
}
protected void handleUIRequest(String message)
{
Message msg = uiHandler.obtainMessage(UIHandler.DISPLAY_UI_TOAST);
msg.obj = message;
uiHandler.sendMessage(msg);
}
protected void handleUISetText(){
Message msg=uiHandler.obtainMessage(UIHandler.TV_SET_TEXT);
uiHandler.sendMessage(msg);
}
}
It seems like you put your entire Activity here, and that it also includes a service, and you didn't try to narrow down your problem.
in your route_calc thread you call showToast, this is probably one of your problems, you should call showToast (or any other UI function) from your Handler.
Something like this:
Do anything you want on your thread:
new Thread(new Runnable()
{
#Override
public void run()
{
try
{
someHeavyStuffHere(); //Big calculations or file download here.
handler.sendEmptyMessage(SUCCESS);
}
catch (Exception e)
{
handler.sendEmptyMessage(FAILURE);
}
}
}).start();
When your data is ready, tell the handler to put it in a view and show it:
protected Handler handler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
if (msg.what == SUCCESS)
{
setCalculatedDataToaView(); // the data you calculated from your thread can now be shown in one of your views.
}
else if (msg.what == FAILURE)
{
errorHandlerHere();//could be your toasts or any other error handling...
}
}
};

Categories