CONTEXT
We have this activity method, called at onCreate starting a Thread :
public void retrieveInfoFromFB(){
new Thread(new Runnable(){
#Override
public void run() {
getMyPersonalInfo();
getMeEvents();
}}).start();
}
getMyPersonalInfo() and getMeEvents() do a Request to Facebook both like that:
if (session!=null && session.isOpened()){
Request request=new Request(session,"/fql",params, HttpMethod.GET,new Request.Callback() {
public void onCompleted(Response response){
// do something with response
}
});
Request.executeAndWait(request);
}
PROBLEM
When the connection is low (not absent, just very low) we have this Thread "working" forever without stopping after a while, yes we already tried to use a RequestBatch with setTimeout(milliseconds) for the Requests, but this seemed not to work.
QUESTION
Is there a way to stop the "retrieveInfoFromFB" thread after (let's say) 10 seconds, while is still waiting for the response from Facebook requests?
p.s
I searched in stackoverflow questions, it seems that all the methods like myThread.destroy() or myThread().interrupt(), are deprecated. And we can't use a while with a flag to do these two request because they must be done just once.
Thank you for your patience.
There is no way to stop the thread communicating with FB (unless you stop the process). However, you can ask the thread to stop itself.
For that you need the FB thread to periodically check if any other process or thread asked it to stop working.
Check out this tutorial on threads: http://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html, but basically you want this:
// communicating with FB
try {
Thread.sleep(1000); sleep one second to give other threads a chance
} catch (InterruptedException e) {
// We've been interrupted: stop talking to FB and return
return;
}
or
// do some more FB work
if (Thread.interrupted()) {
// We've been interrupted: no more FB
return;
}
On either case it is the FB thread that must periodically check if it is time to stop, as it is its job to do any cleanup that might be required.
Related
I'm first making a query on a background thread using retrofit. Then I create a new thread in the onResponse callback. I then sleep the thread for 10 seconds and try to execute some code. While the thread is sleeping, I exit my app. However the logger is never executed when I exit my app during the thread sleep.
mainService = RetrofitClient.getInstance().getRetrofit().create(MainService.class);
mainService.getPosts().enqueue(new Callback<List<Post>>() {
#Override
public void onResponse(#NotNull Call<List<Post>> call, #NotNull Response<List<Post>> response) {
//Running on main thread
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//This code is never executed. I don't see it in the logcat.
Log.d(TAG, "onCreate: Background thread is still running -- " + Thread.currentThread().getName());
}
}).start();
}
#Override
public void onFailure(#NotNull Call<List<Post>> call, #NotNull Throwable t) {
Log.e(TAG, "onFailure: Call failed", t);
}
});
Why isn't the Log.d(TAG, "onCreate: Background thread is still running -- ".... executed even though it's running on a separate thread?
This is a simplified example on what I'm trying to do. In my other project, after I make the retrofit call, I want to save the data to SQLite even if the user closes the app. But in this example, I'm trying to figure out the reason why the logger is not being executed.
While the thread is sleeping, I exit my app.
On many (most?) devices, that will terminate your process, particularly if you do not have a service running. Terminating your process terminates all your threads.
How to run code in background thread after app is killed without Service?
You could enqueue the work using WorkManager, if it is not essential that the work be done right away.
I am a total beginner to android and Java development, and I am currently trying to make a metronome.
The first problem I encountered after getting the sound playback to work, is that whenever the metronome played the app would stop responding - that's when I learned about threads and how I should use a new thread for my audio playback.
Creating a new thread helped and now the app runs fine, but I can't get the thread to stop/interrupt. I've read maybe 50 articles already about threads and interrupts and I can't figure it out.
Here is my 'Player' class code, which I've mostly copied from another Stack Overflow post (I have tried countless other ways and variations and none worked):
package com.example.t.firstapp;
import android.util.Log;
public class Player implements Runnable {
Thread backgroundThread;
Metronome m;
public void start() {
if (backgroundThread == null) {
backgroundThread = new Thread(this);
m = new Metronome();
backgroundThread.start();
}
}
public void stop() {
if (backgroundThread != null) {
backgroundThread.interrupt();
}
}
public void run() {
try {
Log.i("a", "Thread starting.");
while (!backgroundThread.isInterrupted()) {
m.play();
}
Log.i("b", "Thread stopping.");
throw new InterruptedException(); // ???
} catch (InterruptedException ex) {
// important you respond to the InterruptedException and stop processing
// when its thrown! Notice this is outside the while loop.
Log.i("c", "Thread shutting down as it was requested to stop.");
} finally {
backgroundThread = null;
}
}
}
Note the line marked with "???". I added that one myself because otherwise the "catch (InterruptedException ex)" returned an error.
Here is the relevant code from my MainActivity class:
public class MainActivity extends AppCompatActivity {
...
public Player p;
...
public void play() {
p = new Player();
p.start();
}
public void stop() {
p.stop();
}
}
Calling p.stop(); from within the method 'stop' doesn't actually do anything. This is where I get stuck. If I call p.stop() immediately after I start the thread, like this:
public void play() {
p = new Player();
p.start();
p.stop();
}
Then it works, and I see all of the relevant log messages from the Player class. Why doesn't p.stop() work when I call it from my 'stop' method? Is it because I am calling it from a different method, or is it because I am not calling it immediately?
Any help would be greatly appreciated since this is extremely frustrating. I have been studying and practicing Android development for only a week now, but I haven't done anything over the last 5 days but try to solve this problem. Thanks
You misunderstood the concept of interruption. Interupting is not some magical way of forcing the thread to stop, rather it will only work for methods that have interruption support - like sleeping.
Take a look at the Thread#interrupt() API, where it lists interrupt supported methods:
If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.
If this thread is blocked in an I/O operation upon an interruptible channel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a ClosedByInterruptException.
If this thread is blocked in a Selector then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector's wakeup method were invoked.
If none of the previous conditions hold then this thread's interrupt status will be set.
You can nicely implement your own methods with interrupt support, by contantly checking for the interrupt status.
Now let's see how we can solve your problem.
According to your comment, m.play() does not return, meaning, once m.play() is called, the while never checks if the thread has been interrupted; in turn it will never stop, since m.play() isn't implemented to support interrupts. This should also explain why the compiler complains that nobody throws an InterruptedException. (The reason it worked if interrupted immediately, is that the interrupt status is changed before it reaches the while... Think of it.)
Now, I assume that, if you will call m.stop(), m.play() will return, successfully rechecking for thread interruption. That's why it worked, as mentioned in comment.
But look, there's no real use of interrupting the thread - since all you have to do is call m.stop() and release the m.play(), just play and wait to return - which means stop has been called. Same to the while loop, drop it all the way.
public void run() {
Log.i("a", "Thread starting.");
m.play(); // blocks till stopped from some other thread...
Log.i("b", "Thread stopping.");
Log.i("c", "Thread shutting down as it was requested to stop.");
backgroundThread = null;
}
One case where I may see a use of the while and interrupt, if m.play() may return earlier than by calling m.stop() (say, by some exception), and you want to restart the metronome until stop is called; then a loop may be on the rescue, and interrupt may signal that it was actually stopped by calling m.stop().
public void run() {
Log.i("a", "Thread starting.");
while (!backgroundThread.isInterrupted()) {
m.play();
if(!backgroundThread.isInterrupted())
Log.i("b", "Stopped by exception, restarting....");
}
Log.i("c", "Thread stopping.");
Log.i("d", "Thread shutting down as it was requested to stop.");
backgroundThread = null;
}
So I'm trying to add multithreading to my app and I'm running into a weird issue. I create a new runnable to handle parsing all the data so that the application doesn't freeze while it's doing so, and then create a new thread to run that runnable. However, when the thread starts and run() gets called, I noticed it never calls onCompleted(). This is weird to me because if I take that exact block of code out of the run() part, it works perfectly.
Can anybody let me know what I'm doing wrong? I'm a bit new to multithreading in Java, so I would really appreciate it.
Runnable parseRunnable = new Runnable(){
#Override
public void run(){
new Request(session, id + "/comments", null, HttpMethod.GET, new Request.Callback() {
#Override
public void onCompleted(Response response) {
try {
JSONArray msgs = response.getGraphObject().getInnerJSONObject().getJSONArray("data");
populateData(msgs);
} catch (JSONException e) {
e.printStackTrace();
}
Request next = response.getRequestForPagedResults(Response.PagingDirection.NEXT);
retrieveMsgs(next);
}
}).executeAsync();
}
};
Thread parseThread = new Thread(parseRunnable);
parseThread.start();
I set a breakpoint at run() and at "new Request" which always gets hit, but when I set breakpoints for onCompleted(), those are never reached.
Your thread will finish when you reach the end of
public void run ()
I'm going to assume you don't get your callback because your thread has already finished since you call executeAsync (which will execute on a separate thread). Removing your thread altogether will probably fix your problem.
I have a problem when I try to implement a queue for http requests from scratch. Sorry, this might be a very naive concurrency problem to someone.
Basically I want my application to execute only one request at any time. Extra requests go into queue and execute later.
I am aware of other advanced stuff such as FutureTask and Execution pool, but I want the answer because I am curious about how to solve the basic concurrency problem. Following is my Class maintains the requestQueue
private Queue<HttpRequest> requestQueue;
private AsyncTask myAsyncTask=null;
public boolean send(HttpRequest hr){
//if there isn't existing task, start a new one, otherwise just enqueue the request
//COMMENT 1.
if(myAsyncTask==null){
requestQueue.offer(hr);
myAsyncTask= new RequestTask();
myAsyncTask.execute(null);
return true;
}
else{
//enqueue
//COMMENT 2
requestQueue.offer(hr);
}
}
//nested class
RequestTask extends AsyncTask<boolean,void,void>{
protected HttpResponse doInBackground(void... v){
//send all request in the queue
while(requestQueue.peek != null){
HttpResquest r= requestQueue.poll
//... leave out code about executing the request
}
return true;
}
protected void doPostExecute(boolean success){
//COMMENT 3: if scheduler stop here just before myAsyncTask is set to null
myAsyncTask=null;
}
}
The question is, if thread scheduler stops the background thread at the point COMMENT 3 (just before the myAsyncTask is set to null).
//COMMENT 3: if scheduler stop here just before myAsyncTask is set to null
myAsyncTask=null;
At the time, other threads happen to go to the point COMMENT 1 and go into the if ... else ... block. Because the myAsyncTask have not be set to null, the task get enqueued in else block(COMMENT 2) but new asyncTask will not be created, which means the queue will stuck!
//COMMENT 1.
if(myAsyncTask==null){
requestQueue.offer(hr);
myAsyncTask= new RequestTask;
myAsyncTask.execute(null);
return true;
}
else{
//enqueue
//COMMENT 2
requestQueue.offer(hr);
}
I hope it is clear. There is a chance that the queue stop being processed. I am keen to know how to avoid this. Thank you in advance
The way I would normally implement something like this is to create a class that extends thread. This would contain a queue object (use whichever one you prefer) and would have methods for adding jobs. I'd use synchronization to keep everything thread safe. Notify and wait can be used to avoid polling.
Here's an example that might help...
import java.util.*;
public class JobProcessor extends Thread
{
private Queue queue = new LinkedList();
public void addJob(Object job)
{
synchronized(queue)
{
queue.add(job);
queue.notify(); // lests the thread know that an item is ready
}
}
#Overide
public void run()
{
while (true)
{
Object job = null;
synchronized(queue) // ensures thread safety
{
// waits until something is added to the queue.
try
while (queue.isEmpty()) queue.wait();
catch (InterruptedException e)
; // the wait method can throw an exception you have to catch.
// but can ignore if you like.
job = queue.poll();
}
// at this point you have the job object and can process it!
// with minimal time waiting on other threads.
// be sure to check that job isn't null anyway!
// in case you got an InterruptedException.
... processing code ...
// job done loop back and wait for another job in the queue.
}
}
}
You pretty much just have to instantiate a class like this and start the thread, then begin inserting objects to process jobs. When the queue is empty the wait causes this thread to sleep (and also temporarily releases the synchronization lock), notify in the addJob method wakes it back up when required. Synchronization is a way of ensuring that only one thread has access to the queue. If you're not sure about how it works look it up in the java SDK reference.
Your code doesn't have any thread safety code in it (synchronization stuff) and that's where your problem is. It's probably a little over complicated which won't help you debug it either. But the main thing is you need to add synchronization blocks, but make sure you keep them as short as possible.
I have an android application, that have one thread, which will run after each 1 minute.
So my problem is, when i click one button, i have to reset the app, that means, it'll be
a fresh app.
So now when i clicked on that button, all the database and shared preference will clear.
But the thread will start again.
Now am using like this
if (killthread.isAlive()) {
killthread.interrupt();
}else {
// Here what'll i do, I mean how to kill that thread, which in sleep mode.
}
Thank you
vishnu
Thanks for the reply, Here when i click that button, that will come to the else part, but after 1 minute, the thread will start.So how to stop that in stage?
That will be something to do with the thread itself. My bet is that you have coded it to ignore the interrupt.
OK, here's the code from your comment.
public void run() {
while (true) {
try {
Thread.sleep(60000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
}
}
}
What this does is to catch and silently ignore the exception that occurs when the thread is interrupted ... and just keep going.
If you want it to stop on an interrupt it should be this ... or something equivalent.
public void run() {
while (true) {
try {
Thread.sleep(60000);
} catch (InterruptedException e) {
return;
}
}
}
If a Thread is not alive it means
1) it's dead / finished. You cannot / dont need to do anything.
2) it is newly created / havent started yet. That is Thread.start() has not been called yet. In this case Thread.interrupt() will have no effect. The only thing you can do is some custom logic - notify the code that is going to start the thread that it's not needed anymore