AsyncTask:无效视图不生效
AsyncTask: invalidating view does not take effect
更新
我的小陈列柜存储在 Bitbucket 上
https://bitbucket.org/solvapps/animationtest
我有一个 Activity,其中有一个视图。 Contentview
设置为此视图。
public class MainActivity extends AppCompatActivity {
private MyView myView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myView = new MyView(this);
setContentView(myView);
startMovie();
}
public void startMovie(){
MovieTask movieTask = new MovieTask(myView, this);
movieTask.doInBackground(null);
}
}
MovieTask 是一个 Asynctask,它会定期刷新视图。
但是 invalidate() 不会刷新视图。
public class MovieTask extends AsyncTask<String, String, String> {
MyView drawingView;
MainActivity mainActivity;
public MovieTask(MyView view, MainActivity mainActivity){
this.mainActivity = mainActivity;
this.drawingView =view;
}
@Override
protected String doInBackground(String... strings) {
for(int i=20;i<100;i++){
drawingView.myBall.goTo(i,i);
publishProgress();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
mainActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
Log.v("DEBUG_DRAW","in onProgressUpdate()");
drawingView.invalidate();
}
});
}
}
有人可以帮忙吗?
有两种可能的情况,第一种如documents所述:
void invalidate ()
Invalidate the whole view. If the view is visible,
onDraw(android.graphics.Canvas) will be called at some point in the
future.
所以尝试 运行 你在 onResume
中的代码,有可能 View
还不可见。
其次,View#invalidate
告诉系统在主 UI 线程空闲时立即重绘视图。也就是说,调用 invalidate 会安排您的视图在所有其他直接工作完成后重新绘制。
如果您希望定期更新视图,请在单独的线程中使用 Handler#postDelay
或 运行 并使用 View#postInvalidate
更新 View
并触发调用 onDraw
.
看看你是如何启动 AsyncTask
:
public void startMovie() {
MovieTask movieTask = new MovieTask(myView, this);
movieTask.doInBackground(null);
}
您在某些 class 中手动调用一个名为 MovieTask
的方法,因此您 运行 在同一个线程上调用了一个代码。显然,这不是您的意图,您打算 运行 后台线程上的计算代码。
启动 AsyncTask
的正确方法是使用 execute(Params...)
:
public void startMovie() {
MovieTask movieTask = new MovieTask(myView, this);
movieTask.execute("");
}
现在你会得到想要的效果。
P.S.
请不要使用该代码:您不需要启动后台线程来执行此类操作。作为替代方案,请考虑 Animators API.
在 MyBall
中声明 setBall(int pos)
方法 class:
public class MyView extends View {
...
public void setBall(int pos) {
myBall.setX(pos);
myBall.setY(pos);
invalidate();
}
}
然后将 startMovie()
更改为以下内容:
public void startMovie() {
// "ball" means, that Animators API will search for `public setBall(int)` method inside MyView.java and call that method
ObjectAnimator ball = ObjectAnimator.ofInt(myView, "ball", 20, 100);
ball.setDuration(1000);
ball.start();
}
您将获得相同的动画,而无需讨厌的代码。
更新
我的小陈列柜存储在 Bitbucket 上
https://bitbucket.org/solvapps/animationtest
我有一个 Activity,其中有一个视图。 Contentview
设置为此视图。
public class MainActivity extends AppCompatActivity {
private MyView myView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myView = new MyView(this);
setContentView(myView);
startMovie();
}
public void startMovie(){
MovieTask movieTask = new MovieTask(myView, this);
movieTask.doInBackground(null);
}
}
MovieTask 是一个 Asynctask,它会定期刷新视图。 但是 invalidate() 不会刷新视图。
public class MovieTask extends AsyncTask<String, String, String> {
MyView drawingView;
MainActivity mainActivity;
public MovieTask(MyView view, MainActivity mainActivity){
this.mainActivity = mainActivity;
this.drawingView =view;
}
@Override
protected String doInBackground(String... strings) {
for(int i=20;i<100;i++){
drawingView.myBall.goTo(i,i);
publishProgress();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
mainActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
Log.v("DEBUG_DRAW","in onProgressUpdate()");
drawingView.invalidate();
}
});
}
}
有人可以帮忙吗?
有两种可能的情况,第一种如documents所述:
void invalidate () Invalidate the whole view. If the view is visible, onDraw(android.graphics.Canvas) will be called at some point in the future.
所以尝试 运行 你在 onResume
中的代码,有可能 View
还不可见。
其次,View#invalidate
告诉系统在主 UI 线程空闲时立即重绘视图。也就是说,调用 invalidate 会安排您的视图在所有其他直接工作完成后重新绘制。
如果您希望定期更新视图,请在单独的线程中使用 Handler#postDelay
或 运行 并使用 View#postInvalidate
更新 View
并触发调用 onDraw
.
看看你是如何启动 AsyncTask
:
public void startMovie() {
MovieTask movieTask = new MovieTask(myView, this);
movieTask.doInBackground(null);
}
您在某些 class 中手动调用一个名为 MovieTask
的方法,因此您 运行 在同一个线程上调用了一个代码。显然,这不是您的意图,您打算 运行 后台线程上的计算代码。
启动 AsyncTask
的正确方法是使用 execute(Params...)
:
public void startMovie() {
MovieTask movieTask = new MovieTask(myView, this);
movieTask.execute("");
}
现在你会得到想要的效果。
P.S.
请不要使用该代码:您不需要启动后台线程来执行此类操作。作为替代方案,请考虑 Animators API.
在 MyBall
中声明 setBall(int pos)
方法 class:
public class MyView extends View {
...
public void setBall(int pos) {
myBall.setX(pos);
myBall.setY(pos);
invalidate();
}
}
然后将 startMovie()
更改为以下内容:
public void startMovie() {
// "ball" means, that Animators API will search for `public setBall(int)` method inside MyView.java and call that method
ObjectAnimator ball = ObjectAnimator.ofInt(myView, "ball", 20, 100);
ball.setDuration(1000);
ball.start();
}
您将获得相同的动画,而无需讨厌的代码。