I have a class which initiates a sensor listener when it is started. This listener writes the latest sensor value to a variable when an event is triggered. The class goes on to do some logic, and at some point, will check this variable and proceed depending on the value.
My issue is that there's no guarantee that there is any value when the variable is read, since Android sensor listeners only trigger an event when the sensor value changes (and don't necessarily trigger an event as soon as they are started).
Thus, I need my app to wait for an event to trigger so that it has data to work off (preferably with a time-out, to ensure that it doesn't wait indefinitely).
My question is, what's the best way to implement this wait? Should I have a handler that checks every X milliseconds for a value before proceeding? Should I have some sort of message passing between the listener and the handler to tell it when data has been written, and that it can now resume? Are there other options which are better?
EDIT: I should point out, the class logic is executed on the UI thread.
I am using Handler for exactly same situation.
Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
try {
x1.setText(String.valueOf(sensors.getValueAccX()));
Log.d("Sensors", String.valueOf(sensors.getValueAccZ()));//using persoanl methods that are not shown here
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
Toast.makeText(ClientSideActivity.this,
"Server is not running", Toast.LENGTH_LONG).show();
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO Auto-generated method stub
handler.postDelayed(this, 100);
}
});
This is not strictly related to android, but also general java question. Mechanism to implement this is container in java.lang.Oject. Assuming you have some guard object, where producer and consumer threads have access. On consumer thread you call:
guard.wait(some_optional_delay_Look_into_javadoc);
Then cosumer thread will wait until timeout ocurs or hell frozes out or producer thread issues:
guard.notify[All]();
(read documentation)
Your service listener will be producer.
Related
I need to have a background thread that works indefinitely. I've wrote this code to define an IntentService:
public class RecordInternetUsageService extends IntentService {
public RecordInternetUsageService() {
super("test");
// TODO Auto-generated constructor stub
}
#Override
protected void onHandleIntent(Intent intent) {
synchronized (this) {
try {
wait(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Toast.makeText(this, "test", Toast.LENGTH_LONG).show();
}
}
I have two questions, Is it a suitable class to do works indefinitely in background?
Why when I want to sleep this thread using by wait() method, Throws me an exception that mentioned below?
"sending message to a Handler on a dead thread".
And how can I solve this problem?
To do long processing task even when your application is closed i.e. in background one has to use Service... but you can do long processing work on that Main thread of Service or else you get ANR(android not responding). So you have to make a background thread and submit all the task on that background thread(That is done by Handle class) and handle all submitting and responding stuff... to wrap up this design pattern IntenServcie class is offered.
IntentService class automatically invokes the thread when a job is submitted and when the job is completed it kills the sevrice and frees up the memory. IntentSerive Exits as soon as it is done with its job.
The problem here is that you are creating a Toast inside a thread that is managed by the IntentService. The system will use the Handler associated with this thread to show and hide the Toast.
First the Toast will be shown correctly, but when the system tries to hide it, after the onHandleIntent method has finished, the error "sending message to a Handler on a dead thread" will be thrown because the thread in wich the Toast was created is no longer valid,.
I simply have a button in my application where onClick, I need it to start collecting gps points and do some process with it and on click again, i need it to stop that process.
Collected points will be pushed into an sqlite database while the thread is running and also I will draw lines on my map while the button is activated using collected gps points.
My problem is how to implement that thread and which way would be safest.
Extending AsyncTask class seems to be a robust solution but it runs only once and I need this thread to be available just like a toggle button for numerous times.
I tried the following test to see if I can maintain a simple thread in my app but it doesnt work. I cant use stop() method.
After I started my thread however and stopping by falsifying the controller in while loop, start() method to start it again just crashes.
class RunBuffer implements Runnable{
#Override
public void run() {
// TODO Auto-generated method stub
while(toggleBufferIsActive){
try {
Thread.sleep(1000);
test++;
Log.v("Thread running", String.valueOf(test));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
and my toggle button is implemented as follows:
public void ToggleBuffer(View view) {
if(this.toggleBufferIsActive){
this.locationManager.removeUpdates(this.locationListener);
this.gpsLatLongCollectionSize = 0;
// TODO stop collecting and drawing buffer polygon thread
this.toggleBufferIsActive = false;
}
else{
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0,
0, locationListener);
// TODO start collecting and drawing buffer polygon thread
this.toggleBufferIsActive = true;
runBuffer.start(); // crashes here
}
}
my runBuffer object is of type RunBuffer and instantiated in my onCreate() method in my activity.
any suggestion would be appreciable.
my runBuffer object is of type RunBuffer and instantiated in my
onCreate() method in my activity.
it is not possible. runBuffer can not be an instance of RunBuffer, since it extends Runnable. So you are probably wrapping this in a Thread. Something like:
Thread runBuffer = new Thread(new RunBuffer());
runBuffer.start();
Let's hypothesize the after you set
this.toggleBufferIsActive = false;
the while loop ends correctly. In this case, you are trying to restart, which can not be done. An extract of the Thread.start() method from the doc:
It is never legal to start a thread more than once. In particular, a
thread may not be restarted once it has completed execution.
I have some asynctasks in my application that do network functions (download/upload files,http requests) in the background.While these actions are in progress I use ProgressDialog in order to display messages about the progress of the task. However some tasks may require more time to complete (for example downloading a file on a slow network) and this is something unwanted in the application.
How can I set a parameter to control the duration of each asynctask? I want the asynctask to complete at some point regardless of the completion of the job in the task. I have to make the asynctask call the onPostExecute method.
I read about this http://developer.android.com/reference/android/os/AsyncTask.html#get%28long,%20java.util.concurrent.TimeUnit%29
This was not very helpful because the UI would freeze and there was no actual control of the duration of the asynctask
This is a part of my code
public void downloadFiles(String address) {
String mainUrl =address;
//// I overrride the onPostExecute to get
/// results and call another asynctask
new Downloader(this){ //<--asynctask
#Override
protected void onPostExecute(String result){
super.onPostExecute(result);
TestResults=result;
//another method called that creates another asynctask
uploadFiles(mainUrl);
}
}.execute(mainUrl);
}
I also tried to use a Handler like this
But it didn't work either.
Is there a way to make the asynctask return results (which means to make asynctask call onPostExecute method) after a period of time ?
Using a while loop in the doInBackground method of asnctask is not the solution. I guess I need a timer from the mainUI to make the asynctask return results.
PS I have my application using fragments, that is why I call new Downloader(this) to pass the gui from the fragment.
Just tried this:
public void downloadFiles(String address) {
String mainUrl =address;
final Downloader tempObject =new Downloader(this){
#Override
protected void onPostExecute(String result){
super.onPostExecute(result);
downloadResults=result;
}
};
try {
tempObject.execute(mainUrl).get(3000L, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
This would make the UI freeze for 3 seconds and then the task would be evoked.... Which is not what I want.
Also tried out this:
Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
#Override
public void run() {
if ( tempObject.getStatus() == Downloader.Status.RUNNING )
tempObject.cancel(true);
}
}, 5000 );
This would cause the message of onProgressUpdate of asynctask to stop, however the asynctask keeps running....
Any ideas ?
The methodology of the Handler function needs something additional to work. The solution to the problem lies here
AsyncTask may be canceled, however the doInbackground method is still running. Actually the task is set to value "cancel", but the doInbackgroung will still be running until it finishes. To solve this we must periodically check within a loop in doInbackground to see whether the task was set to cancel. Although this is not exactly what I wanted to do, this seems to be the only solution.
In doInBackground we have to check for the status of the task to see whether it was cancelled or not. So actually ,someone could just have the timer inside the doInbackground and make life easier without using the handler class.
I find it disappointing that one can not just terminate the execution of a synctask at will..... If anyone has a better idea, please let me know.
I must use Thread in an Android project. Sometimes, it works corectly, however sometimes does not; it does not start (does not call SendToServer() method)or it starts but return to another function suddenly (return updated; line)before the thread does not finish.
Note: affected value is bigger than 0, it gives condition and it goes to if statement.
Here is the my code sample;
public static Boolean MyUpdateFunction(MyObject myobject){
Boolean updated=false;
//Code for updating local database
int affected= SqliteDb.update(....);
if(affected>0)
{
//Send updated data to server
//For this I must use Thread(I can't use AsyncThread)
updated=true;
SendToServer();
}
return updated;
}
public static void SendToServer()
{
try{
;
Thread th=new Thread(new Runnable() {
public void run() {
try {
//Create data and send it to server
//.......
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
th.start();
th.join();
}
catch(SQLException e)
{
Toast.makeText(myContext,"ERROR: "+e.getMessage(), Toast.LENGTH_LONG).show();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Other people are correct in that an AsyncTask is the way forward, but the direct problem due to what you're experiencing is this (and as such, I would recommend reading up on how Threading works):
When you start the thread, it begins a new process. The UI thread (which is generally where the majority of your code is) continues. So your code will fire the thread with SendToServer(), and then by definition will immediately return updated, as the UI thread immediately goes to the next line.
What you need is a callback from your Thread, which is handled in the onPostExecute() method of an AsyncTask. There's a good tutorial on how to use them and what they do here
Edit:
I've just seen from a comment above that you can't use Asynctasks, fair enough, but you still need a callback/event fired from your Thread to return any results
Instead of using threads and your variables (updated and affected), you can use AsyncTasks: see: http://developer.android.com/reference/android/os/AsyncTask.html
With AsyncTask, you have some methods which are doing exactly what you want:
onPreExecute
doInBackground
onPostExecute
So, what you can do is to check your condition in onPreExecute, then do your SendToServer in the doInBackground and onPostExecute do what you need.
My service needs to check for something every minute and
while(true)
{
Thread.sleep(60000)
//REST OF CODE HERE//
}
is not working. Making the application freeze and asking me to forcefully stop it.
I am sure the problem is with the while loop but I thought it was the only way to infinitely repeat the service whenever the onStart() method executes.
Any suggestions are appreciated.
EDIT
I fixed it and in case you were wondering how the code looks like well there you go:
#Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
super.onStart(intent, startId);
Toast.makeText(this, "Service running", Toast.LENGTH_SHORT).show();
handler = new Handler(){
#Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
Toast.makeText(protectionService.this, "5 secs has passed", Toast.LENGTH_SHORT).show();
}
};
new Thread(new Runnable(){
public void run() {
// TODO Auto-generated method stub
while(true)
{
try {
Thread.sleep(5000);
handler.sendEmptyMessage(0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
}
Basically the service is been called and the tasks of that service will be repeated every 5 secs in that case.
I would like to thank vineetska, Janusz and inazaruk for suggesting to use Handlers. I would like to thank everyone who answered as well, your help was very much appreciated.
create a thread in your service and put while loop there like this:
new Thread(new Runnable(){
public void run() {
// TODO Auto-generated method stub
while(true)
{
Thread.sleep(60000)
//REST OF CODE HERE//
}
}
}).start();
Each of lifecycle method of service is called from UI thread. If you need background task to be running all the time, you can crate new thread for this. This is actually very well described in documentation.
In your case however, you should consider using AlarmManager instead. It handles recurring events very well and was specifically designed for similar scenarios.
Another solution would be to use Handler and its postDelayed() function. This can be used when your operation (that should be executed every 60s) is not time-consuming (or otherwise you should still run it in background thread).
Overall, creating a thread that sleeps all the time is not a good solution for mobile devices. This consumes resources that could've been spent for something more useful. Especially considering a rich set of capabilities of Android for recurring events.
A service itself is not a subthread. This means that every code that is run in your service will be run on the main UI Thread. You need to start a Thread, or use an AsyncTask in your service to move the computation to the background.
Have a look at the documentation of service for more information.
If you want to repeat some code every minute you can use a handler.
A handler has a method called postDelayed this allows you to specify a time after which a runnable will be run. Just call the method again at the end of your runnable to rerun the code after a minute.
Services run on the main thread. If you want to offload processing, you have to start a separate thread. Have a look at IntentService, it does this by default. On another note, having an infinitely running service with sleep() might not a good idea. For scheduled processing, you might want to use AlarmManager.
As Janusz wrote, you can use handler to post delayed. Here is a sample:
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
// Do repeatable stuff
handler.postDelayed(this, DELAYED_TIME);
}
};
handler.post(runnable);
It will post runnable and then post it again and again after DELAYED_TIME.