Frage

I am writing an App and I have a custom view. In this custom view I have to calculate the positions of an undetermined number of points. The number of points depends on what I am reading from my database (so it's differently for each user). So, my question is, how can I solve this in a good way? The steps of the app are as following:

  1. Activity starts
  2. Database query
  3. Drawing

The problem is that the onDraw()-method is called when I open the activity, but I can't draw anything since I have to wait for the database-query and the calculation of the points. How can I use a Thread and maybe something like a progressbar till the calculation is done? Can i prevent the app from running the onDraw()-method immediately when the activity starts?

I appreciate your help.

edit1: So here is the code (Note: I didn't want to calculate anything by now, the errors appear because I try to set the visibility of the ProgressBar to true, without this line it works):

    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);
            }

        }

    }

Here are the Errors:

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)

War es hilfreich?

Lösung

you should research a little about onDraw() lifecycle.

onDraw gets called at the beginning, and then will be called again everytime there is "something" to draw. How you tell a view it has "something" to draw? by calling "invalidate".

So on your onDraw you do nothing at first, if the points are not loaded.

When you have finished your calculations, just call invalidate() and onDraw will get called later on, asynchronously. By this time, in your OnDraw you'll detect that your calculations are ready, so then it's when you paint the stuff.

kind of:

 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
 }

When you understand how this works, and if your calculations are heavy, you definitely want to take them out of the UI thread. You can use a normal thread just like you ask, but then, the way to call "invalidate" is different:

view.postInvalidate();

this is used to invalidate views from outside the main UI thread (ie. your thread).

Also check out AsyncTask as a class to help writing asynchronous threads.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top