====================问题描述====================
我现在有一个需求,要自定义View,初始化的时候调用了onDraw方法,完后我自定义一个方法,调用该方法的时候,要重新调用onDraw方法,但我用postInvalidate无效,代码如下:
启动类:
public class MainActivity extends Activity { TestOnDraw view; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); view = (TestOnDraw) findViewById(R.id.test); new Thread(new Runnable() { @Override public void run() { view.test(); } }).start(); } }
布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <com.example.testdraw.TestOnDraw android:id="@+id/test" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
自定义View
public class TestOnDraw extends View { public TestOnDraw(Context context) { this(context, null); } public TestOnDraw(Context context, AttributeSet attrs) { this(context, attrs, 0); } public TestOnDraw(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); Log.d("test", "in"); } public void test() { postInvalidate(); } }
我查看日志,onDraw方法只进了一次,就是说postInvalidate();没有生效,我如何修改能实现在初始化进入onDraw后,调用test方法时再次进入onDraw方法
====================解决方案1====================
onDraw()的方法是当在屏幕中需要显示界面的时候才调用的,android会判断某个界面是否需要绘制,如果不需要就根本不会调用到他的onDraw 方法, 例如你把你的自定义view设置为GONE,那么你根本看不到打出来的log了
另外,为什幺要调用postInviliade呢, Java 的动态绑定机制不是会默认调用子类的onDraw方法吗? 你在线程中再调取一次postInvliade有什么意义吗?
====================解决方案2====================
..那就在 onDraw() 里调用invaliade,另外建议使用Surface View 实现,避免阻塞线程
====================解决方案3====================
我觉得在view = (TestOnDraw) findViewById(R.id.test)时onDraw并不是延迟执行了,而是根本就没有执行。
执行了,我说清空test方法就是将test方法弄成空实现,里面一行代码都没有,完后可以看到onDraw还是调用了的
postInvalidate() 是往UI队列中丢一个线程,之后开始渲染流程。
在onCreate中 所有的界面并没有实际生成,所以会优先执行postInvalidate中的代码(这个在渲染队列前头)。
但是这个是没有效果的。 view 中有个skipInvalidate()方法 说的就是 当view未显示时候,是被skip掉的。
假如你delay了这个1-2秒, 这个代码执行时后界面已经生成了,他的invalidate就生效, 就会出现你想要的执行两次。
另 界面生成时候,必然会调用一次onDraw。
/**
* Invalidate the whole view. If the view is visible,
* {@link #onDraw(android.graphics.Canvas)} will be called at some point in
* the future. This must be called from a UI thread. To call from a non-UI thread,
* call {@link #postInvalidate()}.
*/
public void invalidate() {
invalidate(true);
}
public void invalidate(Rect dirty) {
if (skipInvalidate()) {
return;
}
}
}