Not able to resume my thread in android - java

I know there are tons of questions and answers on this topic here but I am not able to resolve the below issue to resume a thread in my app.
heres is my runnable:-
Runnable ViewPagerVisibleScroll= new Runnable() {
#Override
public void run() {
if (i <= mAdapter.getCount() - 1) {
verticalViewPager.setCurrentItem(i, true);
handler.postDelayed(ViewPagerVisibleScroll, 3000);
i++;
while (isPaused) {
synchronized (ViewPagerVisibleScroll) {
// wait for resume() to be called
try {
ViewPagerVisibleScroll.wait();
// isPaused = false;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
};
pause and resume methods:-
public void pause() {
synchronized (ViewPagerVisibleScroll) {
isPaused = true;
}
}
public synchronized void resume() {
synchronized (ViewPagerVisibleScroll) {
isPaused = false;
// notify anybody waiting on "this"
ViewPagerVisibleScroll.notify();
}
}
My problem is that thread will pause() when I call pause method but it will not resume when I call resume(). Please help me to get rid of this issue.

First of all, I see this code:
public void pause() {
synchronized (ViewPagerVisibleScroll) {
isPaused = true; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
}
}
public synchronized void resume() {
synchronized (ViewPagerVisibleScroll) {
isPaused = false;
// notify anybody waiting on "this"
ViewPagerVisibleScroll.notify();
}
}
and this:
while (isPaused)
I can guarantee that if you invoke method pause(), i.e. you set isPaused to true, then this loop will be executed while isPaused is true. You should use !isPaused:
while (!isPaused)
i.e. while NOT paused do something. This was just an introduction.
So, back to your problem, I recoment you do next:
1). Create static final objects for synchronization:
private static final Object syncObj = new Object();
private static final Object stopSyncObj = new Object();
2). Implement your runnable as inner class:
public class MyRunnable implements Runnable {
private boolean isPaused;
private boolean isStopped;
public MyRunnable(){
synchronized (stopSyncObj){
isStopped = false;
}
synchronized (syncObj){
isPaused = false;
}
}
#Override
public void run() {
if (i <= mAdapter.getCount() - 1) {
verticalViewPager.setCurrentItem(i, true);
handler.postDelayed(ViewPagerVisibleScroll, 3000);
i++;
//Check thread
boolean isStopped = false;
while (!isStopped) {
synchronized (syncObj) {
boolean isPaused = false;
synchronized (syncObj){
isPaused = this.isPaused;
}
if(isPaused) {
// wait for resume() to be called
try {
syncObj.wait();
// isPaused = false;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
//do somethinghere
}
}
//Check 'stop' flag
synchronized (stopSyncObj){
isStopped = this.isStopped;
}
}
}
}
//This method stops runnable forever
public void stopRunnable(){
synchronized (stopSyncObj){
isStopped = true;
}
}
public void pause(){
synchronized (syncObj){
isPaused = true;
}
}
public void resume(){
synchronized (syncObj){
isPaused = false;
syncObj.notifyAll();
}
}
}
3). Use it:
Runnable ViewPagerVisibleScroll = new MyRunnable();
UPDATED ANSWER
For autoscrolling use ScheduledThreadPoolExecutor:
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
executor.schedule(new Runnable() {
#Override
public void run() {
//scroll viewpager
}
}, 3, TimeUnit.SECONDS);
To stop it use:
executor.shutdown();

Related

How to synchronize MesageReceivedEvent from main EventListener with a new variable inside Thread only when it is updated by main's listener

I need to create a new Thread that will execute a method when and only when the MessageReceivedEvent is updated inside the main ListenerAdapter, and let the thread sleep whenever the variable is not updated.
This thread should run independently from the main thread and not stop new requests.
This is the thread class,
private static final class Worker extends Thread {
private volatile boolean running = false;
MessageReceivedEvent event; //this must update along with the listener
private boolean validateData() {
if (//something) {
return true;
}
return false;
}
private void waitForInput() {
boolean hasInput = false;
try {
while (!hasInput) {
hasInput = validateData();
if (!hasInput) {
Thread.sleep(10);
}
}
} catch (InterruptedException iex) {
Thread.currentThread().interrupt();
}
}
#Override
public void run() {
running = true;
while (running) {
waitForInput();
//do something
}
}
}
It is an inner class ran by a request from the main thread,
the MessageReceivedEvent inside it must be updated only when the actual event from the listener changes, otherwise it should do nothing.
When testing, it will only execute based on the MessageEvent that triggered the thread, how can I make this thread receive the updates?
public class Listener extends ListenerAdapter {
public static MessageReceivedEvent msgEvnt;
#Override
public void onMessageReceived(MessageReceivedEvent msgEvnt) {
Listener.msgEvnt = msgEvnt;
}
This is all the listener does, update the variable whenever there is a new messageEvent.
You can use a Condition Variable to accomplish this.
final ReentrantLock lock = new ReentrantLock();
final Condition condition = lock.newCondition();
private void waitForInput() {
lock.lock();
Listener.msgEvnt = null;
try {
while (Listener.msgEvnt == null)
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
#Override
public void onMessageReceived(MessageReceivedEvent event) {
lock.lock();
try {
Listener.msgEvnt = msgEvnt;
condition.signal();
} finally {
lock.unlock();
}
}
See ReentrantLock and Condition
You can use a BlockingQueue
final BlockingQueue queue = new ConcurrentBlockingQueue();
private MessageReceivedEvent waitForInput() throws InterruptedException {
return queue.take();
}
#Override
public void onMessageReceived(MessageReceivedEvent event) {
queue.put(event);
}
You can use a Callback, this is what I would recommend.
Consumer<? super MessageReceivedEvent> callback;
private void onInput(Consumer<? super MessageReceivedEvent> callback) {
this.callback = callback;
}
#Override
public void onMessageReceived(MessageReceivedEvent event) {
if (this.callback != null)
this.callback.accept(event);
this.callback = null;
}
Example use:
listener.waitForInput(event -> {
System.out.printf("%#s: %s\n", event.getAuthor(), event.getMessage().getContentDisplay());
});
This is already provided by JDA-Utilities

Android threads can't get notify() to work properly using wait() and notify()

So I am writing an Android application which will do a count down when the user presses a button. A thread runs the count down. My problem is that when I pause the application I want the thread to stop counting and then resume once the application is back. My notify is not working correctly. Help thanks!
public class MainActivity extends Activity {
private TextView mText;
private EditText mUserInput;
private CounterThread mCounterThread;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mText = (TextView)findViewById(R.id.text);
mUserInput = (EditText)findViewById(R.id.userInput);
mCounterThread = new CounterThread();
}
#Override
public synchronized void onPause(){
super.onPause();
mCounterThread.running = false;
}
#Override
public synchronized void onResume(){
super.onResume();
mCounterThread.running = true;
notify();//seems like this does nothing!
}
public void startCounterThread(){
mCounterThread.start();
}
public void button_handler(View v){
startCounterThread();
}
public void updateSeconds(final long seconds){
Runnable UIdoWork = new Runnable(){
public void run(){
String time = String.valueOf(seconds);
mText.setText("Your file will open in " + time + " seconds");
}
};
runOnUiThread(UIdoWork);
}
private class CounterThread extends Thread{
int count = 10;
boolean running = true;
#Override
public synchronized void run(){
while(count != 0){
while(!running){
try{
wait();//wait() will wait forever
//I don't want to put a time since
//I have no clue when the user will resume again
}catch(InterruptedException e){
e.printStackTrace();
}
}
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
updateSeconds(count--);
}
}
}
Slightly modified code:
public class MainActivity extends Activity {
private TextView mText;
private EditText mUserInput;
private CounterThread mCounterThread;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_2);
mText = (TextView) findViewById(R.id.text);
mUserInput = (EditText) findViewById(R.id.userInput);
mCounterThread = new CounterThread();
mCounterThread.start();
}
#Override
public synchronized void onPause() {
super.onPause();
mCounterThread.onPause();
}
#Override
public synchronized void onResume() {
super.onResume();
mCounterThread.onResume();
}
public void startCounterThread() {
mCounterThread.start();
}
public void button_handler(View v) {
startCounterThread();
}
public void updateSeconds(final long seconds) {
Runnable UIdoWork = new Runnable() {
public void run() {
String time = String.valueOf(seconds);
mText.setText("Your file will open in " + time + " seconds");
}
};
runOnUiThread(UIdoWork);
}
private class CounterThread extends Thread {
private int count = 10;
private final Object lock = new Object();
private volatile boolean isRunning = true;
public void onResume() {
if(!isRunning){
isRunning = true;
synchronized (lock){
lock.notify();
}
}
}
public void onPause() {
isRunning = false;
}
#Override
public void run() {
while (count != 0) {
synchronized (lock) {
if (!isRunning) try {
lock.wait();
} catch (InterruptedException e) {
//
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//
}
updateSeconds(count--);
}
}
}
}
your field running must be marked as volatile. It basically means that several threads could change it and all threads will see it.
do not expose monitor objects out of a Thread or a Runnable. It's quite bad idea to use activity as a monitor. It's quite bad idea to pass reference of activity anywhere.
you used different monitor objects: Thread and Activity. Use one inside thread.
It makes sense that is not working because wait() and notify() work over an object that is used as a lock. When you run wait() in your run() method, you are using an instance of CounterThread as a lock, but when you run notify() inside your onResume() method, you are using an instance of MainActivity. CounterThread will never get notified. Your alternative is (in your onResume() method):
...
synchronized(mCounterThread) {
mCounterThread.notify();
}
...

Schedule execution of mediaplayer in android

I'm new to Android development and I need some help with a little problem.
I have a background Service that runs my media player and communicate with my PlayerActivity.
So far so good.
I need to schedule the execution of the tracks in different periods. i.e Play track x for one minute than play track y for 30 seconds etc.
So I call MyTimer thread form the PlayerActivity, this thread throws event at the specific time,
the PlayerActivity catches the Event and calls the MediaplayerService next() method.
My Problem is if I call next() without the thread it works fine, If i call it with the thread I get
mContext is null, can't getMirrorDisplayStatus!!!
with mediaplayer warning (1, 902)
I've tried to run this thread with from the PlayerActivity via Handler.post() and runOnUiThread()
and I get the same error.
below is the code for MyTimer Thread.
public class MyTimer implements Runnable {
private Object mPauseLock;
private boolean mPaused;
private boolean mFinished;
private TimeSection section;
public Trainer()
{
mPauseLock = new Object();
mPaused = false;
mFinished = false;
BusProvider.getInstance().register(this);
}
#Override
public void run()
{
while (!mFinished)
{
TimerManager tm = TimerManager.getInstace();
this.section = tm.getCurrentTimeSection();
if(this.section == null)
mFinished = true;
else
{
tm.inc();
// produce sectionChangeEvent event
BusProvider.getInstance().post(produceSectionEvent());
try
{
Thread.sleep((this.section.getTypeDuration() * 1000));
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
synchronized (mPauseLock)
{
while (mPaused)
{
try
{
mPauseLock.wait();
} catch (InterruptedException e)
{
}
}
}
}
}
/**
* Call this on pause.
*/
public void onPause() {
synchronized (mPauseLock) {
mPaused = true;
}
}
/**
* Call this on resume.
*/
public void onResume() {
synchronized (mPauseLock) {
mPaused = false;
mPauseLock.notifyAll();
}
}
#Produce public TimeSectionEvent produceSectionEvent(){
return new TimeSectionEvent(this.section);
}
}
some code of the Player Activity:
public class PlayerActivity implements
IMediaPlayerServiceClient{
private MediaPlayerService mService;
....
/**
* Binds to the instance of MediaPlayerService. If no instance of
* MediaPlayerService exists, it first starts a new instance of the service.
*/
public void bindToService()
{
Intent intent = new Intent(this, MediaPlayerService.class);
if (MediaPlayerServiceRunning())
{
// Bind to LocalService
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
} else
{
startService(intent);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
}
.....
/*
* This is how I start the timing thread
*/
private void startTiming()
{
mTimer = new MyTimer();
runOnUiThread(mTimer);
// trainingHandler.post(mTrainer);
}
public void next(TimeSection section)
{
mService.next(section);
}
/*
* Here I catch the TimeSectionEvent from MyTimer thread
*/
#Subscribe public void onSectionChanged(TimeSectionEvent e)
{
TimeSection section = e.getSection();
if(section != null)
next(section);
}
each activity has context so from the exception that you got i guess its a problem with the context of the MediaPlayerService.
you are using bindService(...) to bind the intent to the MediaPlayerService that should bind the context.
try to check if that binding is still there when you are trying to do "mService.next(section);"
Problem SOLVED!
The problem was that I was that the timing thread was running on the UI thread -> calling Thread.sleep made the UI thread sleeping as well.
So I end up using IntentService that doing the timer thread job in background.
public class TimingService extends IntentService{
private Object mPauseLock;
private boolean mPaused;
private boolean mFinished;
private TimeSection section;
public TimingService()
{
super("TimingService");
mPauseLock = new Object();
mPaused = false;
mFinished = false;
BusProvider.getInstance().register(this);
}
#Override
protected void onHandleIntent(Intent intent)
{
while (!mFinished)
{
TimerManager tm = TimerManager.getInstace();
this.section = tm.getCurrentTimeSection();
if(this.section == null)
mFinished = true;
else
{
tm.inc();
// produce sectionChangeEvent event
BusProvider.getInstance().post(produceSectionEvent());
try
{
Thread.sleep((this.section.getTypeDuration() * 1000));
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
synchronized (mPauseLock)
{
while (mPaused)
{
try
{
mPauseLock.wait();
} catch (InterruptedException e)
{
}
}
}
}
}
/**
* Call this on pause.
*/
public void onPause() {
synchronized (mPauseLock) {
mPaused = true;
}
}
/**
* Call this on resume.
*/
public void onResume() {
synchronized (mPauseLock) {
mPaused = false;
mPauseLock.notifyAll();
}
}
#Produce public TimeSectionEvent produceSectionEvent(){
return new TimeSectionEvent(this.section);
}
#Subscribe
public void onPauseEvent(PauseEvent e)
{
this.onPause();
}
#Subscribe
public void onResumeEvent(ResumeEvent e)
{
this.onResume();
}
}

Do action while long click

Hello I am trying to perform some actions while the user is holding down a button.
My problem is that my Runnable wont "run".
Here is my code:
#Override
public boolean onLongClick(View v) {
final Runnable r = new Runnable()
{
public void run()
{//do the forwarding logic here
int test = 0;
if(holdingDown)
test++;
else
return;
Log.i("test", test+"");
}
};
r.run();
}
return false;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_UP:
{
holdingDown= false;
Log.i("holdingDown", "false");
break;
}
}
return false;
}
The onTouch is for detecting when the user stop pressing the button. When I look at my logs I see at that the Runnable runs only once.
My test log get only the value 1.
The log call for Log.i("holdingDown", "false") is getting triggered at the right time, only when I stop touching the button.
Why is it that my Runnable won't run? Thanks.
EDIT:
I tried this code:
#Override
public boolean onLongClick(View v) {
// TODO Auto-generated method stub
holdingDown = true;
new Thread(new Runnable() {
#Override
public void run() {
if(holdingDown)
{
int test = 0;
test++;
Log.i("test", test+"");
}
else
return;
}
}).start();
return false;
}
Its till not working.
You could try using a Thread instead of a Runnable like this:
Thread thread = new Thread() {
#Override
public void run() {
//code you want to run on long press
} };
thread.start();
OR
You could try putting the Runnable inside a Thread like this:
Thread thread = new Thread(new Runnable() {
public void run() {
// code you want to run on long press
}
});
thread.start();
UPDATE: - try this?
#Override
public boolean onLongClick(View v) {
// TODO Auto-generated method stub
holdingDown = true;
new Thread(new Runnable() {
#Override
public void run() {
if (holdingDown) {
int test = 0;
test++;
Log.i("test", test + "");
} else {
Log.i("test", "else");
}
return;
}
}).start();
return false;
}
You don't do r.run() to start a thread, that only runs it once.
You either do new Thread(r).start(); or you use a ScheduledExecutorService.
You can create a class called HoldingDown overriding Runnable and instantiate a Thread object passing a new instance of your HoldingDown and call the start method.
Also, you can use the mousePressed and mouseReleased events of MouseListener.
You should start a new Thread in your mousePressed, store the instance somewhere and stop it on mouseReleased.
See the documentation for more details.

Two Runnables on the same thread ending at the same time. Is conflict possible?

Below is a simplification of some code I have for a custom View. It has a Runnable for an animation, and a Runnable for audio. The start() function starts both the animation runnable and the audio runnable. Each runnable implements an inteface with a callback on completion.
I need to know when both are finished, so I can call onBothRunnablesFinished().
public class Foo extends View {
RunnableA mRunnableA;
RunnableB mRunnableB;
// overrides of onCreate, onMeasure, onDraw, etc...
private void onBothRunnablesFinished() {
// Do stuff when both runnables are finished...
}
public void start() {
mRunnableA = new RunnableA();
mRunnableB = new RunnableB();
post(mRunnableA);
post(mRunnableB);
}
private class RunnableA implements Runnable, AnimationListener {
private MyAnimation mAnim;
private boolean mRunning = false;
public RunnableA() {
mAnim = new MyAnimation();
mAnim.setAnimationListener(this);
}
public boolean isRunning() {
return mRunning;
}
#Override
public void run() {
mRunning = true;
startAnimation(mAnim);
}
// Called when mAnim finishes
#Override
public void onAnimationEnd(Animation animation) {
mRunning = false;
// **WHAT IF THE OTHER RUNNABLE FINISHES NOW?**
if (mRunnableB.isRunning() == false) {
onBothRunnablesFinished();
}
}
}
private class RunnableB implements Runnable, OnCompletionListener {
private MyMediaPlayer mMediaPlayer;
private boolean mRunning = false;
public RunnableB() {
mMediaPlayer = MyMediaPlayer();
mMediaPlayer.setOnCompletionListener(this);
}
public boolean isRunning() {
return mRunning;
}
#Override
public void run() {
mRunning = true;
mMediaPlayer.start();
}
// Called when mMediaPlayer finishes
#Override
public void onCompletion(MediaPlayer mp) {
mRunning == false;
// **WHAT IF THE OTHER RUNNABLE FINISHES NOW?**
if (mRunnableA.isRunning() == false) {
onBothRunnablesFinished();
}
}
}
}
I've labeled a couple areas of interest with comments. What would happen if the audio and animation runnables finish at the same time? More specifically, could the callback of one runnable interrupt the callback of the other in the commented locations above? Is this possible??
I hope not, because then onBothRunnablesFinished would be called twice. If this is the case, how can I resolve this issue?
I've deleted my other answer. Now that I think about it you don't even need Runnables since the animation and media player frameworks will use their own threads. However you still need to synchronize the call to onActivityFinished() (formerly called onBothRunnablesFinished()) since the framework threads may finish simultaneously:
public class Foo extends View implements AnimationListener, OnCompletionListener {
private MyAnimation mAnim;
private MyMediaPlayer mMediaPlayer;
private boolean mIsOneActivityFinished = false;
synchronized private void onActivityFinished() {
if(!mIsOneActivityFinished) {
// The first activity is finished. Set the flag and return.
mIsOneActivityFinished = true;
return;
}
// Do stuff when both activities are finished...
}
public void start() {
mAnim = new MyAnimation();
mAnim.setAnimationListener(this);
startAnimation(mAnim);
mMediaPlayer = MyMediaPlayer();
mMediaPlayer.setOnCompletionListener(this);
mMediaPlayer.start();
}
// Called when mAnim finishes
#Override
public void onAnimationEnd(Animation animation) {
onActivityFinished();
}
// Called when mMediaPlayer finishes
#Override
public void onCompletion(MediaPlayer mp) {
onActivityFinished();
}
}
Trust me this code will work and is way cleaner. Don't even give a thought to using Runnables as Android does the multi-threading for you.
Barry
you can use an AtomicInteger initialized to 2
and finish the run with
if(atomicInt.decrementAndGet()==0)onBothRunnablesFinished();
I would inject a POJO mutex object into both the runnable objects and use it to synchronize both the isRunning and onCompletion methods. Acutally, isRunning does not need synchronization since it's only called from within the syncrhonized code in onCompletion, but I would consider the synchronization semantics much clearer with it also synchronized.
Using RunnableA as a template (make the changes marked // completion to both classes):
private class RunnableA implements Runnable, AnimationListener {
private MyAnimation mAnim;
private boolean mRunning = false;
private Object mExecutionMutex; // completion
public RunnableA(Object mtx) { // completion
mAnim = new MyAnimation();
mAnim.setAnimationListener(this);
mExecutionMutex=mtx;
}
public boolean isRunning() {
synchronized(mExecutionMutex) { // completion (Note: This is actually unnecessary)
return mRunning;
}
}
#Override
public void run() {
mRunning = true;
startAnimation(mAnim);
}
// Called when mAnim finishes
#Override
public void onAnimationEnd(Animation animation) {
synchronized(mExecutionMutex) { // completion
mRunning = false;
if(mRunnableB.isRunning() == false) {
onBothRunnablesFinished();
}
}
}
}

Categories

Resources