I've encountered a very weird feature.
我遇到了一个非常奇怪的功能。
When I'm trying to run an animation on the main thread, it does not start. When I run said animation using
当我试图在主线程上运行动画时,它不会启动。当我使用运行所述动画
getView().post(new Runnable() {
@Override
public void run() {
getView().startAnimation(a);
}
});
It does start.
它确实开始了。
I've printed the CurrentThread
before starting the animation and both print main
.
我在开始动画之前打印了CurrentThread并且都打印了main。
Obviously, I am missing something here, as both should start the animation on the main thread... My guess is that as post adds the task to the queue, it starts at a more "correct time", but I would love to know what happens here at more depth.
显然,我在这里遗漏了一些东西,因为两者都应该在主线程上启动动画......我的猜测是,当post将任务添加到队列中时,它会在更“正确的时间”开始,但我很想知道这里发生的事情更深入。
EDIT: Let me clear things up - my question is, why starting the animation on post causes it to start, when starting the animation on the main thread does not.
编辑:让我清楚 - 我的问题是,为什么在帖子上启动动画会导致它启动,当在主线程上启动动画时没有。
4 个解决方案
#1
128
post :post causes the Runnable to be added to the message queue,
post:post导致Runnable被添加到消息队列中,
Runnable : Represents a command that can be executed. Often used to run code in a different Thread.
Runnable:表示可以执行的命令。通常用于在不同的线程中运行代码。
run () : Starts executing the active part of the class' code. This method is called when a thread is started that has been created with a class which implements Runnable.
run():开始执行类'代码的活动部分。当启动一个使用实现Runnable的类创建的线程时,将调用此方法。
getView().**post**(new **Runnable**() {
@Override
public void run() {
getView().startAnimation(a);
}
});
code : getView().startAnimation(a);
code:getView()。startAnimation(a);
in your code,
在你的代码中,
post causes the Runnable (the code will be run a in different thread) to add the message queue.
post导致Runnable(代码将在不同的线程中运行)添加消息队列。
So startAnimation will be fired in a new thread when it is fetched from the messageQueue
因此,当从messageQueue获取startAnimation时,将在新线程中触发startAnimation
[EDIT 1]
[编辑1]
Why do we use a new thread instead of UI thread (main thread)?
为什么我们使用新线程而不是UI线程(主线程)?
UI Thread :
UI线程:
-
When application is started, Ui Thread is created automatically
启动应用程序时,将自动创建Ui线程
-
it is in charge of dispatching the events to the appropriate widgets and this includes the drawing events.
它负责将事件分派给适当的小部件,这包括绘图事件。
-
It is also the thread you interact with Android widgets with
它也是您与Android小部件交互的线程
For instance, if you touch the a button on screen, the UI thread dispatches the touch event to the widget which in turn sets its pressed state and posts an invalidate request to the event queue. The UI thread dequeues the request and notifies the widget to redraw itself.
例如,如果触摸屏幕上的a按钮,UI线程会将触摸事件调度到窗口小部件,窗口小部件又设置其按下状态并将无效请求发布到事件队列。 UI线程使请求出列并通知窗口小部件重绘自身。
What happens if a user press a button which will do longOperation ?
如果用户按下将执行longOperation的按钮会发生什么?
((Button)findViewById(R.id.Button1)).setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
final Bitmap b = loadImageFromNetwork();
mImageView.setImageBitmap(b);
}
});
The UI freezes. The program may even crash.
用户界面冻结了。该计划甚至可能会崩溃。
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
final Bitmap b = loadImageFromNetwork();
mImageView.setImageBitmap(b);
}
}).start();
}
It breaks the android rule that never update UI directly from worker thread
它打破了永远不会直接从工作线程更新UI的android规则
Android offers several ways to access the UI thread from other threads.
Android提供了几种从其他线程访问UI线程的方法。
- Activity.runOnUiThread(Runnable)
- Activity.runOnUiThread(可运行)
- View.post(Runnable)
- View.post(可运行)
- View.postDelayed(Runnable, long)
- View.postDelayed(Runnable,long)
- Handler
- 处理器
Like below,
如下,
View.post(Runnable)
View.post(可运行)
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
final Bitmap b = loadImageFromNetwork();
mImageView.post(new Runnable() {
public void run() {
mImageView.setImageBitmap(b);
}
});
}
}).start();
}
Handler
处理器
final Handler myHandler = new Handler();
(new Thread(new Runnable() {
@Override
public void run() {
final Bitmap b = loadImageFromNetwork();
myHandler.post(new Runnable() {
@Override
public void run() {
mImageView.setImageBitmap(b);
}
});
}
})).start();
}
For more info
有关更多信息
http://android-developers.blogspot.com/2009/05/painless-threading.html
http://android-developers.blogspot.com/2009/05/painless-threading.html
http://www.aviyehuda.com/blog/2010/12/20/android-multithreading-in-a-ui-environment/
http://www.aviyehuda.com/blog/2010/12/20/android-multithreading-in-a-ui-environment/
#2
18
Is this being done on onCreate or onCreateView? If so, the app might not be in a state where the View is attached to the window. A lot of algorithms based on View metrics may not work since things like the View's measurements and position may have not been calculated. Android animations typically require them to run through UI math
这是在onCreate还是onCreateView上完成的?如果是这样,应用程序可能不处于视图附加到窗口的状态。许多基于View度量的算法可能无法工作,因为可能尚未计算View的度量和位置等内容。 Android动画通常要求它们通过UI数学运行
View.post actually queues the animation on the View's message loop, so once the view gets attached to the window, it executes the animation instead of having it execute manually.
View.post实际上是在View的消息循环中对动画进行排队,因此一旦视图附加到窗口,它就会执行动画而不是手动执行。
You are actually running things on the UI thread, but at a different time
您实际上是在UI线程上运行,但在不同的时间运行
#3
15
Have a look here for a good answer. view.post() is the same as handler.post() pretty much. It goes into the main thread queue and gets executed after the other pending tasks are finished. If you call activity.runOnUiThread() it will be called immediately on the UI thread.
看看这里有一个很好的答案。 view.post()与handler.post()非常相似。它进入主线程队列并在其他待处理任务完成后执行。如果调用activity.runOnUiThread(),它将立即在UI线程上调用。
#4
2
The problem I think could be the life-cycle method where you are calling the post() method. Are you doing it in onCreate()? if so look at what I found in the activity's onResume() documentation:
我认为问题可能是你调用post()方法的生命周期方法。你是在onCreate()吗?如果是这样看看我在活动的onResume()文档中找到了什么:
onResume()
的onResume()
Added in API level 1 void onResume () Called after onRestoreInstanceState(Bundle), onRestart(), or onPause(), for your activity to start interacting with the user. This is a good place to begin animations, open exclusive-access devices (such as the camera), etc.
在API级别1中添加void onResume()在onRestoreInstanceState(Bundle),onRestart()或onPause()之后调用,以使您的活动开始与用户交互。这是开始动画,打开独家访问设备(如相机)等的好地方。
https://developer.android.com/reference/android/app/Activity.html#onResume()
https://developer.android.com/reference/android/app/Activity.html#onResume()
So, as Joe Plante said, maybe the view is not ready to start animations at the moment you call post(), so try moving it to onResume().
因此,正如Joe Plante所说,也许视图还没有准备好在你调用post()时启动动画,所以尝试将它移动到onResume()。
PD: Actually if you do move the code to onResume() then I think you can remove the post() call since you are already in the ui-thread and the view should be ready to start animations.
PD:实际上如果你确实将代码移动到onResume(),那么我认为你可以删除post()调用,因为你已经在ui-thread中了,视图应该准备开始动画了。
#1
128
post :post causes the Runnable to be added to the message queue,
post:post导致Runnable被添加到消息队列中,
Runnable : Represents a command that can be executed. Often used to run code in a different Thread.
Runnable:表示可以执行的命令。通常用于在不同的线程中运行代码。
run () : Starts executing the active part of the class' code. This method is called when a thread is started that has been created with a class which implements Runnable.
run():开始执行类'代码的活动部分。当启动一个使用实现Runnable的类创建的线程时,将调用此方法。
getView().**post**(new **Runnable**() {
@Override
public void run() {
getView().startAnimation(a);
}
});
code : getView().startAnimation(a);
code:getView()。startAnimation(a);
in your code,
在你的代码中,
post causes the Runnable (the code will be run a in different thread) to add the message queue.
post导致Runnable(代码将在不同的线程中运行)添加消息队列。
So startAnimation will be fired in a new thread when it is fetched from the messageQueue
因此,当从messageQueue获取startAnimation时,将在新线程中触发startAnimation
[EDIT 1]
[编辑1]
Why do we use a new thread instead of UI thread (main thread)?
为什么我们使用新线程而不是UI线程(主线程)?
UI Thread :
UI线程:
-
When application is started, Ui Thread is created automatically
启动应用程序时,将自动创建Ui线程
-
it is in charge of dispatching the events to the appropriate widgets and this includes the drawing events.
它负责将事件分派给适当的小部件,这包括绘图事件。
-
It is also the thread you interact with Android widgets with
它也是您与Android小部件交互的线程
For instance, if you touch the a button on screen, the UI thread dispatches the touch event to the widget which in turn sets its pressed state and posts an invalidate request to the event queue. The UI thread dequeues the request and notifies the widget to redraw itself.
例如,如果触摸屏幕上的a按钮,UI线程会将触摸事件调度到窗口小部件,窗口小部件又设置其按下状态并将无效请求发布到事件队列。 UI线程使请求出列并通知窗口小部件重绘自身。
What happens if a user press a button which will do longOperation ?
如果用户按下将执行longOperation的按钮会发生什么?
((Button)findViewById(R.id.Button1)).setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
final Bitmap b = loadImageFromNetwork();
mImageView.setImageBitmap(b);
}
});
The UI freezes. The program may even crash.
用户界面冻结了。该计划甚至可能会崩溃。
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
final Bitmap b = loadImageFromNetwork();
mImageView.setImageBitmap(b);
}
}).start();
}
It breaks the android rule that never update UI directly from worker thread
它打破了永远不会直接从工作线程更新UI的android规则
Android offers several ways to access the UI thread from other threads.
Android提供了几种从其他线程访问UI线程的方法。
- Activity.runOnUiThread(Runnable)
- Activity.runOnUiThread(可运行)
- View.post(Runnable)
- View.post(可运行)
- View.postDelayed(Runnable, long)
- View.postDelayed(Runnable,long)
- Handler
- 处理器
Like below,
如下,
View.post(Runnable)
View.post(可运行)
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
final Bitmap b = loadImageFromNetwork();
mImageView.post(new Runnable() {
public void run() {
mImageView.setImageBitmap(b);
}
});
}
}).start();
}
Handler
处理器
final Handler myHandler = new Handler();
(new Thread(new Runnable() {
@Override
public void run() {
final Bitmap b = loadImageFromNetwork();
myHandler.post(new Runnable() {
@Override
public void run() {
mImageView.setImageBitmap(b);
}
});
}
})).start();
}
For more info
有关更多信息
http://android-developers.blogspot.com/2009/05/painless-threading.html
http://android-developers.blogspot.com/2009/05/painless-threading.html
http://www.aviyehuda.com/blog/2010/12/20/android-multithreading-in-a-ui-environment/
http://www.aviyehuda.com/blog/2010/12/20/android-multithreading-in-a-ui-environment/
#2
18
Is this being done on onCreate or onCreateView? If so, the app might not be in a state where the View is attached to the window. A lot of algorithms based on View metrics may not work since things like the View's measurements and position may have not been calculated. Android animations typically require them to run through UI math
这是在onCreate还是onCreateView上完成的?如果是这样,应用程序可能不处于视图附加到窗口的状态。许多基于View度量的算法可能无法工作,因为可能尚未计算View的度量和位置等内容。 Android动画通常要求它们通过UI数学运行
View.post actually queues the animation on the View's message loop, so once the view gets attached to the window, it executes the animation instead of having it execute manually.
View.post实际上是在View的消息循环中对动画进行排队,因此一旦视图附加到窗口,它就会执行动画而不是手动执行。
You are actually running things on the UI thread, but at a different time
您实际上是在UI线程上运行,但在不同的时间运行
#3
15
Have a look here for a good answer. view.post() is the same as handler.post() pretty much. It goes into the main thread queue and gets executed after the other pending tasks are finished. If you call activity.runOnUiThread() it will be called immediately on the UI thread.
看看这里有一个很好的答案。 view.post()与handler.post()非常相似。它进入主线程队列并在其他待处理任务完成后执行。如果调用activity.runOnUiThread(),它将立即在UI线程上调用。
#4
2
The problem I think could be the life-cycle method where you are calling the post() method. Are you doing it in onCreate()? if so look at what I found in the activity's onResume() documentation:
我认为问题可能是你调用post()方法的生命周期方法。你是在onCreate()吗?如果是这样看看我在活动的onResume()文档中找到了什么:
onResume()
的onResume()
Added in API level 1 void onResume () Called after onRestoreInstanceState(Bundle), onRestart(), or onPause(), for your activity to start interacting with the user. This is a good place to begin animations, open exclusive-access devices (such as the camera), etc.
在API级别1中添加void onResume()在onRestoreInstanceState(Bundle),onRestart()或onPause()之后调用,以使您的活动开始与用户交互。这是开始动画,打开独家访问设备(如相机)等的好地方。
https://developer.android.com/reference/android/app/Activity.html#onResume()
https://developer.android.com/reference/android/app/Activity.html#onResume()
So, as Joe Plante said, maybe the view is not ready to start animations at the moment you call post(), so try moving it to onResume().
因此,正如Joe Plante所说,也许视图还没有准备好在你调用post()时启动动画,所以尝试将它移动到onResume()。
PD: Actually if you do move the code to onResume() then I think you can remove the post() call since you are already in the ui-thread and the view should be ready to start animations.
PD:实际上如果你确实将代码移动到onResume(),那么我认为你可以删除post()调用,因为你已经在ui-thread中了,视图应该准备开始动画了。