Android View Canvas onDraw未执行

时间:2012-09-03 20:59:32

标签: java android view android-canvas invalidation

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

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

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

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

View是否有可能决定是否再次绘制画布? 有没有办法 FORCE 视图重绘?我认为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(),但绝对没有任何组合。

5 个答案:

答案 0 :(得分:1)

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

这里简要介绍这些方法:

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

中运行

在这里看一下AsyncTask方法的解释:

执行异步任务时,任务将经历4个步骤:

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

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

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

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

  8.   

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

答案 1 :(得分:1)

您是否听说过方法调用setWillNotDraw(boolean)?

查看here

将其设置为false,您将看到

答案 2 :(得分:0)

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

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

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

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

答案 3 :(得分:0)

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

现在详细说明。我有

public class mViewGroup extends RelativeLayout {...}

和其中的几个视图,每个视图如下:

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的调用来自不同的mView,则可能会出现这种情况。时间)。

更改

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

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

解决了这个问题。

答案 4 :(得分:0)

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

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