代码之家  ›  专栏  ›  技术社区  ›  mcfly soft

AsyncTask:无效视图不会生效

  •  7
  • mcfly soft  · 技术社区  · 6 年前

    使现代化

    我的小橱窗存放在Bitbucket上

    https://bitbucket.org/solvapps/animationtest

    我有一个活动,其中有一个观点。 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是一个异步任务,它会定期刷新视图。 但是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();
                }
            });
    
        }
    
    }
    

    有人能帮忙吗?

    2 回复  |  直到 6 年前
        1
  •  6
  •   azizbekian    6 年前

    查看如何启动 AsyncTask :

    
        public void startMovie() {
            MovieTask movieTask = new MovieTask(myView, this);
            movieTask.doInBackground(null);
        }
    
    

    您正在手动调用一个名为 MovieTask ,因此您正在同一线程上运行代码。显然,这不是您的意图,您打算在后台线程上运行计算代码。

    正确的启动方式 异步任务 正在使用 execute(Params...) :

    
        public void startMovie() {
            MovieTask movieTask = new MovieTask(myView, this);
            movieTask.execute("");
        }
    
    

    现在您将获得所需的效果。


    P、 S。

    请不要使用该代码:您不需要启动后台线程来完成这类工作。作为替代方案,考虑 Animators API

    声明 setBall(int pos) 方法内部 MyBall 类别:

    
        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();
        }
    
    

    您将获得相同的动画,而不需要讨厌的代码。

        2
  •  0
  •   Keivan Esbati    6 年前

    有两种可能的情况,第一种如中所述 documents :

    无效无效() 使整个视图无效。如果视图可见, onDraw(android.graphics.Canvas)将在 将来

    因此,请尝试在中运行您的代码 onResume ,有可能 View 尚不可见。

    其次 View#invalidate 告诉系统在主UI线程空闲时立即重新绘制视图。也就是说,调用invalidate schedules可以在所有其他即时工作完成后重新绘制视图。

    如果希望定期更新视图,请使用 Handler#postDelay 或者在单独的线程中运行它并使用 View#postInvalidate 要更新 看法 并触发呼叫 onDraw