최적화3 - Thread 병렬처리

제가 작성한 tistory글의 마이그레이션입니다.

도입

이번 포스팅에서는 Next, Prev 버튼으로 음악을 넘길 때 Viewpager가 버벅거렸던 것을 해결할 예정이다!

문제점 1

Next, Prev 음악을 선택하면 Viewpager가 조금 느려지는 현상이 발생했지만 음악이 변경되는데 이정도면 괜찮지 않나... 라는 안일한 생각을 했고 넘겼다. 그러나 다른 음악 플레이어와 비교했을 때 확실히 버벅거린다고 느껴 원인 파악을 시작했다.

Viewpager가 버벅거렸던 것의 원인이
1. 이미지 로딩
2. 잘못된 설계

라고 생각했다...

하지만 근본적인 문제는 역시 코드였다. 역시 내 잘못..
Viewpager가 버벅거리는 원인을 파악하기 위해 Viewpager가 넘어갈 때 실행되는 코드들을 이진탐색하듯 코드를 주석 처리하며 원인을 찾았다.

그 결과!

public class PlayerController {
    // ...
    public void setMusic(final Uri musicUri) {    
        // ...        
        player = MediaPlayer.create(context, musicUri);    
        // ...
    }
    // ...
}

음악이 설정될 때마다 MediaPlayer.create로 음악이 만들어졌고 여기서 Main Thread의 리소스를 많이 사용해 버벅거리는 현상이 발생했던 것이다.

해결책 1

그래서 해당 코드를 Thread로 처리해 버벅거림 현상을 해결했다.
코드를 보면

public class PlayerController {
    // ...
    public void setMusic(final Uri musicUri) {    
        // ...        
        new Thread() {            
            public void run() {
                try {
                    player.release();
                } catch (Exception e) {
 
                } finally {
                    player = null;
                }
 
                player = MediaPlayer.create(context, musicUri);
                player.setLooping(isLoop);
 
                player.setOnCompletionListener((mp) -> {
                    currentStatus = Const.ACTION_MUSIC_NEXT;
                    Log.e("heepie", "finished Music");
                });
 
                play();
 
            }
        }.start();        
    // ...
    }
    // ...
}

문제점 2

이렇게 코드를 변경하니 버벅거리는 현상은 해결했다. 그러나 더 큰 문제가 발생했다.
빠른 속도로 음악을 변경하게 될 경우, 음악이 2개가 동시에 실행되는 문제가 발생했다.

원인 MusicPlayer를 Release하는 부분이 있지만, Thread로 병렬로 처리되기 때문에 1개의 Thread가 완료되기 전 다음 Thread가 시작되면 이전 음악은 Release되지 않는다.

해결책 2

그래서 처리방법을 고민하면서 책과 인터넷을 찾아봤다.
그 결과, MusicPlayer를 1개의 Thread만 접근 가능한 Thread-safe한 List에 담아두고 가장 마지막에 선택된 음악을 제외하고 나머지를 Release하는 방법을 선택했다. 그림으로 확인하면

코드를 보면

public class PlayerController {
    // ...
    public void setMusic(final Uri musicUri) {    
        // ...        
        new Thread(() -> {            
            // 음악 등록
            player = MediaPlayer.create(context, musicUri);
            player.setLooping(isLoop);
 
            player.setOnCompletionListener((mp) -> {
                currentStatus = Const.ACTION_MUSIC_NEXT;
                Log.e("heepie", "finished Music");
            });
            play();
 
            // 음악 추가
            playerList.add(player);
 
            // 마지막에 추가된 음악을 제외한 나머지는 모두 제거
            for (int i=0; i<players.size()-1; i=i+1) {
                try {
                    playerList.get(i).release();
                } catch (Exception e) {
 
                }
            }
        }).start();    
    // ...
    }
    // ...
}

스크린샷

변경 후에도 음악은 1개만 실행된다.

AS-ISTO-BE

좋은 웹페이지 즐겨찾기