Get error exception when using the sleep function - java

I want to delay my application for a while while a melody is playing, and when it's finished change the image on an imageview.
public void addListenerOnButtons() {
harmonicaTecknad= (ImageView)this.findViewById(R.id.harmonicatecknadspelautblas);
harmonicaTecknad.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
harmonicaTecknad.setImageResource(R.drawable.harmonicatecknadtryckrood);
RunAnimations();
utblas=MediaPlayer.create(SpelaTonerActivity.this, R.raw.utblas4);
utblas.start();
Thread timer = new Thread(){
public void run() {
try { // The delay should occur here
sleep(utblas.getDuration());
} catch(InterruptedException e) {
e.printStackTrace();
} finally {
harmonicaTecknad.setImageResource(R.drawable.harmonicatecknad1);
}
}
};
timer.start();
}
}
I get an exception error, obviously I cannot set the image inside the thread, so where should I set it?

This is all explained in details, with examples, in the android documentation:
Android offers several ways to access the UI thread from other
threads. You may already be familiar with some of them but here is a
comprehensive list:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
Handler
[...]
Unfortunately, these classes and methods could also tend to make your
code more complicated and more difficult to read. It becomes even
worse when your implement complex operations that require frequent UI
updates.
To remedy this problem, Android 1.5 and later platforms offer a
utility class called AsyncTask, that simplifies the creation of
long-running tasks that need to communicate with the user interface.

Write harmonicaTecknad.setImageResource(R.drawable.harmonicatecknad1); code on UI thread because you can not write UI code to non UI thread.
So simply replace above line of code with
runOnUiThread(new Runnable()
{
#Override
public void run()
{
harmonicaTecknad.setImageResource(R.drawable.harmonicatecknad1);
}
});
If you are still getting error then for testing purpose just change sleep(utblas.getDuration()); with sleep(1000);

As the other answers say, you need to set the image from the UI thread. However, while you can use Thread.sleep(), you should in general avoid using sleeps for logic. Most classes have some way to get callbacks when things happen - for example in your case you can use MediaPlayer.OnCompletionListener. You register for a callback from the media player, and that callback will always be on the UI thread. This is what it looks like:
public void addListenerOnButtons() {
harmonicaTecknad= (ImageView)this.findViewById(R.id.harmonicatecknadspelautblas);
harmonicaTecknad.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
harmonicaTecknad.setImageResource(R.drawable.harmonicatecknadtryckrood);
RunAnimations();
utblas=MediaPlayer.create(SpelaTonerActivity.this, R.raw.utblas4);
utblas.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
harmonicaTecknad.setImageResource(R.drawable.harmonicatecknad1);
}
};
utblas.start();
}
}

Related

How to signal an infinite observable to stop/continue emission?

Problem description
I writing an Android application in Java to handle RFID reading based on some proprietary library and hardware. The RFID reader has a JNI library, which acts as an API to the hardware. This library is thread safe (as they say) but I cannot make the scanning process run on the Android's UI thread. I also don't want to use AsyncTask because it has started being deprecated I want the user to be able to start/resume the scanning process based on the click of a button without the process starting each time from the beginning.
I have the following code inside a class Scanner that is a singleton object.
class Scanner {
/*...*/
public Observable<Product> scan() {
return Observable.create(emitter -> {
while (true) {
UHFTAGInfo TAG = RFIDReader.inventorySingleTag();
if (TAG != null) {
emitter.onNext(new Product(TAG.getEPC()));
}
}
});
}
/*...*/
}
On the UI side, I have a ScanFragment and some buttons. This is the OnClickListener() of the scanButton that triggers the scanning process.
scanButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Scanner.getInstance().scan()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Product>() {
#Override
public void onSubscribe(#NonNull Disposable d) {
}
#Override
public void onNext(#NonNull Product product) {
listProducts.add(product);
adapter.notifyDataSetChanged();
}
#Override
public void onError(#NonNull Throwable e) {
}
#Override
public void onComplete() {
}
});
}
Questions
What is the correct way to stop/resume/end the above infinite emitting Observable when another stopButton/resumeButton is pressed or when user moves to another fragment?
I have thought many different things like an Atomic flag without and with an Observable for it and using takeUntil for that Observable. But will takeUntil stop my Observable and I will have to start it from the beginning?
First of all, you have an unconditional infinite loop which is unable to respond to when the downstream disposes the sequence. Use while (!emitter.isDisposed()).
Stopping a sequence is done via Disposable.dispose. You get one Disposable in onSubscribe so you'll have to make that available to the button that you want to stop a sequence.
Resuming is essentially subscribing to the sequence again, i.e., what you already do in that onClick callback.

Java FX application stuck when Java opens Matlab

I'm making a program which sends some data to the Matlab and receives output from matlab. To do that, I used matlabcontrol library.
Problem
After I click Java FX application button to submit data, matlabcontrol opens Matlab for further calculations. But when java opens the matlab, Java FX application stuck with wait cursor.Then starts to work again after Matlab finishes the process of calculation.
What I did
public void runner()
{
Platform.runLater(new Runnable()
{
#Override
public void run()
{
firstFunc();
}
});
Platform.runLater(new Runnable()
{
#Override
public void run()
{
secondFunc();
}
});
}
public void firstFunc()
{
// This function controls UI while Matlab does it's calculations
double progress = 0.2;
progressLabel.setText(progress*100+"% Completed");
progressBar.setProgress(progress);
}
public void secondFunc()
{
// This method creates matlab connection and handle matlab
firstClass mainFunc = new firstClass(pathSelected);
mainFunc.func();
}
So I used Platform runLater to run two methods separately. But still my program stuck with wait cursor when Matlab starts to functioning.
I also used threads to run these functions in parallel. But had the same issue. How can I correct this. Any help?
Update
As described in this question, I did use service and task with countdownlatch. But still didn't get what I wanted. In there,
Service<Void> service = new Service<Void>() {
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
//Background work
final CountDownLatch latch = new CountDownLatch(1);
Platform.runLater(new Runnable() {
#Override
public void run() {
try{
//FX Stuff done here
firstFunc();
}finally{
latch.countDown();
}
}
});
latch.await();
//Keep with the background work
// I added matlab calling function here.
secondFunc();
return null;
}
};
}
};
service.start();
latch await and let background work to carry on. But in my case, my FX application shows a progress bar. So it should always update while background task happens. In here, it finishes FX task and moves to background task. I didn't get what I wanted. please help.
I had to use Service, Task and CountDownLatch to accomplish this task as I mentioned in Question Update part.
Also, I had to run another task inside the firstFunc, where I did update the progress. Like in this answer.

Animators may only be run on Looper threads Android

I'm trying to animate something when a task is completed. The problem here is I get this error message:
android.util.AndroidRuntimeException: Animators may only be run on Looper threads
at android.animation.ValueAnimator.cancel(ValueAnimator.java:1004)
at android.view.ViewPropertyAnimator.animatePropertyBy(ViewPropertyAnimator.java:965)
at android.view.ViewPropertyAnimator.animateProperty(ViewPropertyAnimator.java:921)
at android.view.ViewPropertyAnimator.alpha(ViewPropertyAnimator.java:735)
at com.design.zaton.prototypei.MainActivity$1$1.run(MainActivity.java:93)
at java.lang.Thread.run(Thread.java:761)
The app worked fine before with the same exact code but now it simply doesn't. I'm really confused.
Here's where the error happens:
new Thread(new Runnable() {
#Override
public void run() {
final String s = getGiphyViews(String.valueOf(mEdit.getText()));
runOnUiThread(new Runnable() {
#Override
public void run() {
result.setText(s);
}
});
loading.animate()
.alpha(0)
.setDuration(100);
done.animate()
.scaleY(1)
.scaleX(1)
.setDuration(300);
}
}).start();
The error outlines the loading.animate() method.
Thanks in advance!
runOnUiThread(new Runnable() {
#Override
public void run() {
//Your code
}
});
You have to execute the code in the UI Thread
Looper threads are threads in Android that permanently loop (or until you cancel them). They work in conjunction with Handlers which will post and send messages to Looper threads. Animators use heavy use of Looper threads because they perform their actions in repeated cycles. This allows the animator to not block after you press "start" so you can continue to perform other actions.
To further complicate matters, you most likely are performing animations on View objects. These can only be run on the main UI thread (which happens to be the biggest Looper thread of them all). So, you can not run these animations on separate threads like you are trying.
I think, there has been a solution for this using Handler. You can use postDelayed to minimal as 100 and run your animating tasks. In your case it would be:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
final String s = getGiphyViews(String.valueOf(mEdit.getText()));
runOnUiThread(new Runnable() {
#Override
public void run() {
result.setText(s);
}
});
loading.animate()
.alpha(0)
.setDuration(100);
done.animate()
.scaleY(1)
.scaleX(1)
.setDuration(300);
}
}, 100);
I had this problem today and above work resolved the problem. I would love to hear from anyone if there is any problem with this method.
Kotlin
If you still want to use a delay (or not)
Handler(Looper.getMainLooper()).postDelayed({
// Your Code
}, 1000)
Put Code Where Are getting error and doing any network operations
new Handler().post(new Runnable() {
#Override
public void run() {
// add your code here
}
});
I think you can create a main handler instance in your activity and override handle message method. you can save a handler quote in your work thread.When you finished work you can use handler to send a message and you receive message in handle message method. To start animation from handler message method and so on...

InvokeAndBlock causing EDT violation, everytime I used after showModeless dialog

I am using InvokeAndBlock whenever any process based function performed. for example.
If I want to save something and it takes while to save the data then i used below code.
First show process dialog.
initProcessDialog();
progressDialog.showModeless(); // show process dialog
//Actual process
Display.getInstance().invokeAndBlock(new Runnable() {
public void run() {
saveAll("SAVE_ALL",jobData);
FileUtil.removeBackupFile(jobDataDetail.getJobTemplateFileName());
progressDialog.dispose();
}
});
also added InvokeAndBlock while any action performed which is time-consuming.
backButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
initLoadingDialog();
loadingDialog.showModeless();
Display.getInstance().invokeAndBlock(new Runnable() {
public void run() {
}
});
}
});
Any correction require in process ?
Since your calls to invokeAndBlock are mostly related to your own code its hard to tell what exactly you are doing.
The call to dialog.dispose() within invokeAndBlock is wrong. You need to call it after the invokeAndBlock which will work exactly the same without the EDT violation.
Codename One has one UI thread: the EDT.
invokeAndBlock opens a separate thread where you aren't allowed to access any UI related API's.

Runnable concurrency

I am playing around with JMonkeyEngine.
While doing this i play JavaFX MediaPlayer.
This MediaPlayer takes a Runnable to handle what's to do, when the media finished:
mp.setOnEndOfMedia(new Runnable() {
#Override public void run() {
}}
I want to do sth. like this:
mp.setOnEndOfMedia(new Runnable() {
#Override public void run() {
// instance.toggleLists();
initMediaPlayer(mediaView, actualList.getPath()+actualList.getMediaLocation());
detachChild(node);
node = new TextureNode("mediaManagerTextureNode");
node.init(app, mp);
attachChild(node);
}
});
this is working a couple of times, but finally i am running into some runtime error.
java.lang.IllegalStateException: Scene graph is not properly updated for rendering.
State was changed after rootNode.updateGeometricState() call.
Make sure you do not modify the scene from another thread!
Problem spatial name: Root Node
Yeah, that's true. I am messing up that thread from the outside.
As i am a little bit unused to this stuff...
I don't need to do that thing at that location in that run method, it's just what has to be done,when this is running.
What is the best way to pass over the work so that my ordinary update call can do that housework ?
I already tried to build in a flag, setting that to true and when true, updating that by the standard update call from the application itself, but somehow i ever run into this error. That didn't help me much.
The MediaPlayer just needs to tell my App "Hey! I'm ready! Give me a break and change me to something new!"
That is, what is happening in that run method.
You can use Application.enqueue to make a Runnable run on the main thread in the next update - like so: (assuming app is a reference to the Application)
mp.setOnEndOfMedia(new Runnable() {
#Override public void run() {
app.enqueue(new Runnable() {
#Override public void run() {
initMediaPlayer(mediaView, actualList.getPath()+actualList.getMediaLocation());
detachChild(node);
node = new TextureNode("mediaManagerTextureNode");
node.init(app, mp);
attachChild(node);
}
});
}
});
If you're using Java 8, you can abbreviate this using lambda expressions:
mp.setOnEndOfMedia(() -> {app.enqueue(() -> {
initMediaPlayer(mediaView, actualList.getPath()+actualList.getMediaLocation());
detachChild(node);
node = new TextureNode("mediaManagerTextureNode");
node.init(app, mp);
attachChild(node);
}});

Categories

Resources