Passing a variable to a Custom View Class from Act

2019-07-10 02:33发布

问题:

I am testing drawing audio frequency into canvas using canvas.drawLine() method. I am able to do static draw into canvas. Basically I have a test app which has two buttons START and STOP and a Canvas where i am trying to draw the audio frequencies obtained from FFT. When i hit the START button it starts recording sound using AudioRecord class and collects data into buffer which i run through FFT to get the frequencies. This is in very early stage. Right now i am only trying to figure out how to pass these frequency values to onDraw method of my Custom View class. Here are the relevent codes starting from the layout.

activity_main.xml

<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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <com.example.testapp.WaveForm
        android:id="@+id/waveForm1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginTop="78dp" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/button1"
        android:layout_alignBottom="@+id/button1"
        android:layout_alignRight="@+id/waveForm1"
        android:layout_marginRight="19dp"
        android:text="STOP" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/waveForm1"
        android:layout_alignParentTop="true"
        android:text="START" />

</RelativeLayout>

I think its very starighforward. Here is my Custom View class

WaveForm.java

package com.example.testapp;

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

public class WaveForm extends View {

    private Paint mLinePaint;
    float x ;
    float y;

    public WaveForm(Context context, AttributeSet attrs) {
        super(context, attrs);
        mLinePaint = new Paint();
        mLinePaint.setStyle(Paint.Style.STROKE);
        mLinePaint.setARGB(255, 0, 0, 255);
        mLinePaint.setAntiAlias(true);
        mLinePaint.setStrokeWidth(10);
        x = 0.0f;
        y = 0.0f;

    }

    @Override
    protected void onDraw(Canvas canvas) {
        //Instead of 50 here i would like to pass the value obtained from the Activity class
        canvas.drawLine(x, 0, y, 50, mLinePaint);   
        y = y + 1.0f;
        x = x + 1.0f;
        super.onDraw(canvas);
    }



}

As i mentioned in the comment in the onDraw method, i would like to pass the frequency value i obtained in the Activity instead of 50. Finally here is my Activity:

MainActivity.java

package com.example.testapp;


import android.app.Activity;
import android.graphics.Canvas;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder.AudioSource;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;



public class MainActivity extends Activity {
    boolean recording = false;
    AudioRecord audioRecord;
    double[] x;
    double[] y;
    double currentPoint = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final View myInstance = (View) findViewById(R.id.waveForm1);

        Button start = (Button) findViewById(R.id.button1);
        start.setOnClickListener(new OnClickListener(){

        @Override
        public void onClick(View v) {
            int sampleRateInHz=44100;
            int channelConfig = AudioFormat.CHANNEL_IN_MONO;
            int bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, AudioFormat.ENCODING_PCM_16BIT);
            audioRecord = new AudioRecord(AudioSource.MIC, sampleRateInHz, channelConfig, AudioFormat.ENCODING_PCM_16BIT,  AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, AudioFormat.ENCODING_PCM_16BIT));
            byte[] audioData = new byte[bufferSizeInBytes/4];

            FFT myFFT = new FFT(audioData.length);
            Canvas canvas = new Canvas();
            recording = true;
            audioRecord.startRecording();
            while(recording) {
            audioRecord.read(audioData,0, bufferSizeInBytes/4);
            //convert to double here
            for(int i=0; i<audioData.length; i++) {
                x[i] = (double)audioData[i];
                y[i] = 0;
            }
            double[] samples = myFFT.fft(x, y);
            for(int i=0; i<samples.length; i++) {
                currentPoint = samples[i];
                myInstance.draw(canvas);
                myInstance.invalidate();
            }
            }

        }
        });
        Button stop = (Button) findViewById(R.id.button2);
        stop.setOnClickListener(new OnClickListener(){

        @Override
        public void onClick(View v) {
        recording = false;
        audioRecord.stop();

        }
        });     
    }     
}

The currentPoint variable is what i am trying to pass to the onDraw method. Thanks in advance for taking a look.

回答1:

Create Getter/Setter for currentPoint variable inside WaveForm to get value from MainActivity before calling draw as:

public class WaveForm extends View {

    private double currentPoint = 50;
    public void setCurrentPoint(double currentPoint){
         this.currentPoint=currentPoint;
    }
    public double getCurrentPoint(){

       return this.currentPoint;
    }
    @Override
    protected void onDraw(Canvas canvas) {

        canvas.drawLine(x, 0, y, getCurrentPoint(), mLinePaint);   
        ...
    }

}

and from MainActivity set currentPoint value by calling setCurrentPoint method before calling onDraw:

    for(int i=0; i<samples.length; i++) {
        currentPoint = samples[i];
        myInstance.setCurrentPoint(currentPoint);
        myInstance.draw(canvas);
        myInstance.invalidate();
    }


回答2:

Specify currentPoint as a static variable, and use MainActivity.currentPoint to get the value of the variable from your other class. Alternatively, just use a getter method that returns the variable.