4

画面上をボールが走るアプリがあります。ボールが半分に到達すると、アプリケーションはオーディオを録音し、FFT を計算し、追加の分析を行います。

これは Asynctask によって処理されますが、アニメーションは依然として短時間途切れます。

スムーズに実行する方法について何か提案はありますか?

ありがとう

以下のコード:

import com.ben.applicationLayer.GameView;
import dataObjectLayer.Sprite;
import dataObjectLayer.MusicalNote;
import android.media.AudioRecord;
import android.media.MediaRecorder.AudioSource;
import android.media.AudioFormat; 
import android.os.AsyncTask;

public class recorderThread extends AsyncTask<Sprite, Void, Integer> {

short[] audioData;
int bufferSize;    
Sprite ballComp;

@Override
protected Integer doInBackground(Sprite... ball) {

    MusicalNote note = ball[0].expectedNote;
    ballComp = ball[0];
        boolean recorded = false; 
        double frequency;
        int sampleRate = 8192;  
        AudioRecord recorder = instatiateRecorder(sampleRate);
        double[] magnitude = new double[1024];
        double[] audioDataDoubles = new double[2048];

        while (!recorded) {  //loop until recording is running

        if (recorder.getState()==android.media.AudioRecord.STATE_INITIALIZED) 
// check to see if the recorder has initialized yet.
        {
            if (recorder.getRecordingState()==android.media.AudioRecord.RECORDSTATE_STOPPED)
                  recorder.startRecording();  
//check to see if the Recorder has stopped or is not recording, and make it record.                               
            else {             
               double max_index;
               recorder.read(audioData,0,bufferSize);   
//read the PCM audio data into the audioData array

               computeFFT(audioDataDoubles, magnitude);

               max_index = getLargestPeakIndex(magnitude);

               frequency = getFrequencyFromIndex(max_index, sampleRate);

            //checks if correct frequency, assigns number
               int correctNo = correctNumber(frequency, note);

checkIfMultipleNotes(correctNo, max_index, frequency, sampleRate, magnitude, note);

               if (audioDataIsNotEmpty())
                   recorded = true;
               if (correctNo!=1)
                   return correctNo;
              }
        }
        else
        {
            recorded = false;
            recorder = instatiateRecorder(sampleRate);
        }
    }

        if (recorder.getState()==android.media.AudioRecord.RECORDSTATE_RECORDING) 
        {
            killRecorder(recorder);
        }

        return 1;
}


private void killRecorder(AudioRecord recorder) {
    recorder.stop(); //stop the recorder before ending the thread
    recorder.release(); //release the recorders resources
    recorder=null; //set the recorder to be garbage collected
}

@Override
protected void onPostExecute(Integer result) {  
    (result == 2)
        GameView.score++;
    }

private AudioRecord instatiateRecorder(int sampleRate) {    
        bufferSize= AudioRecord.getMinBufferSize(sampleRate,AudioFormat.CHANNEL_CONFIGURATION_MONO,
                AudioFormat.ENCODING_PCM_16BIT)*2;
 //get the buffer size to use with this audio record

AudioRecord recorder = new AudioRecord (AudioSource.MIC,sampleRate, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,bufferSize); //instantiate the AudioRecorder

    audioData = new short [bufferSize]; //short array that pcm data is put into.         
        return recorder;
}

}
4

3 に答える 3

3

Asynctask を使用することは、やりたいことの線に沿っています。ただし、スレッドプールを使用することをお勧めします。次に、アニメーションをタスクとして配置し、オーディオ録音をタスクとして追加し、FFT を別のタスクとして追加し、追加の分析をタスクとして追加できます。

短いスタッターは、アニメーション スレッドで記録用のリソースを割り当てた結果である可能性があります。プールを使用すると、オーディオ タスクを実行するスレッドの作成中に一時停止する必要がなくなります。明らかに、問題を完全に理解するにはいくつかのコードが便利です。

を見てみましょう:

ScheduledThreadPoolExecutor http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html

また

ThreadPoolExecutor http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html

あなたがやりたいことの非常に簡単な例:

アクティビティでは、これを定義してタスクを開始できます

ExecutorService threadPool = new ScheduledThreadPoolExecutor(2);
Recording record = new Recording();
Ball ball = new Ball(threadPool, record);
threadPool.submit(ball);

Ball.java

import java.util.concurrent.ExecutorService;

public class Ball implements Runnable { 
    private final Recording record;
    private final ExecutorService threadPool;

    private boolean condition;  
    private boolean active;

    public Ball(ExecutorService threadPool, Recording record) {
        this.record = record;
        this.threadPool = threadPool;
        this.active = true;
    }

    @Override public void run() {
        while (this.active) {
            moveBall();
            if (isBallHalfway()) {
                threadPool.submit(record);
            }
        }
    }

    private boolean isBallHalfway() {
        return condition; // Condition for determining when ball is halfway
    }

    private void moveBall() {
        // Code to move the ball
    }
}

Recording.java

public class Recording implements Runnable {
    @Override public void run() {
        // Do recording tasks here
    }
}
于 2012-01-25T21:52:13.493 に答える
1

Mohammed が言うように、コードを見ずに何が問題なのかを推測するのは困難です。それを念頭に置いて...

AsyncTask他のスレッドの実行をブロックしているようです。Thread.sleep()スケジューラーが UI スレッドに戻る機会を与えるために、いくつかの呼び出しがあることを確認してください(Thread.yield()これもオプションですが、yield には問題があることに注意してください)。

于 2012-01-26T10:46:58.373 に答える
0

コードがないと、最適化できると推測するのは難しいでしょうが、ロード時に100万回を超える操作で何をしたかを説明します。•パフォーマンスに問題がある場合は、次のことを試してください。1-変数のデータ型を確認して設定する変数がそれ以上のバイトを必要としないことが確実な場合、つまりサイズの場合はintではなくshortにします。

2-コードを確認し、すべての結果を次回の起動のために保存できるようにして、再度計算するのではなく、次回呼び出します。

•ただし、アニメーションが遅く、メモリに問題がない場合は、アニメーションの期間を短くするか、移動の単位を増やしてみてください。

ちなみに、アニメーションはどのように実装しますか?フレームごとのアニメーション、またはレイアウトアニメーション、またはビューアニメーション?

于 2012-01-25T21:25:52.450 に答える