Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android thread wait until visible

I've made a custom pie chart view that I want to animate starting when the pie chart is visible. Currently what I have is the pie chart animating but by the time you can actually see it on the screen the animation is half over. This is what I have:

public class SinglePieChart extends SurfaceView implements SurfaceHolder.Callback {
    // Chart setting variables
    private int emptyCircleCol, strokeColor, number, total;

    // Paint for drawing custom view
    private Paint circlePaint;

    private RectF rect;

    private Context context;
    private AnimThread animThread;
    private SurfaceHolder holder;

    // animation variables
    private float speed;
    private float current = 0.0f;
    private boolean percentsCalculated = false;
    private float degree;
    private int viewWidth, viewHeight;

    public SinglePieChart(Context ctx, AttributeSet attrs) {
        super(ctx, attrs);

        context = ctx;

        // Paint object for drawing in doDraw
        circlePaint = new Paint();
        circlePaint.setStyle(Style.STROKE);
        circlePaint.setStrokeWidth(3);
        circlePaint.setAntiAlias(true);
        circlePaint.setDither(true);


        rect = new RectF();

        //get the attributes specified in attrs.xml using the name we included
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
            R.styleable.DashboardChartSmall, 0, 0);

        try {
            //get the colors specified using the names in attrs.xml
            emptyCircleCol = a.getColor(R.styleable.DashboardChartSmall_smCircleColor, 0xFF65676E); // light gray is default
            strokeColor    = a.getColor(R.styleable.DashboardChartSmall_smColor, 0xFF39B54A); // green is default

            // Default number values
            total  = a.getInteger(R.styleable.DashboardChartSmall_smTotal,  1);
            number = a.getInteger(R.styleable.DashboardChartSmall_smNumber, 0);
        } finally {
            a.recycle();
        }

        this.setZOrderOnTop(true);

        holder = getHolder();
        holder.setFormat(PixelFormat.TRANSPARENT);

        holder.addCallback(this);
    }

    protected void calculateValues() {
        degree = 360 * number / total;
        percentsCalculated = true;
        speed = 10 * number / total;
        viewWidth  = this.getMeasuredWidth();
        viewHeight = this.getMeasuredHeight();

        float top, left, bottom, right;

        if (viewWidth < viewHeight) {
            left = 4;
            right = viewWidth - 4;
            top = ((viewHeight - viewWidth) / 2) + 4;
            bottom = viewHeight - top;
        } else {
            top = 4;
            bottom = viewHeight - 4;
            left = ((viewWidth - viewHeight) / 2) + 4;
            right = viewWidth - left;
        }

        rect.set(left, top, right, bottom);
    }

    protected void doDraw(Canvas canvas) {
        if (total == 0) {
            // Number values are not ready 
            animThread.setRunning(false);
            return;
        }

        if (!percentsCalculated) {
            calculateValues();
        }

        // set the paint color using the circle color specified
        float last = current;
        float start = -90;

        circlePaint.setColor(strokeColor);
        canvas.drawArc(rect, start, (last > degree) ? degree : last, false, circlePaint);
        start += (last > number) ? number : last;
        last = (last < number) ? 0 : last - number;

        circlePaint.setColor(emptyCircleCol);

        if (current > 360) {
            current = 360;
        }

        canvas.drawArc(rect, start, 360 - current, false, circlePaint);     

        current += speed;

        if (last > 0 || number == 0) {
            // we're done
            animThread.setRunning(false);
        }
    }

    public void setNumbers(int num, int tot) {
        number = num;
        total  = tot;

        invalidate();
        requestLayout();
    }


    public void setColor(int col) {
        strokeColor = col;
    }

    public void redraw() {
        calculateValues();
        animThread.setRunning(true);

        invalidate();
        requestLayout();
    }

    @Override
    public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
    }

    @Override
    public void surfaceCreated(SurfaceHolder arg0) {
        animThread = new AnimThread(holder, context, this);
        animThread.setRunning(true);
        animThread.start();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder arg0) {
        animThread.setRunning(false);

        boolean retry = true;

        while(retry) {
            try {
                animThread.join();
                retry = false;
            } catch(Exception e) {
                Log.v("Exception Occured", e.getMessage());
            }
        }
    }

    public class AnimThread extends Thread {
        boolean mRun;
        Canvas mcanvas;
        SurfaceHolder surfaceHolder;
        Context context;
        SinglePieChart msurfacePanel;

        public AnimThread(SurfaceHolder sholder, Context ctx, SinglePieChart spanel) {
            surfaceHolder = sholder;
            context = ctx;
            mRun = false;
            msurfacePanel = spanel;
        }

        void setRunning(boolean bRun) {
            mRun = bRun;
        }

        @Override
        public void run() {
            super.run();
            while (mRun) {
                mcanvas = surfaceHolder.lockCanvas();
                if (mcanvas != null) {
                    msurfacePanel.doDraw(mcanvas);
                    surfaceHolder.unlockCanvasAndPost(mcanvas);
                }
            }
        }
    }
}

Also if you see any programming errors, memory leaks, poor performing code, please let me know. I'm new to Android.

Here is the layout that uses the SinglePieChart class:

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">
        <com.davidscoville.vokab.views.elements.SinglePieChart
            android:id="@+id/smallPieChart"
            android:layout_width="match_parent" 
            android:layout_height="match_parent" />

        <TextView
            android:id="@+id/dashSmNumber"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true"
            android:textSize="25sp"
            android:textColor="#FFFFFF" />

    </RelativeLayout>

    <TextView
        android:id="@+id/dashSmLabel"
        android:layout_width="match_parent"
        android:layout_height="20dp"
        android:textSize="14sp"
        android:gravity="center"
        android:textColor="#FFFFFF" />
</merge>
like image 929
chrislondon Avatar asked Apr 17 '13 12:04

chrislondon


2 Answers

Alright I'm going with the my pie chart won't automatically animate and it will have a new function that the Activity will trigger to start animating once it's ready. I wish there was an easier way...

like image 77
chrislondon Avatar answered Oct 16 '22 16:10

chrislondon


Alternatively you can use the animation framework(or nine old androids if you want to support older apis). This will allow you to animate properties on your view, in your case the start and current variables.

I'd set this to happen during onAttachedToWindow.

Note if you aren't doing a lot of other things in this pie chart a surfaceview might be overkill for your needs.

like image 38
Jim Baca Avatar answered Oct 16 '22 17:10

Jim Baca