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,.
Related
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.
On executing the following code, i found that the entire app freezes for 10000ms before showing anything on the emulator's screen. I would have expected the first Toast message to appear , followed by the app to freeze for 10000ms and the second toast message to appear. makes me wonder if android piles up all the code in the 'oncreate' method before executing it. is it supposed to be that way?
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toast.makeText(this, new ServiceCode("Hi").s, Toast.LENGTH_SHORT).show();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Toast.makeText(this, new ServiceCode("Hello").s, Toast.LENGTH_SHORT).show();
}
It behaves as expected. There is a single thread responsible for UI updates. It's called main thread. This thread shows toast messages too. When you call Toast.show(), Android schedules a new task for the main thread. When main thread is done with onCreate(), it will execute this task and show the toast. But because you blocked main thread for 10 seconds, no toasts are show. There is no one free, who can show this message. But then, 10 seconds later, both toasts will appear one after another, because main thread is free to show them.
Best practice is to never block the main thread. Otherwise your application will freeze and users will see ANR (application nor responding) message. If you need to execute something later in time, you need to post this task to the main thread's task queue for been executed later.
The code below will behave as you expect.
public class MainActivity extends Activity {
private Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// show first toast immediately
Toast.makeText(this, new ServiceCode("Hi").s, Toast.LENGTH_SHORT).show();
// schedule second toast to appear 10 sec later
handler.postDelayed(new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.this,
new ServiceCode("Hello").s, Toast.LENGTH_SHORT).show();
}
}, 10000);
}
}
When an Activity is created, the system-process would send a message to the UI thread of the Activity. The UI thread of the the Activity received the message and then executes "onCreate" method.
Here you make a toast in the "onCreate" method. That will not show the toast immediately. It only sends a message to the message queue of the UI thread. After you UI thread have fininshed the "onCreate" "onStart" "onResume" method, it receives the message of "Toast". At that moment, the Toast is actually showed on the screen.
The reason is simple, the show method of the Toast class might not be a synchronous call "internally", what I mean is, the main-thread is very unlikely to wait until the Toast is actually shown and rendered to continue, hence, it might start a functionality to start rendering the Toast BUT since you immediately after that force the main-thread to stop, it doesn't handle that request since main thread have the highest priority.
Hope it helps!
Regards!
check these links to know about the Android Life-Cycle
http://developer.android.com/training/basics/activity-lifecycle/index.html
Android activity life cycle - what are all these methods for?
your creating a Splash Screen,
if not remove
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
you App won't freeze.
Try this :
Toast.makeText(this, new ServiceCode("Hi").s, Toast.LENGTH_SHORT).show();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
Toast.makeText(this, new ServiceCode("Hello").s, Toast.LENGTH_SHORT).show();
}
}
The display of Toast is an asynchronous call.Thus, once the toast request is executed, the operating system jumps to the next operation and meanwhile the toast is prepared and displayed.
In your case since the next operation blocks the UI Thread for 10 sec the toast is not displayed until the UI Thread is released.
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.