0

My issue is that no matter what I do, no matter how many questions and answers I read through on the internet, I cant get a simple rectangle to draw on my android device screen. Let me rephrase that, it shows up on screen but it wont change. I cant get an animation to update. onDraw() never calls multiple times, just once on startup. why? Here is my view objects code:

package prospect_industries.es;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

public class TestView extends View {

    //Variables
    public static final int SIZE = 300;
    public float TOP = 0.0f;
    public float LEFT = 0.0f;
    public float RIGHT = 100f;
    public float BOTTOM = 100f;

    private Paint rectanglePaint;
    private RectF rect1;

    //Constructors
    public TestView(final Context context, final AttributeSet attrs, final int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public TestView(final Context context, final AttributeSet attrs) {
        super(context, attrs, 0);
        init();
    }

    public TestView(final Context context) {
        super(context, null, 0);
        init();
    }

    //View methods
    @Override
    protected void onDraw(final Canvas canvas){
        canvas.drawRect(rect1, rectanglePaint);
        Log.i("test1", "in onDraw");
    }

    @Override
    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        final int chosenWidth = chooseDimension(widthMode, widthSize);
        final int chosenHeight = chooseDimension(heightMode, heightSize);
        setMeasuredDimension(chosenWidth, chosenHeight);
        Log.i("test1", String.valueOf(chosenWidth));
        Log.i("test1",String.valueOf(chosenHeight));
    }

    //Class Methods
    private int chooseDimension(final int mode, final int size) {
        switch (mode) {
            case MeasureSpec.AT_MOST:
            case MeasureSpec.EXACTLY:
                return size;
            case MeasureSpec.UNSPECIFIED:
            default:
                return getDefaultDimension();
        }
    }

    private int getDefaultDimension() { return SIZE; }

    private void init(){
        requestFocus();
        rectanglePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        rectanglePaint.setColor(-1);
        rectanglePaint.setStyle(Paint.Style.FILL);

        rect1 = new RectF(LEFT, TOP, RIGHT, BOTTOM);
    }

    public void update() {
        RIGHT += 10;
        BOTTOM += 10;
        rect1 = new RectF(LEFT, TOP, RIGHT, BOTTOM);
        invalidate();
        Log.i("test1", "in update");
    }
}

Here is my main class which has a few methods for other things Im working on as well as a timer which calls the update() method inside of my test view object.

package prospect_industries.es;

import android.app.Activity;
import android.content.Context;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import java.io.IOException;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;


public class MainActivity extends Activity {

    private boolean setup = false;
    public int waitDelay = 1000; //Milliseconds - currently 1 second
    private Timer checkTime;
    private TimerTask listen;
    private MediaRecorder mRecorder;

    //Splashscreen
    private Timer splashScreen;
    private int waitTime = 3000; //3 seconds

    private GaugeView mGaugeView;
    private final Random RAND = new Random();
    private TestView testview;
    private SurfaceHolder surfaceHolder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.content_main);

        //mGaugeView = (GaugeView) findViewById(R.id.gauge_view);
        testview = (TestView) findViewById(R.id.test_view);
    }


    @Override
    public void onStart() {
        super.onStart();
        //Timers
        //1 second wait tick
        checkTime = new Timer();
        checkTime.schedule(new TimerTask() {
            public void run() {
                MainActivity.this.runOnUiThread(new Runnable() {
                    public void run() {
                        //mGaugeView.setTargetValue(RAND.nextInt(101));
                        testview.update();
                    }
                });
            }
        }, 0, waitDelay);

        //Set splash screen wait timer
        splashScreen = new Timer();
        splashScreen.schedule(new TimerTask() {
            public void run() {
                MainActivity.this.runOnUiThread(new Runnable() {
                    public void run() {
                        setContentView(R.layout.content_main);
                    }
                });
                splashScreen.cancel();
            }
        }, waitTime);

        //set welcome screen
        setContentView(R.layout.activity_welcome);
    }

    @Override
    public void onStop() {
        super.onStop();
        if(checkTime != null) {
            checkTime.cancel();
            stop();
        }
    }

    public void stop() {
        if (mRecorder != null) {
            mRecorder.stop();
            mRecorder.release();
            mRecorder = null;
        }
    }

    public double getAmplitude() {
        if (mRecorder != null)
            return  mRecorder.getMaxAmplitude();
        else
            return 0;

    }

    public void checkSound(){
        if (mRecorder == null) {
            mRecorder = new MediaRecorder();
            mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
            mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
            mRecorder.setOutputFile("/dev/null");
            try {
                mRecorder.prepare();
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            mRecorder.start();
        }
    }

    private static class MainView extends SurfaceView implements SurfaceHolder.Callback {

        private SurfaceHolder surfaceHolder;

        public MainView(Context context) {
            super(context);
            surfaceHolder = getHolder();
            surfaceHolder.addCallback(this);
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            // TODO Auto-generated method stub

        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            // TODO Auto-generated method stub

        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            // TODO Auto-generated method stub

        }
    }
}

Lastly, here is the xml layout file which loads in the test view object.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    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"
    android:background="#103681"
    tools:context="prospect_industries.es.MainActivity">

    <prospect_industries.es.TestView
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:id="@+id/test_view"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true" />

</RelativeLayout>

I have been looking all over stackExchange for hours but I cant fix my problem, onDraw is only called once and never again no matter what I do. Right now the rectangle should be expanding out but it isnt being redrawn.

  • The second and third constructor of `TestView`: `super(context, attrs);` instead of `this(context, attrs, 0);` and `super(context);` instead of `this(context, null, 0);`. I think so. – Đăng Khoa Huỳnh Apr 07 '16 at 12:20
  • Instead of thinking about what isn't happening, check what is happening; use a few system.out.prints to see the flow of the code in the console. That way you might get an idea of where it is failing. – geostocker Apr 07 '16 at 12:22
  • I am getting a single log print because the program runs onDraw once at instantiation and thats it. – Travis Dewitt Apr 07 '16 at 12:56

1 Answers1

0

The problem is that you initialize the rectangle to be 1px wide and 1px tall and never resize it. You should be able to see 1 white pixel somewhere in the top left corner of your TestView.

Try changing the rect1 size to 0,0,100,100 and see if the problem persists.

public static final float TOP = 0.0f;
public static final float LEFT = 0.0f;
public static final float RIGHT = 100.0f;
public static final float BOTTOM = 100.0f;
Dmitri Timofti
  • 2,428
  • 1
  • 22
  • 25
  • I feel almost ashamed that I did not notice that. Ive spent so long working with graphics and java that I should have seen this. My only accomplishment at this point is that I actually succeeded in posting a stackExhange question without a bunch of people saying how its answered elsewhere for once. Thank you! I guess sometimes we cant see whats right in front of us even when its staring us dead in the face. – Travis Dewitt Apr 07 '16 at 13:00
  • Sure, no problem! Glad I could help :) – Dmitri Timofti Apr 07 '16 at 13:07
  • I actually still have one problem. I added a couple lines of code to check for a change in the rectangle drawing and my issue actually persists. onDraw is never called. I will update the Question with my changes. Basically I'm adding to the width and height of the rectangle and invalidating the image but the onDraw method still never runs. – Travis Dewitt Apr 07 '16 at 13:15
  • @TravisDewitt in the current implementation the rect1 size is growing by 1px every second. Are you sure that onDraw() is not called or you just didn't notice the 1px difference? – Dmitri Timofti Apr 07 '16 at 13:27
  • I have a log that prints every time the onDraw is called and it only prints once at startup. Also, I changed the change to 10px changes and still nothing happened. – Travis Dewitt Apr 07 '16 at 13:31
  • I've tested your code on a Nvidia Shield( Android version 5.1.1) and it works just fine...just a wild guess - try `invalidate();requestLayout();`. – Dmitri Timofti Apr 07 '16 at 13:47
  • I feel so stuck. That didnt work. I'm on a galaxy note 4 and it just doesnt run. – Travis Dewitt Apr 07 '16 at 13:49
  • Have you tried adding `setWillNotDraw(false);` inside your `init();` method? [Reference](http://stackoverflow.com/questions/17595546/why-ondraw-is-not-called-after-invalidate). – Dmitri Timofti Apr 07 '16 at 14:00
  • I have, I believe that is used in view groups more commonly anyway. – Travis Dewitt Apr 07 '16 at 14:06