3

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

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

如果加载了这些图片,则 AsyncTask 正在触发view.postInvalidate() 问题是我的自定义视图在每次触发 view.postInvalidate() 时都不会触发onDraw(Canvas canvas)。

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

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

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

我希望你们中的任何人都对这个问题有更多的了解。

编辑:

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

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

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

4

5 回答 5

1

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

这些方法在这里简要描述:

另一方面, 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 方法而不是从 UIThread 调用的 postInvalidate 方法。

于 2012-09-03T21:33:01.217 回答
1

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

在这里查看

将其设置为false,您会看到

于 2014-12-04T16:04:09.027 回答
0

我已经解决了请求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();有时有效,有时无效(如果调用是AsyncTask从属于不同s 的不同mViews 但在非常接近的时刻进行的)。

改变

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

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

解决了这个问题。

于 2013-11-02T11:56:37.960 回答
0

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

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

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

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

于 2012-09-06T13:13:38.040 回答
0

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

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

于 2017-01-10T04:44:37.877 回答