마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

안드로이드 UI Thread 관련 과부하 이슈 질문드립니다.

0 추천

문제 상황: 사용자 요청에 따라 FFmpeg을 사용해 오디오 파일 관련 작업을 쓰레드로 하고 있습니다. 이외에도 가사 출력, 오디오 플레이어 등과 함께 쓰레드가 돌고 있습니다. 헌데 다음과 같은 오류? 메세지? 를 발견했습니다. UI나 쓰레드의 버벅임이 혹시 이 때문인가 싶습니다. 

 

관련 주요부문 코드 입니다.

                    case MotionEvent.ACTION_UP: {
                        long currentDuration = vAudioPlayer.getCurrentDuration();
                        if (mRecordThread != null) {
                            // 병합을 시작 ( combineList가 홀수일 때: 레코드 버튼을 눌렀을 때 combineList의 사이즈가 홀수가 된다 )
                            if (combineList.size() % 2 == 1) {
                                mRecordThread.stopFileWrite();

                                File waveFile = new File(RecordActivity.currentCreateFileName.replaceAll("/ucc/", "/tmp/")
                                        + "_" + caltime(combineList.get(combineList.size() - 1) / 1000, false) + "_uv.pcm");
                                // 위의 경로에 해당 녹음 파일이 존재하면 wav 파일로 변환,
                                if (waveFile.exists()) {
                                    copyWaveFile(RecordActivity.currentCreateFileName.replaceAll("/ucc/", "/tmp/") + "_" + caltime(combineList.get(combineList.size() - 1) / 1000, false) + "_uv.pcm",
                                            RecordActivity.currentCreateFileName.replaceAll("/ucc/", "/tmp/") + "_" + caltime(combineList.get(combineList.size() - 1) / 1000, false) + "_u0.wav");

                                    // wav 볼륨 파일 증폭
                                    if (mMp3ConcatThread != null) {
                                        mMp3ConcatThread.startCombine(null, 3333333333333333333L, combineList.get(combineList.size() - 1), currentDuration);
                                    }
                                }

                                combineList.add(currentDuration);
                                // startCombine Thread 분기 처리( if old_position: 0, 3333333333333333333L, 7777777777777777777L, 그 외 )
                                if (combineList.size() == 2) {
                                    // 0: 처음 한번 녹음할 때
                                    mMp3ConcatThread.startCombine(null, 0, combineList.get(combineList.size() - 2), currentDuration);
                                } else {
                                    // 그 외: 두번 이상 녹음할 때
                                    mMp3ConcatThread.startCombine(null, combineList.get(combineList.size() - 3), combineList.get(combineList.size() - 2), currentDuration);
                                }
                            }
                            vAudioPlayer.setSampleTranspo(false);
                            mRecordThread.setSampleTranspo(false);
                        }
                    }

                    // 버튼, 이미지 뷰 애니메이션
                    micBg1.setVisibility(View.GONE);
                    micBg2.setVisibility(View.GONE);

                    micBg1.clearAnimation();
                    micBg2.clearAnimation();

                    userImg.setImageBitmap(userBlurImg);
                    userImg.startAnimation(animZoomOut);
                    artistImg.setImageBitmap(artistImgBitmap);
                    artistImg.startAnimation(animZoomIn);
                    break;
                }
                return false;
            }
        });

질문 1: 이 메세지 (or 오류?)의 정확한 이유는 무엇인가요. Main 쓰레드가 과부하라면 UI 처리 해주는 부분에 과부하가 걸린다는 뜻인가요? 그렇다면 정확히 어느 부분에서 과부하가 걸리는지 알아낼 수 있는 방법을 모르겠습니다. 

질문 2: 위 오류나 메세지가 나타나면 다른 쓰레드의 작업에도 영향을 주나요? 예를 들어 FFmpeg 오디오 처리를 하는 쓰레드의 작업도 skip 된다거나 하는 류의 문제가 있을 수 있나요?

시도 1: 찾아보니 이미지 리소스의 용량이 클 때 나타날 수 있다고 하여 이미지의 용량을 100kb 이하로 줄이고 사용해봤습니다. 현상은 똑같이 나타납니다. setImage 와 animation 하는 부분을 주석 처리하고 실행하니 skip되는 frame의 단위가 줄 뿐 현상은 계속해서 나타납니다.

준버기 (1,160 포인트) 님이 2018년 7월 5일 질문

1개의 답변

+1 추천
 
채택된 답변
1: 이 메세지 (or 오류?)의 정확한 이유는 무엇인가요. Main 쓰레드가 과부하라면 UI 처리 해주는 부분에 과부하가 걸린다는 뜻인가요? 그렇다면 정확히 어느 부분에서 과부하가 걸리는지 알아낼 수 있는 방법을 모르겠습니다.

=> Main 쓰레드에서 UI 처리하는데, 이 부분이 오래 걸리면, UI 처리 하는 부분의 처리가 늦어질수 밖에 없습니다.

오래걸리는 작업은 Main 쓰레드가 아닌 부분에서 처리 하시는 걸 권장합니다.

=> 첨부한 코드 상으로는 copyWaveFile 가 오래 걸릴 것으로 예상은 됩니다만,

long startTime = System.currentTimeMillis();
copyWaveFile(.....);
Log.e("XXX", "Delay  : " + (System.currentTimeMillis() - startTime);

와 같이 각 명령어 수행 시간을 찍어보시면, 상대적으로 오래 걸리는 부분이 있을 겁니다. 이 부분을 별도 Thread로 분리 해 주시면,  완화 될 겁니다.(CPU 성능을 넘는 처리를 도시에 할 경우 별도 Thread로 분리 하더라도 해결 안될 순 있습니다만.. 오디오 처리 정도는 어지간한 단말에선 문제가 없을 겁니다.)

 

질문 2: 위 오류나 메세지가 나타나면 다른 쓰레드의 작업에도 영향을 주나요? 예를 들어 FFmpeg 오디오 처리를 하는 쓰레드의 작업도 skip 된다거나 하는 류의 문제가 있을 수 있나요?

 => 가능합니다.  마이크 소리를 버퍼가 넘치도록 못 가져갈경우 마이크 소리가 일부 유실 될 수 있으며, 그로 인해 소리가 끊길 수 있습니다.
익명사용자 님이 2018년 7월 5일 답변
준버기님이 2018년 7월 6일 채택됨
답변 감사합니다. 질문 2에 답변해주신건 쓰레드간의 문제라기 보다는 오디오 입력에 관한 문제인건가요?
아 그리고 copyWave 로그를 찍어보니 16 이라고 나오면 0.016초 인가요? 이 시간이 과부하에 영향을 줄 정도인지 아닌지 모르겠네요.
질문 2에 답변해주신건 쓰레드간의 문제라기 보다는 오디오 입력에 관한 문제인건가요?
=> 예를 드린 것으로, 다른 쪽에서 문제가 생길수도 있습니다.

copyWave 로그를 찍어보니 16 이라고 나오면 0.016초 인가요?
=> 맞습니다. ms 단위로,  screen refresh rate가  60Hz라면  1초에 60번 그려야 할테니. 단순 계산으로도 16.6ms 이내에 영상이 출력되어야 하는데,  이 동작만 16ms라면, 제시간에 표시 안될테니 문제가 될 수 있습니다. 120Hz 라면, 8.3ms 이내에 처리 되어야 할테구요...
vAudioPlayer.getCurrentDuration() 전부터 artistImg.startAnimation(animZoomIn); 이후까지의 전체 시간을 찍어보시고, copyWave 시간보다 값이 유의미하게 크게 찍힌다면, 다른쪽에서도 시간을 잡아 먹은데가 있다는 애기니, 한 줄마다 시간을 찍어 찾아 보셔야 할 수 있습니다.
...