【问题标题】:Android View Canvas onDraw not performedAndroid View Canvas onDraw 未执行
【发布时间】:2017-01-10 12:44:37
【问题描述】:

我目前正在开发一个在画布上绘制一些图块的自定义视图。 这些图块是从多个文件中加载的,并会在需要时加载。

它们将由 AsyncTask 加载。如果它们已经加载,它们只会被绘制在画布上。 这工作正常!

如果加载了这些图片,AsyncTask 将触发 view.postInvalidate() 问题是每次我触发 view.postInvalidate() 时,我的自定义视图 没有触发 onDraw(Canvas canvas)。

view.postInvalidate 仅在加载图片时触发 onDraw() 方法第一次,然后仅当我在内部的 onTouchEvent 中触发 this.invalidate() 时我的自定义视图

视图是否有可能决定是否再次绘制画布? 有没有办法强制视图重绘?我认为 invalidate 方法告诉 View 如果 View 考虑重绘会很酷-.-

这些无效方法是否有限制?

我希望你们中的任何人都知道这个问题。

编辑:

我只是将 every postInvalidate() 更改为 invalidate() 因为图像都是由从主线程执行的 AsyncTask 加载的 但是仍然存在执行的 invalidate() 没有执行 onDraw() 方法的问题。 我发现 view.invalidate() 是通过覆盖原始方法触发的:

@Override
public void invalidate() {
    super.invalidate();
    Log.d(TAG, "invalidate executed");
}

我现在不知道该怎么办。我正在触发 view.invalidate() 和 view.postInvalidate() 但绝对没有任何组合。

【问题讨论】:

    标签: java android view android-canvas invalidation


    【解决方案1】:

    这里有点误会。 invalidate 和 postInvalidate 方法用于告诉 View 在最早的绘制周期内需要刷新和重绘。区别在于 invalidate 方法应该在 UI Thread 内调用,而 postInvalidate 应该从 UI Thread 外调用。

    这里简要介绍这些方法:

    另一方面,AsyncTask 是专门针对您面临的问题而设计的课程。当您需要在后台执行一项大任务时,您需要异步执行 AsyncTask,但是! AsyncTask 的回调方法在 UIThread 中运行!

    看看这里对 AsyncTask 方法的解释:

    当一个异步任务被执行时,任务会经过4个步骤:

    1. onPreExecute(),在任务执行后立即在 UI 线程上调用。此步骤通常用于设置任务,例如在用户界面中显示进度条。

    2. doInBackground(Params...),在 onPreExecute() 执行完成后立即在后台线程上调用。此步骤用于执行可能需要很长时间的后台计算。异步任务的参数传递到这一步。计算的结果必须由这一步返回,并将传递回最后一步。此步骤还可以使用 publishProgress(Progress...) 来发布一个或多个进度单位。这些值在 UI 线程的 onProgressUpdate(Progress...) 步骤中发布。

    3. onProgressUpdate(Progress...),在调用 publishProgress(Progress...) 后在 UI 线程上调用。执行的时间是不确定的。此方法用于在后台计算仍在执行时在用户界面中显示任何形式的进度。例如,它可用于动画进度条或在文本字段中显示日志。

    4. onPostExecute(Result),在后台计算完成后在 UI 线程上调用。后台计算的结果作为参数传递给这一步。

    这意味着在 onPostExecute 方法中你应该尝试使用 invalidate 方法而不是 postInvalidate 方法,因为它是从 UIThread 调用的。

    【讨论】:

    • 好的,谢谢。还没想过。现在我为每个 AsyncTask 使用 view.invalidate()。
    【解决方案2】:

    你听说过调用 setWillNotDraw(boolean) 的方法吗?

    看看here

    设置为false,你会看到

    【讨论】:

      【解决方案3】:

      只是为了将来和可能的谷歌搜索者保存这个;)

      我创建了一个新类,为我的视图提供数据。此类扩展 Thread 并在后台运行。它检查我的视图必须显示哪些图块。

      长话短说:每次必须显示新图块时,我的提供程序类都会收集一些更新请求。 如果“收集”了 3 个或更多更新请求,或者距离第一次更新请求超过 1 秒,则视图将获取 view.postInvalidate()。

      问题在于,如果您同时触发多个请求,视图会忽略一些无效请求。如果您收集这些无效请求并仅使用一个 invalidate() 触发其中几个请求,您可以在一小段时间内看到最新信息 - 但您可以看到它;)

      【讨论】:

        【解决方案4】:

        我已经解决了请求 view.invalidate()view.postInvalidate() 的问题,而不是单独使每个子视图无效(这些子视图中的每一个都包含自己的 AsyncTask),而是使它们共同的父 ViewGroup 无效。

        现在详细介绍。我有

        public class mViewGroup extends RelativeLayout {...}
        

        里面还有几个View,每个View如下:

        public class mView extends View {
        
        private mViewGroup mContext = null;
        
        //with a little bit modified standard constructors:
        public mView (Context context, mViewGroup ParentViewGroup) {
                super(context);
                mContext = ParentViewGroup;
        }
        
        //and also with an AsyncTask:
        private class mViewAsyncTask extends AsyncTask<Integer, Void, Void> {
        public mAsyncTask() {
           @Override
           protected Void doInBackground(Integer... a) {
               //which does its work and sometimes publishes progress:
               publishProgress();
               return null;
           }
        
           protected void onProgressUpdate(Void... progress) {
               invalidate();
           }
        
        }
        

        invalidate(); 的调用有时有效,有时无效(可能是从属于不同mViews 的不同AsyncTasks 进行的调用,但时间非常接近)。

        变化

        invalidate(); //i.e. invalidating individual View
        

        mContext.invalidate(); //i.e. invalidating the whole ViewGroup

        解决了问题。

        【讨论】:

          【解决方案5】:

          在我的情况下,目标自定义视图当时具有 height = 0 属性。(我的错误) 而 postInvalidate() 和 invalidate 也没有触发 onDraw() 和 Log。

          当我正确更改高度时,所有问题都解决了。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-03-07
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多