android - 在 onDraw() 中使用线程

标签 android multithreading ondraw

我正在编写一个应用程序并且我有一个自定义 View 。在这个自定义 View 中,我必须计算不确定数量的点的位置。点数取决于我从数据库中读取的内容(因此每个用户都不同)。 所以,我的问题是,我怎样才能很好地解决这个问题?该应用程序的步骤如下:

  1. Activity 开始
  2. 数据库查询
  3. 绘图

问题是当我打开 Activity 时调用了 onDraw() 方法,但我无法绘制任何东西,因为我必须等待数据库查询和计算点。在计算完成之前,我如何使用线程或者进度条之类的东西?我可以阻止应用程序在 Activity 开始时立即运行 onDraw() 方法吗?

感谢您的帮助。

edit1:所以这是代码(注意:我现在不想计算任何东西,出现错误是因为我尝试将 ProgressBar 的可见性设置为 true,没有这行它就可以工作):

    public class MyView extends View {
    private ProgressBar progressBar;
    private boolean calculationsDone;

    public MyView(Context context, AttributeSet attrs) {
            super(context);
            // TODO Auto-generated constructor stub

            progressBar = (ProgressBar) findViewById(R.id.progressBar1);
            calculationsDone=false;
        }

    protected void onDraw(final Canvas canvas) {
            super.onDraw(canvas);


            if(calculationsDone == true){
                //draw stuff
                progressBar.setVisibility(INVISIBLE);
            }else{
                Log.d("calcNotDone", "CALCULATION NOT DONE YET!");
                progressBar.setVisibility(VISIBLE);
            }

        }

    }

这里是错误:

03-31 20:45:44.131: E/AndroidRuntime(27445): FATAL EXCEPTION: main 03-31 20:45:44.131: E/AndroidRuntime(27445): java.lang.NullPointerException 03-31 20:45:44.131: E/AndroidRuntime(27445): at com.example.test.MyView.onDraw(MyView.java:50) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.draw(View.java:14853) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.getDisplayList(View.java:13744) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.getDisplayList(View.java:13786) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.draw(View.java:14563) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewGroup.drawChild(ViewGroup.java:3316) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3153) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.draw(View.java:14856) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.getDisplayList(View.java:13744) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.getDisplayList(View.java:13786) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.draw(View.java:14563) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewGroup.drawChild(ViewGroup.java:3316) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3153) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.getDisplayList(View.java:13739) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.getDisplayList(View.java:13786) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.draw(View.java:14563) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewGroup.drawChild(ViewGroup.java:3316) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3153) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.getDisplayList(View.java:13739) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.getDisplayList(View.java:13786) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.draw(View.java:14563) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewGroup.drawChild(ViewGroup.java:3316) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3153) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.draw(View.java:14856) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.widget.FrameLayout.draw(FrameLayout.java:467) 03-31 20:45:44.131: E/AndroidRuntime(27445): at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2621) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.getDisplayList(View.java:13744) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.getDisplayList(View.java:13786) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.HardwareRenderer$GlRenderer.buildDisplayList(HardwareRenderer.java:1411) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.HardwareRenderer$GlRenderer.draw(HardwareRenderer.java:1359) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewRootImpl.draw(ViewRootImpl.java:2672) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2538) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2154) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1249) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6364) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.Choreographer$CallbackRecord.run(Choreographer.java:791) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.Choreographer.doCallbacks(Choreographer.java:591) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.Choreographer.doFrame(Choreographer.java:561) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:777) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.os.Handler.handleCallback(Handler.java:730) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.os.Handler.dispatchMessage(Handler.java:92) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.os.Looper.loop(Looper.java:176) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.app.ActivityThread.main(ActivityThread.java:5419) 03-31 20:45:44.131: E/AndroidRuntime(27445): at java.lang.reflect.Method.invokeNative(Native Method) 03-31 20:45:44.131: E/AndroidRuntime(27445): at java.lang.reflect.Method.invoke(Method.java:525) 03-31 20:45:44.131: E/AndroidRuntime(27445): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046) 03-31 20:45:44.131: E/AndroidRuntime(27445): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862) 03-31 20:45:44.131: E/AndroidRuntime(27445): at dalvik.system.NativeStart.main(Native Method)

最佳答案

你应该研究一下 onDraw() 生命周期。

onDraw 在开始时被调用,然后每次有“something”要绘制时都会被调用。您如何告诉 View 它有“东西” 可以绘制?通过调用“invalidate”。

所以在您的 onDraw 上,如果点未加载,一开始您什么都不做

当您完成计算后,只需调用 invalidate()onDraw 稍后将被调用,异步。这时候,在您的 OnDraw 中,您会检测到您的计算已经准备就绪,所以然后就是您绘制这些东西的时候了。

种类:

 boolean myCalculationsAreReady=false;

 Paint mPaint=new Paint(); // to draw text "loading" ... (new edit). You have to call mPaint.setColor(Color.WHITE) or any color you want, the default would be Black.

 public void onDraw(Canvas canvas) {

      if (myCalculationsAreReady) {

            drawMyStuff (canvas);

      } else {

            // You don't have your calculations yet , just ignore, or paint a message ...
            drawDataNotReady(canvas);

      }

 }

 private void drawMyStuff (Canvas c) {
         // here you have your calculations available
         // time to draw !
 }

 // to make this view totally independent, you can create yourself a progress indicator here.
 // you can also put a standard progressbar at the parent level and notify the parent when
 // to show / hide it. I like this approach, because it's more efficient (you save one view)
 // but obviously you can use any fancy view you like over this one.

 private void drawDataNotReady (Canvas c) {
         c.drawText (0, c.getHeight() / 2, "Please wait while data is loading ...", mPaint); 
 }

 private void do_my_heavy_calculations () {

         // do all your calculations. 
         .
         .
         .             
         // when you are done:

         myCalculationsAreReady=true;

         invalidate(); // this will call onDraw
 }

当您了解其工作原理后,如果您的计算量很大,您肯定希望将它们从 UI 线程中取出。您可以按照您的要求使用普通线程,但是调用“invalidate”的方式不同:

view.postInvalidate();

这用于使来自主 UI 线程(即您的线程)外部的 View 无效。

另请查看 AsyncTask 作为帮助编写异步线程的类。

关于android - 在 onDraw() 中使用线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22765947/

相关文章:

android - 改变 MediaRouteButton 的行为?

c# - Microsoft TPL(任务并行库)与 Intel TBB(线程构建 block )

android - drawBitmap 不是全屏

android - 每次我在 View 寻呼机中更改或滑动页面时都会调用 onDraw() 方法

Android:用不同的笔画宽度绘制

android - 无法添加名称为 'testTarget' 的配置,因为具有该名称的配置已存在

android - 如何获取 android.app.UiAutomation 的实例

android - 调用 Fragment 类的方法的问题

java - Java 多线程程序中的对象可见性

c++ - 细粒度锁定