AsyncTask:使视图无效不会生效

时间:2018-03-16 08:58:17

标签: java android android-asynctask android-animation android-view

更新

我的小橱窗存放在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是一个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();
            }
        });

    }

}

有人可以帮忙吗?

2 个答案:

答案 0 :(得分:7)

了解如何启动AsyncTask


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

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

正确启动AsyncTask的方法正在使用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();
    }

你会得到相同的动画而没有讨厌的代码。

答案 1 :(得分:0)

有两种可能的情况,首先如documents中所述:

  

void invalidate()   使整个视图无效。如果视图可见,   onDraw(android.graphics.Canvas)将在某个时刻被调用   将来

因此,请尝试在onResume中运行您的代码,View可能尚未显示。

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

如果您希望定期更新视图,请使用Handler#postDelay或在单独的线程中运行,并使用View#postInvalidate更新View并触发对{{1}的调用}}