I can't get a spawned thread to stop:
I'm implementing the vibration-part of the Ringer-class in the regular Android Phone.apk (basically word for word), but after vibrating once (and stopping) correctly, the second time I call startVibration() and subsequently stopVibration(), it doesn't stop the thread (the log prints out that mVibratorThread is null, even though an instance of it is clearly still active, because the phone is vibrating :-)!)...
public volatile boolean mContinueVibrating;
public VibratorThread mVibratorThread;
private static final int VIBRATE_LENGTH = 1000; // ms
private static final int PAUSE_LENGTH = 1000; // ms
public void startVibration(){
//Start the vibration alarm
if (mVibratorThread == null) {
mContinueVibrating = true;
mVibratorThread = new VibratorThread();
Log.i(TAG, "Starting vibration...");
mVibratorThread.start();
}
}
public void stopVibration(){
//Stop the vibration alarm
Log.i(TAG, "Stopping vibration...");
if (mVibratorThread != null){
mContinueVibrating = false;
mVibratorThread = null;
Log.i(TAG, "Thread wasn't null, but is now set to null...");
} else {
Log.i(TAG, "Thread was null...");
}
}
private class VibratorThread extends Thread {
public void run() {
Vibrator mVibrator = (Vibrator) m_context.getSystemService(Context.VIBRATOR_SERVICE);
while (mContinueVibrating) {
mVibrator.vibrate(VIBRATE_LENGTH);
SystemClock.sleep(VIBRATE_LENGTH + PAUSE_LENGTH);
Log.i(TAG, "VIBRATING NOW!!" + mContinueVibrating);
}
}
}
I've already tried the method described in Where to stop/destroy threads in Android Service class?
Thanks for your help,
Nick
Please call the startVibrator and stopVibrator from a Handler
here is the tutorial for Handler http://www.tutorialforandroid.com/2009/01/using-handler-in-android.html
The issue was that the class that was referencing the Thread was being re-initiated halfway through the process, and the new instance of the class naturally had no knowledge of the thread that was initiated by its predecessor, so the reference to the thread was null. I fixed it by putting the thread in its own, singleton class.
Related
I have an app designed to record sensor data every 10ms and store into a SQLite db on the phone. I'm doing the db inserts as an async task because they happen so fast and there are so many of them that they slow down navigation noticeably. However, I'm occasionally running into problems when trying to stop the recording.
In one of my fragments there is a start stop button. Press it to record. Press it again to stop recording. The onClick looks like this:
#Override
public void onClick(View v) {
if (!recordingStarted){
recordingStarted = true;
mainActivity.startService(new Intent(mainActivity, SensorService.class));
startButton.setText(getResources().getString(R.string.start_button_label_stop));
Snackbar.make(coordinatorLayout, "Recording...", Snackbar.LENGTH_SHORT).show();
} else {
mainActivity.stopService(new Intent(mainActivity, SensorService.class));
startButton.setEnabled(false);
Snackbar.make(coordinatorLayout, "Recording stopped.", Snackbar.LENGTH_SHORT).show();
}
}
When recording is started, the SensorService class is called up. That just registers listeners, starts a service so I can collect data when the screen is off, calculates some sensor things etc. This is where my async task lies. The only interesting parts of that class are:
public class SensorService extends Service implements SensorEventListener {
public BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "onReceive("+intent+")");
if (!intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
return;
}
Runnable runnable = new Runnable() {
public void run() {
Log.i(TAG, "Runnable executing...");
unregisterListener();
registerListener();
}
};
new Handler().postDelayed(runnable, SCREEN_OFF_RECEIVER_DELAY);
}
};
public void onSensorChanged(SensorEvent event) {
sensor = event.sensor;
int i = sensor.getType();
if (i == MainActivity.TYPE_ACCELEROMETER) {
accelerometerMatrix = event.values;
} else if (i == MainActivity.TYPE_GYROSCOPE) {
gyroscopeMatrix = event.values;
} else if (i == MainActivity.TYPE_GRAVITY) {
gravityMatrix = event.values;
} else if (i == MainActivity.TYPE_MAGNETIC) {
magneticMatrix = event.values;
}
long curTime = System.currentTimeMillis();
long diffTime = (curTime - lastUpdate);
// only allow one update every POLL_FREQUENCY.
if(diffTime > POLL_FREQUENCY) {
lastUpdate = curTime;
//cut a bunch of stuff here to save space
//insert into database
new InsertSensorDataTask().execute();
}
}
#Override
public void onCreate() {
super.onCreate();
dbHelper = new DBHelper(getApplicationContext());
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
accelerometer = sensorManager.getDefaultSensor(MainActivity.TYPE_ACCELEROMETER);
gyroscope = sensorManager.getDefaultSensor(MainActivity.TYPE_GYROSCOPE);
gravity = sensorManager.getDefaultSensor(MainActivity.TYPE_GRAVITY);
magnetic = sensorManager.getDefaultSensor(MainActivity.TYPE_MAGNETIC);
PowerManager manager =
(PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = manager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
registerReceiver(receiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
}
#Override
public void onDestroy() {
unregisterReceiver(receiver);
unregisterListener();
wakeLock.release();
dbHelper.close();
stopForeground(true);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
startForeground(Process.myPid(), new Notification());
registerListener();
wakeLock.acquire();
return START_STICKY;
}
private class InsertSensorDataTask extends AsyncTask<String, String, Boolean> {
#Override
protected Boolean doInBackground(String... params) {
try {
dbHelper.insertData(Short.parseShort(MainActivity.subInfo.get("subNum")), System.currentTimeMillis(),
accelerometerMatrix[0], accelerometerMatrix[1], accelerometerMatrix[2],
accelerometerWorldMatrix[0], accelerometerWorldMatrix[1], accelerometerWorldMatrix[2],
gyroscopeMatrix[0], gyroscopeMatrix[1], gyroscopeMatrix[2]);
return true;
} catch (SQLException e) {
Log.e(TAG, "insertData: " + e.getMessage(), e);
return false;
}
}
}
}
When I hit the stop button, that will immediately call stopService in the onClick, which I believe will call onDestroy in the SensorService. However I run into conditions where stop is pressed, listeners are unregistered, databases are closed, but there are still async tasks running in the background. My guess is that they're still completing their final tasks before actually stopping. This runs me into exception territory because then the async code is trying to insert data into a database that is now closed. I could just catch those and ignore them, but I want to figure out the correct way to handle this type of situation
How should I refactor my code to allow for the async tasks to finish? Because this isn't 1 big job but rather thousands of small db insert jobs, I would have imagined they could stop rather quickly so I'm surprised that I keep running into these closed db exception problems
Is there a way to tell when all async tasks are done? Maybe I could use that as a condition in onDestroy before anything gets closed?
Or would it be worth moving away from async tasks altogether? I mostly just want to avoid running these db inserts in the main UI thread
So it could be worse than that. When you call execute(), you actually add a task to a queue. A single thread goes through the queue and runs the tasks one at a time. So you could have multiple tasks queued that won't be canceled. By the way this is 1 shared thread for all async tasks, so if you have other tasks they can also hold up things.
There's two solutions here. The first is to have an isCanceled variable at the service level that all async tasks look at at the start of doInBackground and immediately exit if that is set.
The second is I think a better solution. Create a Thread. The Thread should look like this:
while(!isCanceled) {
insertData = BlockingQueue.take()
//insert insertData
}
Your sensor data callback can then add an item to this queue, and your onStop can just cancel the thread and empty the queue.
I'm trying to use semaphores to make a thread waiting for something happening outside it with a semaphore, but I don't know why it is not working. Probably is something I don't know about Android semaphores, because I already used the same "way to operate" with some real time operating system (such as FreeRTOS and MXLite) and it works fine.
Practically I have a thread that is running a service each time it executes a while loop inside its run() method. The service execute some long operation and then die, I just want the thread not to run a new service before the previous one has finisched.
The code looks like that (condLog is just a function that doeas a Log.i with the string passed if a DEBUG define is true):
public Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
startScheduler(msg);
}
};
private static boolean serviceRunning = false;
private static Context context; // context is set in the main class contructor
private executeScheduledAction myThread = new executeScheduledAction();
private void startScheduler(Message msg) {
condLog("startScheduler- message received...");
myThread .releaseSemaphore();
}
private final class executeScheduledAction extends Thread {
private final static int MAX_CONCURRENT = 1;
private Semaphore semaphore = new Semaphore(MAX_CONCURRENT, true);
public executeScheduledAction () {}
public void releaseSemaphore() {
semaphore.release();
condLog("releaseSemaphore - Semaphore released, semaphore permit: " + semaphore.availablePermits());
}
#Override
public void run() {
condLog( "executeScheduledAction - thread started...");
serviceRunning = true;
while(serviceRunning ){
try {
condLog( "executeScheduledAction - taking semaphore, semaphore permits: " + semaphore.availablePermits() );
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
condLog("executeScheduledAction - semaphore taken, running service");
// HERE RUN THE SERVICE
}
condLog( "Thread finished...");
}
}
THe first call myThread.start method. As I expected, the semaphore is taken the first time and the service is correctly launched. At the end, service send a message to an handler that call executeScheduledAction.release...and this is what I obtain in the Logcat:
executeScheduledAction - thread started...
executeScheduledAction - taking semaphore, semaphore permits: 1
executeScheduledAction - semaphore taken, running service
executeScheduledAction - taking semaphore, semaphore permits: 0
startScheduler - message received...
releaseSemaphore - Semaphore released, semaphore permit: 2
Why is it 2 and not 1? it looks like I'm not release the same semaphore I'm acquiring...
Really, any help would be helpfull and appreciated.
Thank you all very much
Cristiano
Semaphore has to go negative to be blocking. In this case you can use a CountDownLatch. If I have not misunderstood you, it should suit better your needs.
I have to run a bit of code in the background every one second, the code will call a webservice which searches a database and returns a value to the application. My question is which method would be the most effective to do this? I have read up on Timers, Threads, AsyncTask and Services and each seem to have their pros and cons. Please can someone tell me which would be the best to use considering execution time and battery life.
Thanks
Update:
I decided to use Aysnc task to run my code in the background while using a TimeTask to trigger the AsyncTask at regular intervals. This way the operation is destroyed when I leave that particular activity
You should use the service to do the background operation but in your case you want to run code in 1 sec here is the example of service using handler it call in every 1 sec.
public class YourService extends Service {
private static final String TAG = "Your Service";
private final Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
}
};
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
// Toast.makeText(this, "My Service Created", Toast.LENGTH_LONG).show();
Log.d(TAG, "onCreate");
}
#Override
public void onDestroy() {
super.onDestroy();
// Toast.makeText(this, "My Service Stopped", Toast.LENGTH_LONG).show();
handler.removeCallbacks(sendUpdatesToUI);
}
private Runnable sendUpdatesToUI = new Runnable() {
public void run() {
/// Any thing you want to do put the code here like web service procees it will run in ever 1 second
handler.postDelayed(this, 1000); // 1 seconds
}
};
#Override
public void onStart(Intent intent, int startid) {
handler.removeCallbacks(sendUpdatesToUI);
handler.postDelayed(sendUpdatesToUI, 1000);//1 second
Log.d(TAG, "onStart");
}
}
and service can't run every time android idle the service within 3 or 4 hr i suggested you to use the foreground service to use your process long running.
For operations like this I tend to use a Service component. for the task itself i use an AsyncTask which will wait a set time before it repeats itself (using a while loop).
You will have to create a new Thread so that the call don't lock up the device if the call takes longer than expected. The AsyncTask is an easy way to use multithreading, but it lacks the functionality of repeating tasks. I would say that you are best of either using a Timer or the newer ScheduledExecutorService.
If you chose to use the Timer you create a TimerTask that you can hand it. The ScheduledExecutorService takes a Runnable instead.
You might want to wrap the thread in a Service (The Service does not provide a new Thread), but this is not always necessary depending on your needs.
As suggested in comment, you can also use the Handler.postDelayed(). Although you still need to create a new thread and then call Looper.prepare() on it:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
(Code from Looper docs)
Also; calls to a webservice every second seems way too frequent, especially if the user is on a slow connection or there are data that needs to be transferred, try to reduce the calls as much as possible.
I think it's not only one solution, so it's up to you. You can try start thread with this run method:
private final int spleeptime = 1000;
public boolean running;
#Override
public void run() {
while (running) {
try {
int waited = 0;
while ((waited < spleeptime)) {
sleep(100);
waited += 100;
}
} catch (InterruptedException e) {
} finally {
// your code here
}
}
}
I have created IntentService with infinite loop inside the onHandleIntent then add static methods start,resume,pause,stop to directly call it within my Activities.
The scenario is, inside the infinite loop, I am calling callback methods which is creating a new thread to execute long process.
The problem is, I am worrying about continuously creating Threads due to infinite loop. I am pretty sure that there is better way to manage it. I am thinking of ThreadPool or something enable to use only one thread in a sequential manner. So that, I am saving time,memory,overheads etc..
OTHER APPROACH ARE VERY WELCOME. Ask me other information as needed. Then, I will update here.
Here are my codes(take a look at SampleCallback):
IntentService
import android.app.IntentService;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
public class SampleCallbackIntentService extends IntentService {
private final String LOG_LOGCAT_TAG = "SampleCallbackIntentService";
private Handler _handler;
public SampleCallbackIntentService(String name) {
super(name);
}
#Override
public void onCreate() {
super.onCreate();
// initialize variables for pause & resume thread
_mPauseLock = new Object();
_mPaused = false;
_mFinished = false;
// initialize handler to switch to UI/Main thread
_handler = new Handler()
{
#Override
public void handleMessage(final Message msg)
{
_callback.doSomethingFromUIThread(msg);
}
};
}
private final SampleCallback _callback = new SampleCallback() {
#Override
public void doSomethingFromCurrentThread(final Object object) {
new Thread(new Runnable() {
#Override
public void run() {
//do long running process.
// I will access object here.
}
}).start();
}
#Override
public void doSomethingFromUIThread(final Message msg) {
//may update UI here.
}
};
private final int CALLBACK_MESSAGE = 1;
#Override
protected void onHandleIntent(Intent arg0) {
Log.i(LOG_LOGCAT_TAG, "loop started");
while (!_mFinished) {
// do stuff here
// create the object variable. Then pass to callback method
_callback.doSomethingFromCurrentThread(object);
// process and create the result to pass
String someResult = "some result here";
_handler.sendMessage(_handler.obtainMessage(CALLBACK_MESSAGE, someResult));
synchronized (_mPauseLock) {
while (_mPaused) {
try {
Log.i(LOG_LOGCAT_TAG, "loop paused");
_mPauseLock.wait();
Log.i(LOG_LOGCAT_TAG, "loop resumed");
} catch (InterruptedException e) {
Log.e(LOG_LOGCAT_TAG, "error occured on pause", e);
}
}
}
try {
//using sleep here might be not good design.
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e(LOG_LOGCAT_TAG, "error occured on sleep", e);
}
}
Log.i(LOG_LOGCAT_TAG, "loop ended");
}
private static Object _mPauseLock;
private static boolean _mPaused;
private static boolean _mFinished;
public static void start(Context context) {
Intent service = new Intent(context, SampleCallbackIntentService .class);
if(context.startService(service)==null) {
Log.e(LOG_LOGCAT_TAG, "Service cannot be started");
} else {
Log.i(LOG_LOGCAT_TAG, "start() called");
}
}
/**
* Call this on pause.
*/
public static void pause() {
Log.i(LOG_LOGCAT_TAG, "pause() called");
synchronized (_mPauseLock) {
_mPaused = true;
}
}
/**
* Call this on resume.
*/
public static void resume() {
Log.i(LOG_LOGCAT_TAG, "resume() called");
synchronized (_mPauseLock) {
_mPaused = false;
_mPauseLock.notifyAll();
}
}
public static void stop() {
if(_mPauseLock == null) return;
synchronized (_mPauseLock) {
Log.i(LOG_LOGCAT_TAG, "stop() called");
_mFinished = true;
}
}
}
SampleCallback
import android.os.Message;
public interface SampleCallback {
public void doSomethingFromCurrentThread(final Object object);
public void doSomethingFromUIThread(final Message msg);
}
UPDATES1
I am using location api aside from google api. I will create a android library project and use that api to get the latest location (e.g. every 2secs) in the background.
On the application side, just need to call static methods to use it (e.g. start(context, callback), pause(), resume(), stop()). It has callbacks to obtain the location. After obtaining the needed information from the location object, I will create a new thread to call my own created callbacks (which implemented by the application side).
You can use AsyncTask instead of creating a new thread every time? AsyncTask manages a fixed pool of threads (or one background thread - depending on Android version) and allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
However I wonder why do you need to create an infinite loop inside the onHandleIntent method? By doing that you prevent your IntentService from receiving further Intents. Since in IntentService:
All requests are handled on a single worker thread -- they may take as
long as necessary (and will not block the application's main loop),
but only one request will be processed at a time.
I think you want to execute some long-running code out of the UI thread in the IntentService. But that doesn't require the creation of an infinite loop in the IntentService worker thread. Just send the requests as needed to the IntentService using Context.startService(Intent) call. If you want IntentService to send back some result or just call a callback in the UI thread you can pass a Messenger (or a ResultReceiver) object with the Intent.
Activity:
final Handler uiHandler = new Handler(Looper.getMainLooper());
private void postTask() {
Intent intent = new Intent("com.yourservice.DOACTION");
intent.putExtra("messenger", new Messenger(handler));
intent.putExtra("object", YourObject()); // pass other Parcelable objects
startService(intent);
}
IntentService:
protected void onHandleIntent(Intent intent) {
Messenger messenger = intent.getParcelableExtra("messenger");
YourObject object = intent.getParcelableExtra("object");
//... do work here ...
Message msg = Message.obtain();
msg.what = CALLBACK_MESSAGE;
msg.setData(someResult);
messenger.send(Message.obtain());
}
Look into the docs for ExecutorService (not to be confused with Android Services) and the Executors package. There are a few examples there on how to use thread pools.
So wait, why do you need to use all these callbacks? Can't you just have each intent encode what needs to be done and then have your onHandleIntent execute different code based on the information of the intent. This is the way IntentService is intended to be used.
You shouldn't be doing any of the thread handling in the IntentSerivce. The IntentService is supposed to be handling all the threading code (and you should let it because it's probably highly optimized).
I'm new to android dev and I was wondering if, upon startup, will the following code start looping, check the result of connect, vibrate if 1, and then sleep for 5 minutes?
/** Called when the activity is first created. */
boolean flag = true;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
while(flag) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
String foundblock = connect("blahblahblah"); //will return either 0 or 1
if (foundblock == "1") {
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
long milliseconds = 10;
v.vibrate(milliseconds);
flag = false;
}
}
}, 300000);
}
Yeah, it'll loop. Don't expect the android process manager to keep it alive for too long though. It will also result in a ton of runnables being posted, as itll run through the while loop over and over.
This code will be forcefully terminated due to onCreate() not returning within an acceptable time limit. You can start a thread from onCreate() but you can't hang out forever.
Lose the while loop, and just postDelayed(). Your runnable can loop within it (as long as you give yourself a way to be told to terminate it!).
You might change the variable foundblock (and the return of your connect() function) to boolean or at least an int, since String is overkill for what you're describing and since string checks for equality are not performed with the == operator.
It will crash as the onCreate has a time limit. If you put the loop in a seperate thread then it will stop the application from crashing.
example:
Thread myThread = new Thread(){
public void run(){
while(flag) {
int foundblock = connect("blahblahblah"); //will return either 0 or 1
if (foundblock == 1) {
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
long milliseconds = 10;
v.vibrate(milliseconds);
flag = false;
}
}
}
};
myThread.start();
This definately works, rather than then putting this thread to sleep, just restart it after the time you want to wait has passed by calling myThread.start() again.