I have a WebView in my activity, which have a JSInterface :
mWebView.addJavascriptInterface(new JSInterface(mWebView, this), "interfaceWebsite");
When I call a function in my interface, I would like to see some Views (Textview/Button) modified.
public void changeStep(int newStep){
step = newStep;
tvStep.setText("Etape "+step);
step_info = getString(R.string.step3_info);
}
}
step_info works (my options menu change), it's just a string var, but not my TextView, it throw VM aborting.
I call the function this way (where addWebsiteActivity is "this" in the code above) :
addWebsiteActivity.changeStep(step);
Is this possible to do that in a proper way ?
Thanks
Only the original thread that created a view hierarchy can touch its views
Taht's why I can call changeStep from JSInterface but I can inside my activity class... How can I do that then ?
And the solution is...
runOnUiThread(new Runnable() {
public void run() {
step = newStep;
tvStep.setText("Etape "+step);
step_info = getString(R.string.step3_info);
}
});
Like this it knows it's a code for the main thread. But it's strange Eclipse throw me VM aborting exept that the explicit error above...
changeStep method must be called inside UI thread. You can achieved this with runOnUiThread:
addWebsiteActivity.runOnUiThread(new Runnable() {
public void run() {
changeStep(step);
}
})
change step to newStep in your code
Related
My scenario is an onCreate() activity method which executes the following code (simplified):
dialog.show(); //loading wheel
try {
remote.sendRequest(myData, new MyHandler());
}
catch (Exception e) {
dialog.dismiss();
//log and react
}
class MyHandler extends SDKSpecificCompiledHandler {
#Override
public void failure() {
dialog.dismiss();
//do stuff
}
#override
public void success() {
dialog.dismiss();
//do stuff
}
}
//I have read-only access to this handler!
public abstract class SDKSpecificCompiledHandler {
public abstract void success(JSONObject successData);
public abstract void failure(JSONObject errorData);
}
Explanation: A remote service is called passing an handler that gets called when he's done. A loading wheel (dialog) is shown to the user until a success, failure or exception happens.
The problem is when the service gets successfully called but no response ever comes. In that case dialog.dismiss() doesn't get called and the loading wheel keeps spinning for ever.
What I need is a sort of timeout which dismisses the dialog (and possibly takes other actions) after some seconds if the server doesn't get back.
My first though would be to create a new thread for the service call, and right after the launch set a timer which dismisses the dialog.
Would it be a good idea?
Thank you,
EDIT:
The service is third-party/not editable. I'm using a pre-compiled artifact.
Still not really sure what you're trying to achieve but if you want to run some code after some time on main thread (i.e. your code will do stuff to the UI), you can use a android.os.Handler
mHandler = new Handler(getMainLooper());
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
// do stuff on UI thread
}
},10000);
When your call returned from the server, simply cancel the messages on the queue:
mHandler.removeCallbacksAndMessages(null);
It is better to use time out in service call itself, You can set the time out with service , If you need know how to set the time out then I should know what kind of service you are using ?
One more thing is that if you are using a loader you should make that loader in such a way that it can be cancel by the client.
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...
So, I have an activity with a handler.
private final Runnable m_Runnable = new Runnable()
{
public void run()
{
if(LiveAPI.getStatus() == 1){
matches = LiveAPI.getMatches();
listAdapter.notifyDataSetChanged();
}
LivePage.this.mHandler.postDelayed(m_Runnable, 5000);
}
};
Here I get some data and update my list with it. It works.
When I click on an item of my list, this functon is called
private void showLiveMatch(int position) {
Intent i = new Intent(this, LiveMatch.class);
i.putExtra("match", matches.get(position));
startActivity(i);
}
My new activity appears, wich also contains another handler:
private final Runnable m_Runnable = new Runnable()
{
public void run()
{
if(LiveAPI.getStatus() == 1){
match = LiveAPI.getMatch(match.getId());
displayCommentaries();
}
LiveMatch.this.mHandler.postDelayed(m_Runnable, 5000);
}
};
Sometimes this works as I want.
But in some cases it seems like in second activity is still called LiveAPI.getMatches() from the first handler rather than LiveAPI.getMatch(match.getId());
Every function displays a console text, and that's how I figure it out what function is called.
Can someone explain me why?
Once you post either m_Runnable (from LivePage or LiveMatch), it does its stuff and then schedules itself to run in 5 seconds. Basically, each time you start one with a click, it creates an infinite loop. Enough clicks and you will have the logic for each of these running constantly. (That is, unless you have some other code that periodically calls mHandler.removeCallbacks(m_Runnable); that you haven't shown us.) Without knowing more about what you're trying to do, it's hard to recommend how to fix this, but you should somehow avoid creating these kind of infinite loops.
Be aware that all handlers you create on the UI thread simply feed Runnable objects into the (single) MessageQueue for the thread. So there's no such thing as something being called from one handler or another.
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);
}});
I am trying to understand how looper.loop works, and when to use it in my code.
I have a bound service that has a runnable. Inside I have a handler that is used to hold code that updates the Ui. Here is the code.
private Runnable builder = new Runnable() {
public void run()
{
while(isThreadStarted == true)
{
if (newgps == 1)
{
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
public void run() {
//some code that updates UI
}
}
}
}
}
looper.prepair
}
From what I read looper. prepare has to be called before the handler is made. But I noticed I didn’t do that but this code still works. How is this possible?
I want to fix this but im not sure where to put loper.loop. Because this handler is called many many times. Would it be ok if i put looper.loop right after .prepare? Then .quit when isThreadStarted == false?
The Handler is associated with the UI thread, since you attach it to Looper.getMainLooper(). The UI thread prepares its Looperon application start, so that is nothing the application has to do itself.
By using Looper.getMainLooper(), you get Handler of main thread and you are posting on main thread. Main thread has its looper prepared by system already when it is created.