0

나는 음악 노트를 재생하고 좌표계, 노래 이름 및 시간의 arraylist를 기준으로 크기가 확장되는 것으로되어있는 android studio에서 작성한 프로그램이 있습니다. 노트를 연주하십시오. 그러나 내가 가지고있는 문제는 모든 음이 정확하게 재생된다는 것입니다. 모든 음을 재생하는 루프를 종료 한 후을 끝내면 마지막 원만이 그려지고과 이 그려집니다. 이 질문을 전에 보았습니다. setWillNotDraw(false);을 호출하는 것에 대한 해답을 얻었습니다.하지만 저는 이것을 생성자에서 호출했으며, 여전히 동일한 문제가 있습니다. 여러 다른 장소에서 invalidate();을 호출 해봤지만 아무 것도 작동하지 않는 것 같습니다. 어떤 도움이라도 대단히 감사하겠습니다!OnDraw()는 루프 후 한 번만 호출됩니다.

내 코드 :

생성자

public PlayView(Context context, @Nullable AttributeSet attrs) { 
    super(context, attrs); 
    saver = PersistentSaver.getInstance(context); 
    this.context=context; 
    setWillNotDraw(false); 
} 

에이

@Override 
public void onDraw(Canvas canvas){ 
    super.onDraw(canvas); 
    this.canvas=canvas; 
    if(mCurrentRect !=null&& colorPaint!=null) { 
     canvas.drawOval(mCurrentRect, colorPaint); 
    } 
} 

에게 내가 확인 한 notes-을 재생하는 루프를 그릴, 모든 원 좌표 및 메모 올바른 배열에 포함되어 있습니다 :

public void playSong(){ 
    String song = saver.getCurrSongName(); 
    ArrayList<Long> Times = saver.getTimesForNotes(song); 
    ArrayList<Float> xCoordinates = saver.getPressXCoordinates(song); 
    ArrayList<Float> yCoordinates = saver.getPressYCoordinates(song); 
    ArrayList<String> notes = saver.getNotesForSong(song); 
    for(int i=0;i<Times.size();i++) { 
     //pause until correct time. TODO: ADJUST ERROR BOUND 
     while (true) { 
      currTime = System.currentTimeMillis() - startTime; 
      if (currTime <= Times.get(i) + epsilon && currTime >= Times.get(i) - epsilon) break; 
     } 
     //play note with that x and y coordinate and draw circle 
     playNote(xCoordinates.get(i), yCoordinates.get(i), notes.get(i)); 
    } 
} 

코드는 메모와 사운드를 재생하기 :

private void playNote(float pressx, float pressy, String note){ 
    colorPaint=new Paint(); 
    colorPaint.setStyle(Paint.Style.STROKE); 
    colorPaint.setStrokeWidth(10); 
    colorPaint.setColor(generateColor(pressx,pressy)); 
    float translateX = 50.0f; 
    float translateY = 50.0f; 
    Random rand = new Random(10000); 
    int xr = rand.nextInt(); 
    int yr = rand.nextInt(); 
    int startColor = generateColor(pressx,pressy); 
    int midColor = generateColor(pressx+rand.nextInt(),pressy+rand.nextInt()); 
    int endColor = generateColor(pressx+xr,pressy+yr); 
    mCurrentRect = new AnimatableRectF(pressx-50,pressy-50,pressx+50,pressy+50); 
    debugx=pressx; 
    playAnimation(startColor,midColor,endColor, translateX, translateY); 
    playSound(note); 
} 

애니메이션을 재생을 가정하지만 루프가 종료 한 후에 만 ​​onDraw();를 호출하는 코드

private void playAnimation(int startColor, int midColor, int endColor, float translateX, float translateY){ 
    ObjectAnimator animateLeft = ObjectAnimator.ofFloat(mCurrentRect, "left", mCurrentRect.left, mCurrentRect.left-translateX); 
    ObjectAnimator animateRight = ObjectAnimator.ofFloat(mCurrentRect, "right", mCurrentRect.right, mCurrentRect.right+translateX); 
    ObjectAnimator animateTop = ObjectAnimator.ofFloat(mCurrentRect, "top", mCurrentRect.top, mCurrentRect.top-translateY); 
    ObjectAnimator animateBottom = ObjectAnimator.ofFloat(mCurrentRect, "bottom", mCurrentRect.bottom, mCurrentRect.bottom+translateY); 
    ArgbEvaluator evaluator = new ArgbEvaluator(); 
    ObjectAnimator animateColor = ObjectAnimator.ofObject(this, "color", evaluator, startColor,midColor,endColor); 
    animateBottom.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 
     //TODO: DEBUG ANIMATOR 
     @Override 
     public void onAnimationUpdate(ValueAnimator valueAnimator) { 
      postInvalidate(); 
     } 
    }); 
    AnimatorSet rectAnimation = new AnimatorSet(); 
    rectAnimation.playTogether(animateLeft, animateRight, animateTop, animateBottom,animateColor); 
    rectAnimation.setDuration(1000).start(); 
    invalidate(); 


} 

playNote, 꺼내, 및 generateColor 메소드

//Generates color based on the press x and y. 
private int generateColor(float pressx, float pressy){ 
    int Red = (((int) (pressx%255)) << 16) & 0x00FF0000; //Shift red 16-bits and mask out other stuff 
    int Green = (((int) (pressy%255)) << 8) & 0x0000FF00; //Shift Green 8-bits and mask out other stuff 
    int Blue = ((int)((pressx+pressy)%255)) & 0x000000FF; //Mask out anything not blue. 

    return 0xFF000000 | Red | Green | Blue; //0xFF000000 for 100% Alpha. Bitwise OR everything together. 

} 

private void playSound(String noun){ 
    Resources res = context.getResources(); 
    int resID = res.getIdentifier(noun, "raw", context.getPackageName()); 
    MediaPlayer mediaPlayer = MediaPlayer.create(context,resID); 
    mediaPlayer.start(); 
    mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 
     @Override 
     public void onCompletion(MediaPlayer mediaPlayer) { 
      mediaPlayer.release(); 
     } 
    }); 
} 

private void playNote(float pressx, float pressy, String note){ 
    colorPaint=new Paint(); 
    colorPaint.setStyle(Paint.Style.STROKE); 
    colorPaint.setStrokeWidth(10); 
    colorPaint.setColor(generateColor(pressx,pressy)); 
    float translateX = 50.0f; 
    float translateY = 50.0f; 
    Random rand = new Random(10000); 
    int xr = rand.nextInt(); 
    int yr = rand.nextInt(); 
    int startColor = generateColor(pressx,pressy); 
    int midColor = generateColor(pressx+rand.nextInt(),pressy+rand.nextInt()); 
    int endColor = generateColor(pressx+xr,pressy+yr); 
    mCurrentRect = new AnimatableRectF(pressx-50,pressy-50,pressx+50,pressy+50); 
    debugx=pressx; 
    playAnimation(startColor,midColor,endColor, translateX, translateY); 
    playSound(note); 
} 

고마워요!

+0

이 보이는(). mCurrentRect = new AnimatableRectF (프레스 -50, 프레스 -50, 프레스 + 50, 프레스 +50); 그리기 시작하고 다른 소리가 들리면 다음 객체 (다시 호출 된 onDraw())를 그리기 시작합니다. 그것은 당신이 왜 마지막 것을보고 있는지를 설명 할 수 있습니다. – WiseGuy

+0

하지만 rect 목록을 배열 목록에 저장하고 그 배열을 그릴 때 끝날 때까지 모든 rect를 한꺼번에 그릴 때까지 그리지 않습니다. onDraw 자체가 루프 내에서 호출되는 일조차없는 것처럼 보입니다. 왜 그런지 모르겠습니다. 특히 playAnimation 메서드에서 invalidate()를 호출했기 때문입니다. – JohnDoe

답변

0

바쁜 루프를 사용하는 대신 다음 노트를 재생하기 전에 필요한 시간을 기다리십시오. Timer 또는 handler.postDelayed(runnable, delayMilliseconds) 또는 그 이상인 경우 Rx의 Observable.timer()을 사용하십시오.

차단 루프가 UI 스레드가 실행되는 것을 방지하고 화면을 업데이트하지 못하기 때문입니다. 당신이 멀티 태스킹을 배울하지 않으려면 가장 쉬운 방법이 할 수 있습니다 : 각 사운드는 방법 playNote 재생됩니다 후 글로벌 var에 mCurrentRect를 재설정 할 수처럼

Handler mainHandler = new Handler(context.getMainLooper()); 

mainHandler.postDelayed(new Runnable() { 
    public void run() { playNote(...) } 
}, Times.get(i)) 
+0

감사합니다! 이것은 완벽하게 작동했습니다. – JohnDoe