wait() notify() is not working as expected - java

I have a MyService class which contains a nested BroadcastReceiver class:
public class MyService {
private Object lock;
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
synchronized(lock) {
doTask();
lock.wait();
Log.d(TAG, "After wait ...");
}
}
}
private synchronized void doTask() {
Log.d(TAG, "do task ...");
synchronized(lock) {
lock.notify();
}
}
}
As you see above, when onReceive() is called, my code run doTask() in a synchronized block. Then, in doTask() function, my code run lock.notify(). I expected to see the log in terminal Log.d(TAG, "After wait ...");
I run my Android project. When onReceive() is triggered, I can see the log "do task ...", then, it is hanging there, I can't see log "After wait ...", why my wait-notify is not working as expected?

I run my Android project. When onReceive() is triggered, I can see the
log "do task ...", then, it is hanging there, I can't see log "After
wait ...", why my wait-notify is not working as expected?
BroadcastReceivers run always on the ui thread. if MyService runs on the Ui thread, what you are experiencing is a deadlock. It could be also that MyService runs on a background thread. If the notify is executed before wait, then the thread running MyService is waiting for the next notify

Related

Not understanding Android Mediaplayer Synchronization

Recently I've been learning Android from Beginning Android games when I came across this code:
MediaPlayer mediaPlayer;
boolean isPrepared = false;
public AndroidMusic(AssetFileDescriptor assetDescriptor) {
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(assetDescriptor.getFileDescriptor(),
assetDescriptor.getStartOffset(),
assetDescriptor.getLength());
mediaPlayer.prepare();
isPrepared = true;
mediaPlayer.setOnCompletionListener(this);
} catch (Exception e) {
throw new RuntimeException("Couldn't load music");
}
}
public void dispose() {
if (mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer.release();
}
public boolean isLooping() {
return mediaPlayer.isLooping();
}
public boolean isPlaying() {
return mediaPlayer.isPlaying();
}
public boolean isStopped() {
return !isPrepared;
}
public void pause() {
if (mediaPlayer.isPlaying())
mediaPlayer.pause();
}
public void play() {
if (mediaPlayer.isPlaying())
return;
try {
synchronized (this) {
if (!isPrepared)
mediaPlayer.prepare();
mediaPlayer.start();
}
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void setLooping(boolean isLooping) {
mediaPlayer.setLooping(isLooping);
}
public void setVolume(float volume) {
mediaPlayer.setVolume(volume, volume);
}
public void stop() {
mediaPlayer.stop();
synchronized (this) {
isPrepared = false;
}
}
public void onCompletion(MediaPlayer player) {
synchronized (this) {
isPrepared = false;
}
}
}
I'm very confused as to why we need to synchronize things here. Will there be more than one thing accessing these synchronized blocks? The book states, " The method
OnCompletionListener.onCompletion() might be called in a separate thread, and since
we set the isPrepared member in this method, we have to make sure that it is safe from
concurrent modifications. "
CallBacks are new to me, but I assume that when the MediaPlayer finishes, onCompletion is called. How will this onCompletion be called from a separate thread? Won't it be called on the thread that's executing this class? Eg, Thread 1 is executing play() and eventually the file ends, so onCompletion() is called on Thread 1. How will this be called on Thread 2? The synchronization on onCompletion() confuses me most, as with the other ones I somewhat understand that a different thread(UI thread) might edit the value of isPrepared in stop(), so that needs to be synchronized. The book's explanation further confuses me. How does this synchronization work, and what purpose does it serve?
All synchronized blocks synchronized on the same object can only have one thread executing inside them at the same time. All other threads attempting to enter the synchronized block are blocked until the thread inside the synchronized block exits the block.
Will there be more than one thing accessing these synchronized blocks?
It's your choice. You could have a central AndroidMusic class, and request to play something from threads.
YourClass.java
AndroidMusic androidMusic;
public void initialize(){
Thread thread = new Thread(
Runnable runnable = new Runnable() {
#Override
public void run() {
androidMusic = new AndroidMusic(myAssetDescriptor);
}
};
);
thread.start();
}
public void playMusic(){
Thread thread = new Thread(
Runnable runnable = new Runnable() {
#Override
public void run() {
androidMusic.play();
}
};
);
thread.start();
}
The strategy in this code is useful because you are using the method prepare(). This method is not async, so the UI can be blocked on the execution if is not called from a thread.
Assuming that you have the execution of the player in threads you could have concurrent request trying to modify the isPrepared at the same time. With the synchronized block all the threads will be waiting for his turn to access or modify the value.
About the onCompletion listeners:
The listener of the MediaPlayer is referencing the self instance of the AndroidMusic class.
You initialize a new AndroidMusic();
You have a MediaPlayer with a Callback to self class (AndroidMusic)
The callback will be in the same thread that the AndroidMusic instance is.
With the synchronized block your AndroidMusic class will be safe when a multiple threads request the play action at same time.
In simple term, the synchronized access can be thought of sequential access. For eg: If there is a variable which can be modified by two different methods running in two different threads without synchronized access, there might be high chance that :
The change made by one Thread in that variable is not seen by the other Thread.
The other Thread starts the modification taking the half-changed values of the variable done by the first Thread.
Such part of the method are called Critical Region of the method and basically, with synchronized keyword, if a Thread accesses that variable, it applies lock on that variable before going to Critical Region so, other Thread cannot access it simultaneously. It helps to prevent weird modifications.
Now, talking about MediaPlayer, there are two versions of preparing the MediaPlayer object: prepare(suitable for local files) and prepareAsync()(suitable for remote files). The Async version returns immediately without blocking the UI thread and does its background processing in a new Thread. When prepareAsync() is completed in that new Thread, a callback is returned to the Main Thread. We can set a listener for such callback via setOnPreparedListener(OnPreparedListener listener). Other than that, normally, the MediaPlayer instance is created and managed in the MainThread(UI Thread) so, there in no need of synchronized keyword. But, as #Ariel Perez said, it's always your choice and you can have two separate threads: one for setting data source on the player object and another for starting the playback.

Service not running after closing app

I am trying to make background service that will run 15 sec after user closes tha app, I have done service that runs 15 sec (loop with Logs), bud when I close tha app, then it stopes
and another problem is, when I try to stop it from main activity by stopService(intent); then the onDestroy method is called, but thread with loop continues
.. please can someone help me?
*sorry for my english - no native :D
public class NotificationService extends Service {
final private class MyThread implements Runnable {
int service_id;
MyThread(int service_id) {
this.service_id = service_id;
}
#Override
public void run() {
synchronized (this) {
for (int i = 0; i < 15; i++) {
try {
wait(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e("onStartCommand", "loop:" + i);
}
stopSelf(service_id);
}
}
}
Thread thread;
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "onCreate", Toast.LENGTH_SHORT).show();
}
#Override
public int onStartCommand(#Nullable Intent intent, int flags, int startId) {
Log.e("onStartCommand", "started");
Toast.makeText(this, "onStartCommand", Toast.LENGTH_SHORT).show();
thread = new Thread(new MyThread(startId));
thread.start();
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
Log.e("onDestroy", "onDestroy");
Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show();
super.onDestroy();
}
}
I am trying to make background service that will run 15 sec after user closes tha app, I have done service that runs 15 sec (loop with Logs), bud when I close tha app, then it stopes
Your code only starts the loop thread when startService(yourNotificationService)is called on the Activity or Broadcast Receiverthat is responsible for calling it does so. It then kills itself with stopSelf(service_id).
If, after you have returned from onStartCommand(), you immediately kill the app without calling stopSelf(service_id) (i.e. your 15 seconds is not up), then your Service will MOST LIKELY restart itself given the START_STICKY return value. However, after you call stopSelf(service_id) you are telling the Service to kill itself; after you close your app, there is nothing to tell your Service to restart through the onStartCommand() call.
and another proble is, when I try to stop it from main activity by stopService(intent); then the onDestroy method is called, but thred with loop continues
A Service is an Android component; it is not another process or thread, it runs in the same process and thread as the main UI thread unless you specify otherwise, as seen here.
Note that services, like other application objects, run in the main thread of their hosting process. This means that, if your service is going to do any CPU intensive (such as MP3 playback) or blocking (such as networking) operations, it should spawn its own thread in which to do that work. More information on this can be found in Processes and Threads. The IntentService class is available as a standard implementation of Service that has its own thread where it schedules its work to be done.
In your case, calling stopService(intent) tells the Service to stop itself, which it does. It does not stop the Thread you started (the MyThread instance). To do that, you must first make your Thread interruptible; see here to do that. Once you do that, you need to change your onDestroy() code to actually interrupt the MyThread instance, as here
#Override
public void onDestroy() {
Log.e("onDestroy", "onDestroy");
Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show();
thread.interrupt();
super.onDestroy();
}

How to use Runnable.wait() in AsyncTask? Why does the AsyncTask NOT wait...?

I am using AsyncTask to run a background operation. Of course switching to another thread while already working in a background thread does not make a lot of sense in general, except the other thread is the UI thread. This what I would like to to: While the task is running I need to "access" the UI, e.g. to show a dialog to ask the user how to proceed.
run the background task
stop the task at some point to get user feedback
switch to the UI thread to show dialog and ask for input
switch back to background task and continue work
How can this be done? I thought I could use Runnable with myActivity.runOnUiThread(runnable) but this does not work:
private void copyFiles() {
CopyTask copyTask = new CopyTask(this);
copyTask.execute();
}
// CustomAsyncTask is a AsyncTask subclass that takes a reference to the current
// activity as parameter
private class CopyTask extends CustomAsyncTask<Void, Void, Void> {
private doCopy;
#Override
protected Boolean doInBackground(Void... params) {
// Custom code, e.g. copy files from A to B and check for conflict
for (File file : allFiles) {
doCopy = true;
if (isConflict(file)) {
// Stop current thread and ask for user feedback on UI Thread
Runnable uiRunnable = new Runnable() {
public void run() {
// Pos 1. --> Execute custom code, e.g. use AlertDialog to ask user if file should be replaced...
doCopy = false;
synchronized (this) {
this.notify();
}
}
});
synchronized(uiRunnable) {
// Execute code on UI thread
activity.runOnUiThread(uiRunnable);
// Wait until runnable finished
try {
uiRunnable.wait();
}
catch (InterruptedException e ) {
e.printStackTrace();
}
}
}
// Pos 2. --> Continue work
if (doCopy)
copyFromAToB(File);
}
return null;
}
}
Within doInBackground() (--> in a background thread) the AsyncTask calls activity.runOnUiThread(uiRunnable). Next uiRunnable.wait() is called. Regarding to the docu wait() should do the following:
Causes the calling thread to wait until another thread calls the
notify() or notifyAll() method of this object.
Thus the background thread should wait to continue its work until this.notify() (== uiRunnable.notifiy()) is called on another thread (= the UI thread), shouldn't it?
Well, id does not wait! After calling uiRunnable.wait() the background thread immediately continues by jumping to if (doCopy).... It seems that the background thread and the main thread are executed in parallel (not surprising since this is what thread do...) and thus its a race condition whether doCopy = false on the UI thread or if (doCopy) on the background thread is reached first.
How is this possible? Why doesn't wait() works as described? Or am I getting something wrong?
Thank you very much!
EDIT:
To avoid missunderstandings: Of course I know the lifecycle methodes of AsyncTask but as far as I understand them, they are not what I am looking for (see my reply to the comment blow).
Interrupting the AsyncTask as soon as a UI interaction is necessary, query the UI and start a new AsyncTask would be possible of course. However this would result in code which is very hard to read/understand/maintain.
As I understand the docu of wait() everything should work fine here. Primary question is not how to do UI interaction during the lifecycle of an AsyncTask but why wait()does not work as expected.
The Basics
When you start an AsyncTask first the onPreExecute() method runs on the UI thread. You can override this method to make changes to the UI prior to the doInBackground() method running.
After the doInBackground() method finishes, the onPostExecute() method runs on the UI thread, so you can use this to make changes to the UI from here. If you need to make regular changes to the UI Thread during the doInBackground() method you override the onProgressUpdate() method which runs on the UI Thread, and then call it from within doInBackground(), which will allow you to periodically update the UI.
You could use something like the following;
private class DoStuffTask extends AsyncTask {
#Override
protected void doInBackground(Object... args) {
// Do stuff
onProgressUpdate(x);
// Do more stuff
}
#Override
protected void onProgressUpdate(Object... args) {
// Update your UI here
}
}
Now if this doesn't quite do it and you want the AsyncTask to wait for input during the doInBackground() method it is probably worth considering using multiple AsyncTasks instead. You can then finish each AsyncTask, ask for input, and then start a new AsyncTask to continue working.
Given that AlertDialog instances are asynchronous, this is probably the preferred solution because you can start the next AsyncTask from the AlertDialog itself.
Using wait() in an AsyncTask
If you would prefer to use a single AsyncTask you can use wait from within your AsyncTask to prevent execution continuing until some condition is met. Instead of using a new Runnable we are just using two threads in this instance, the thread running doInBackground() and the main thread, and we are synchronizing on the AsycTask itself.
Example below;
public class TestTask extends AsyncTask{
private boolean notified;
private Promptable p;
public interface Promptable { public abstract void prompt(); }
public TestTask(Promptable p){
this.p = p;
}
#Override
protected Object doInBackground(Object... arg0) {
Log.d("First", "First");
onProgressUpdate(null);
synchronized(this){
while(!notified){
try{
this.wait();
}
catch(InterruptedException e){ }
}
}
Log.d("Second", "Second");
return null;
}
#Override
protected void onProgressUpdate(Object... args){
synchronized(this){
notified = true;
p.prompt();
this.notify();
}
}
}
In the example above, assume that your Activity is parsed into the AsyncTask's constructor, and that it implements an interface we create called Promptable. You'll notice that even though we're calling wait() we are putting it in a while loop. If we didn't do this, and somehow notify() got called before wait() then your thread would lock up indefinitely. Also, you can't depend on the fact that your thread will wait forever, so the while loop ensures that it doesn't continue until notify is called.
I hope this helps.

How to Keep Listener Thread Alive

I have a class which is a listener for incoming messages and should be alive forever (So that it can listen for incoming messages) until i explicitly disconnect the connection for it. I have declared the thread as setDaemon(false) but it terminates with the calling methods termination.
Please tell me how to keep that thread alive and also please throw some light on how to implement the Spring TaskExecutor to achieve same.
Thanks in advance.
it is a listener it gets notified when someone sends message... so how do i keep it running ?
The Listener Class
public class MyListnerImpl implements Listener {
private final connectionImpl con;
public MyListnerImpl(ConnectionImpl con) {
if (con.isAuthenticated() && con.isConnected()) {
if (logger.isInfoEnabled()) {
logger.info("Initializing XmppListner:");
}
this.itsCon = con;
Thread t1 = new Thread(this);
t1.setDaemon(false);
t1.start();
}
}
public final void listnerInterfaceMethod(final Chat chat, final Message message) {
System.out.println("Message" + message);
}
public final void run() {
itsCon.getChatManager().addChatListener(new ChatManagerListener() {
public void chatCreated(final Chat chat, final boolean createdLocally) {
if (!createdLocally) {
chat.addMessageListener(itsFbml);
}
}
});
}
}
Calling class simply creates its object and thread gets started by the Listeners constructor.
I want to keep this thread created run until i interrupt it.
There are a few things you could do that would be better than hanging the initial thread forever:
Use otherThread.join(). This will cause the current thread you are running in to sleep until the other thread has finished executing.
As #nanda suggests, use ExcecutorService.shutdown() to wait until a pool of threads has finished.
Use otherThread.setDaemon(false) and simply let your initial thread exit. This will set your new threads as user threads. Java will not shut down until the only threads running are daemon threads.
synchronized(this) {
while (true) {
this.wait();
}
}
This will make the current thread wait on the monitor of the current class until someone calls notify(), or forever.
copied from How do you hang a thread in Java in one line?
A thread says alive until run() returns (or throw an error/exception) If you want to keep it alive, use a loop, don't return and catch any error/exception.
This is how i solved the problems that time,
So this case was not of multi threading , had just a single thread which needed to run for ever,
So Inserted
public final void run() {
while(true)
{
//Run Method Logic...
}
}
And instantiated it from a spring bean.
I was also looking at more fancy things for this single threaded scenario like awaitTermination(); or something like that.

Why is this thread running multiple times in a row?

I just solved the problem myself. I had multiple calls for syncCustomers() due to a dialog closing event problem. I solved it by providing the parent JFrame in the JDialog constructor. Pretty stupid error on my side.
My application contains a task that synchronizes with a webservice and a local database. This task may take up to several minutes. Thus I want to notify the user about this time consuming process with a simple dialog (Swing). The user is not supposed to continue working while the sync process is running.
So I thought of:
open modal dialog with the notification for the user
start the sync process in a separate thread
close modal dialog after sync process is done
User clicked on the button to start sync process:
private void syncCustomers() {
if (checkWebserviceAuth()) {
SyncDialog dialog = new SyncDialog();
dialog.setLocationRelativeTo(this);
dialog.setVisible(true);
SyncCustomersTask task = new SyncCustomersTask(dialog, getCoach());
task.run(); // task.start() will result in the same problem
} else {
openAuthorizeDialog(true);
}
}
public class SyncDialog extends javax.swing.JDialog {
public SyncDialog() {
initComponents();
// I already noticed that the modal dialog won't work for me since it interrupts within syncCustomers()
//this.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
this.setTitle(Application.getApplicationTitle());
}
...
}
public class SyncCustomersTask extends Thread {
private void doWork() {
System.out.println("Start doWork() and sleep for 10 seconds...");
try {
// for testing purpose
Thread.sleep(10000);
} catch (InterruptedException ex) {
}
System.out.println("Done with doWork().");
}
#Override
public void run() {
doWork();
if (getCallback() != null) {
System.out.println("Invoke callback...");
getCallback().dispose();
System.out.println("Callback invoked.");
}
}
...
}
This will result in an infinite loop of:
Start with doWork()...
Start doWork() and sleep for 10 seconds...
Done with doWork().
Invoke callback...
Callback invoked.
If I comment out
getCallback().dispose();
, the loop will stop after the second execution:
Start with doWork()...
Start doWork() and sleep for 10 seconds...
Done with doWork().
Invoke callback...
Callback invoked.
Start with doWork()...
Start doWork() and sleep for 10 seconds...
Done with doWork().
Invoke callback...
Callback invoked.
I don't get it. What fires the thread to execute over and over again?
I guess this whole thing isn't a good idea to start with, but I wasn't able to get things like ProgressMonitor working either. :(
Call start(), not run(). The latter will simply execute the thread, but not in a separate thread! The start() method will instantiate a new thread, and only then invoke your run() method in that new thread.
This is a surprising common problem, btw.
invoking run() does not execute code in a new thread.

Categories

Resources