How to kill a thread in a service? - android

I have a service that runs whenever the screen gets turned on. When I put the phone to sleep, the service and the thread should stop.
I managed to stop the service, but the thread still runs. How can i kill the thread?
void runAppCheck(){
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
while (true) {
try {
Thread.sleep(10000);
mHandler.post(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
getForegroundApplication();
compareResults();
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
boolean screenIsOn = pm.isScreenOn();
if (!screenIsOn) {
Log.i(TAG ,"Screen is OFF, stopping service");
stopSelf();
//TODO stop thread
}
}
});
} catch (Exception e) {
// TODO: handle exception
}
}
}
}).start();

You can stop a Thread by using a shared variable that acts as a flag to ask the Thread to stop. For example, in your outer Thread, declare private volatile boolean mRunning = true and change tn the outer while(true) to while(mRunning). Then implement a method to request it to cease running:
public void terminate() {
mRunning = false;
}

I don't get your problem entirely, because the answer seem to be quite easy, unless I'm missing something.
Stopping your thread in your example seems to be as easy as calling return;, which will end the public void run() method and that will end the thread.
....
if (!screenIsOn) {
Log.i(TAG ,"Screen is OFF, stopping service");
stopSelf();
return;
}
....
Update after OP's comment:
If you are not using an AlarmManager and you can be sure that your thread still receives some CPU cycles, why do you do a mHandler.post(....) call? Why not just skip that post call.
void runAppCheck(){
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
while (true) {
try {
Thread.sleep(10000);
// TODO Auto-generated method stub
getForegroundApplication();
compareResults();
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
boolean screenIsOn = pm.isScreenOn();
if (!screenIsOn) {
Log.i(TAG ,"Screen is OFF, stopping service");
stopSelf();
//stop thread
return;
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
}).start();

Related

Handler stuck in loop within Android Service

I'm currently trying to do an app that keeps track of the phone through the GPS by using a service. in order to get the GPS to update the coordinates, I need to use a handler within the service. Right now the proble I have is that when the I do the Handler.post, it gets stuck in an loop, and after that, it completely ignores the rest of the service code.
When I was debugging, I found out that the handler was alternating messages between methods but nothing useful came out of it, it was just a loop between the same methods over and over again.
Here's my Service code that includes the handler:
public int onStartCommand(Intent intent, int flags, int startId)
{
ctx = ServicioDeFondo.this;
mHandler = new Handler();
reportarGPS = new Thread(new Runnable() { public void run()
{
try
{
while(true)
{
mHandler.post(new Runnable() {
#Override
public void run() {
gps = new GPSTrack(ctx);
latitude = String.valueOf(gps.getLatitude());
longitude = String.valueOf(gps.getLongitude());
}
});
Thread.sleep(10000);
try {
new APISendClass().execute();
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
catch (Exception e)
{
//TODO Auto-generated catch block
e.printStackTrace();
}
} });
reportarGPS.start();
return START_STICKY;
}
I"ve been stuck here all day, any help would be greatly appreciated!
With your brief description of the problem, it's hard to understand what the expected behavior is. You don't explain what GPSTrack and APISendClass do and what type of objects that are. You state "it gets stuck in a loop". It's not clear what "it" is. With the while (true) statement, the thread will loop until cancelled.
Note that Service methods, such as onStartCommand() run on the main thread. That means that your Handler() constructor associates the handler with the main thread. The runnables you post to that handler run on the main thread. Is that what you wanted?
Also note that stopping the service by stopSelf() or Context.stopService() does not kill the thread. You need to have code to cancel the thread when it is no longer needed. This is often done in onDestroy().
I took the code you posted, replaced the calls to unknown objects with Log statements and ran it. The logcat output alternated between "Get lat/long" and "APISendClass()".
Handler mHandler;
Context ctx;
Thread reportGPS;
public int onStartCommand(Intent intent, int flags, int startId){
Log.i("TEST", "onStartCommand()");
ctx = this;
// Service methods run on main thread.
// Handler constructor with no args associates Handler
// with current thread, which here is the main thread.
mHandler = new Handler();
reportGPS = new Thread(new Runnable() {
#Override
public void run() {
try {
while (true) {
mHandler.post(new Runnable() {
#Override
public void run() {
// This runnable is posted to the main thread.
// Is that what you intended?
//gps = new GPSTrack(ctx);
//latitude = String.valueOf(gps.getLatitude());
//longitude = String.valueOf(gps.getLongitude());
Log.i("TEST", "Get lat/long");
}
});
Thread.sleep(2000);
try {
//new APISendClass().execute();
Log.i("TEST", "APISendClass().execute()");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
reportGPS.start();
return START_STICKY;
}

Application skipping 600 frames

so im building this service for a application locker. it runs fine for the most part.but when i try to run the service to lock my own application(ie the app locker itself) there's a lag for like 4-5 seconds and then the lock activity launches. The logcat displays that it has skipped 600 frames and is doing too much work on the main thread. can anyone tell him how do i fix this or optimize this code
the AppActivities contains the name of activities that are to be ignored from launching the locker again when they are on top of the stack.eg the lockscreen activity to be shown to the user. The allowedapp is the last app verified by the user
public class LockerService extends Service {
String LockedApps[];
String allowedapp = null;
DataBaseHandler handler;
Intent pwdIntent = null;
ActivityManager am;
String[] AppActivities = { "com.packagename.Locker",
"com.packagename.Compare_Pattern",
"com.packagename.Captcha_Verfication",
"com.haibison.android.lockpattern.LockPatternActivity" };
private final static Handler servicehandler = new Handler() {
#Override
public void handleMessage(Message msg) {
}
};
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
handler = new DataBaseHandler(this);
am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
pwdIntent = new Intent(LockerService.this, Locker.class);
pwdIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
private Runnable checkforeground = new Runnable() {
public void run() {
handler.open();
LockedApps = handler.getPackages();
handler.close();
String packname = am.getRunningTasks(1).get(0).topActivity
.getPackageName();
String activityname = am.getRunningTasks(1).get(0).topActivity
.getClassName();
SharedPreferences sp = PreferenceManager
.getDefaultSharedPreferences(LockerService.this);
allowedapp = sp.getString("allowedapp", "anon");
// check if top application is mylocker application
if ((packname.equals("com.packagename"))
&& (allowedapp.equals("com.packagename"))) {
// do nothing
}
// check if top application is mylocker application and prevent relaunching the lockeractivity every 1.5 seconds
else if ((packname.equals("com.packagename"))
&& !(Arrays.asList(AppActivities).contains(activityname))) {
try {
Editor edit = sp.edit();
edit.putString("current_app", packname);
edit.commit();
startActivity(pwdIntent);
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else if ((Arrays.asList(LockedApps).contains(packname))
&& (allowedapp.equals(packname))) {
// do nothing
} else if ((Arrays.asList(LockedApps).contains(packname))) {
Editor edit = sp.edit();
edit.putString("current_app", packname);
edit.commit();
startActivity(pwdIntent);
}
servicehandler.postDelayed(this, 1500); // 1.5 seconds
}
};
#Override
public void onStart(Intent intent, int startId) {
servicehandler.removeCallbacks(checkforeground);
servicehandler.postDelayed(checkforeground, 1500);// 1.5 second
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
servicehandler.removeCallbacks(checkforeground);
stopSelf();
}
}
first of all as Gabe mentioned, a runnable runs on the main Thread.To solve the frames issue You'll need to create another new thread to run your code in the background.
Try this initialize executorService and LcThread and a boolean running_statusin your service.
The running_status variable is used to break the while loop of your thread so that stops looping in the back
#Override
public void onStart(Intent intent, int startId) {
running_status = true;
executorService = Executors.newSingleThreadExecutor();
servicehandler.removeCallbacks(LcThread);
LcThread = new LockerThread();
executorService.submit(LcThread);
}
create the following class
class LockerThread implements Runnable {
#Override
public void run() {
while(running_status){
//copy code from your old Runnable run method here
}
}
}
next modify the onDestroy method
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
if (executorService != null) {
executorService.shutdown();
}
running_status = false;
servicehandler.removeCallbacks(LcThread);
stopSelf();
}
hope this solves your problem
A runnable still happens on the main thread. Services do not have their own thread by default, they run on the UI thread. If you want to do heavy processing in a service, you need to use a Thread or AsyncTask, so the processing does not occur on the UI thread.

Viewpager swip delay

I'm using viewpager to show music and on swip left/right changing music according to that.When i swip viewpager it takes few sec in swip(it doesnot swip smoothly).
Code:
#Override
public void onPageSelected(int arg0) {
// TODO Auto-generated method stub
if (mCurrentPage > arg0) {
try {
Constant.position--;
musicService = new Intent(getApplicationContext(),
MusicService.class);
musicService.putExtra(Constant.NEXT, Constant.PREVIOUS);
startService(musicService);
musicService = null;
} catch (Exception e) {
e.printStackTrace();
}
} else {
try {
Constant.position++;
musicService = new Intent(getApplicationContext(),
MusicService.class);
musicService.putExtra(Constant.NEXT, Constant.NEXT);
startService(musicService);
musicService = null;
} catch (Exception e) {
e.printStackTrace();
}
}
mCurrentPage = arg0;
}
whenever I remove this code from onPageSelected, it swip smoothly. I had also putted this code inside handler but no befinits same issue.
Suggest me where I'm doing wrong and how to resolver this.
Update:
#Override
public int onStartCommand(final Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
mThread = new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
sPosition = Constant.position;
if (intent != null) {
try {
mPrevious = (String) intent.getExtras().get(
Constant.NEXT);
System.out.println("value of previous=" + mPrevious);
if (mPrevious.equalsIgnoreCase(Constant.PLAY)) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
cancelNotification();
} else {
mediaPlayer.start();
buildNotification(title, album);
}
} else if (mPrevious
.equalsIgnoreCase(Constant.PREVIOUS)) {
playPrevious();
} else if (mPrevious.equalsIgnoreCase(Constant.NEXT)) {
playNext();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
});
mThread.start();
return START_NOT_STICKY;
}
From the guide topic Services:
Caution: A services runs in the same process as the application in which it is declared and in the main thread of that application, by default. So, if your service performs intensive or blocking operations while the user interacts with an activity from the same application, the service will slow down activity performance. To avoid impacting application performance, you should start a new thread inside the service
Make sure your music service starts a thread to delegate work to.

While Loop inside Thread not working?

I have a very simple UI and i need to constantly run a check process, so I am trying to use a Thread with a while loop.
When I run the loop with nothing but a Thread.sleep(1000) command, it works fine, but as soon as I put in a display.setText(), the program runs for a second on the emulator then quits. I cannot even see the error message since it exits so fast.
I then took the display.setText() command outside the thread and just put it directly inside onCreate, and it works fine (so there is no problem with the actual command).
here is my code, and help will be greatly appreciated.
Thank you!
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
on=(Button) findViewById(R.id.bon);
off=(Button) findViewById(R.id.boff);
display=(TextView) findViewById(R.id.tvdisplay);
display2=(TextView) findViewById(R.id.tvdisplay2);
display3=(TextView) findViewById(R.id.tvdisplay3);
stopper=(Button) findViewById(R.id.stops);
stopper.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(boo=true)
{
boo=false;
display3.setText("System Off");
}
else{
boo=true;
}
}
});
Thread x = new Thread() {
public void run() {
while (boo) {
display3.setText("System On");
try {
// do something here
//display3.setText("System On");
Log.d(TAG, "local Thread sleeping");
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e(TAG, "local Thread error", e);
}
}
}
};
display3.setText("System On");
display3.setText("System On");
x.start();
}
You can't update the UI from a non-UI thread. Use a Handler. Something like this could work:
// inside onCreate:
final Handler handler = new Handler();
final Runnable updater = new Runnable() {
public void run() {
display3.setText("System On");
}
};
Thread x = new Thread() {
public void run() {
while (boo) {
handler.invokeLater(updater);
try {
// do something here
//display3.setText("System On");
Log.d(TAG, "local Thread sleeping");
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e(TAG, "local Thread error", e);
}
}
}
};
You could also avoid a Handler for this simple case and just use
while (boo) {
runOnUiThread(updater);
// ...
Alternatively, you could use an AsyncTask instead of your own Thread class and override the onProgressUpdate method.
Not 100% certain, but I think it is a case of not being able to modify UI controls from a thread that did not create them?
When you are not in your UI thread, instead of display3.setText("test") use:
display3.post(new Runnable() {
public void run() {
display3.setText("test");
{
});
You should encapsulate this code in an AsyncTask instead. Like so:
private class MyTask extends AsyncTask<Void, Void, Void> {
private Activity activity;
MyTask(Activity activity){
this.activity = activity;
}
protected Long doInBackground() {
while (true){
activity.runOnUiThread(new Runnable(){
public void run(){
display3.setText("System On");
}
});
try{
Thread.sleep(1000);
}catch (InterruptedException e) {
Log.e(TAG, "local Thread error", e);
}
}
}
Then just launch the task from your onCreate method.
In non-UI thread,you can't update UI.In new Thread,you can use some methods to notice to update UI.
use Handler
use AsyncTask
use LocalBroadcast
if the process is the observer pattern,can use RxJava

how to stop infinite loop threads from android service?

i am working with threads in sample application.In my application i have used 3 threads are running in infinite loop.These 3 threads are used in android service class.when i am starting these threads then the threads are running and UI is not allowing until completion of infinite loop.but how can i stop the threads and how can i handle UI?
i have written a service class as follows:
ServiceApp.java
public class ServiceApp extends Service
{
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
while(true)
{
Thread child1=new Thread(new Runnable() {
#Override
public void run() {
try {
function1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
child1.start();
Thread child2=new Thread(new Runnable() {
#Override
public void run() {
try {
function2();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
});
child2.start();
Thread child3=new Thread(new Runnable() {
#Override
public void run() {
try {
function3();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
child3.start();
Toast.makeText(ServiceApp.this, "All threads started", Toast.LENGTH_SHORT).show();
}
}
public void function1() throws InterruptedException
{
Generic generic=new Generic(); //this for connect to web services
String add=generic.getAdd(10,20);
Log.v("function1", "addition from service"+add);
Thread.sleep(1000);
}
public void function2() throws InterruptedException
{
Generic generic=new Generic(); //this for connect to web services
String sub=generic.getSub(34,20);
Log.v("function2", "subtraction from service"+sub);
Thread.sleep(1000);
}
public void function3() throws InterruptedException
{
Generic generic=new Generic(); //this for connect to web services
String mul=generic.getMul(4, 6);
Log.v("function3", "multipicationn from service"+mul);
Thread.sleep(1000);
}
}
how can i stop child1,child2,child3 threads from activity class?
please any body help me?
Service.onCreate() is executed inside the UI thread. You have an infinite loop there, that continuously creates more and more threads, so UI doesn't get a chance to respond to user's actions. If you actually intend to have so many threads, you need to create another thread that would start the original three.
Activity can communicate with the service either via Binder (you'll need to return an actual implementation instead of null there) or by sending intents, which you can capture and process in Service.onStart()

Categories

Resources