월별 글 목록: 2014년 3월월

자바 병렬 프로그래밍 : 멀티코어를 100% 활용하는..

이 책은 자바로 멀티 스레드를 조금 더 공부하기 위해서 꼭 필요한 책이라고 생각한다.
이 책에 대해서 간단하게 딴죽을 걸고 넘어가자면, 병렬보다는 병행이 더 좋지 않을까 하는 것과 용어 선택이 조금 이상한 부분들이 좀 있다는 것(?) 정도이다.

이 책의 저자중의 한 명인, Doug Lea 교수님은 자바의 java.util.concurrent 패키지의 아버지라 말할 수 있을 정도로, 자바 멀티 스레드를 병행 프로그래밍의 여러 상황에 적절하게 대응하고 개발하기 쉽게 확장한 바에 가장 큰 역활을 한 분이다.

그래서, 나는 이 분이 쓰신 Concurrent Programming in Java(1996, 1999) 책은 자바 스레드 분야의 최고의 명저라고 생각한다. 국내에서는 “자바 병행 프로그래밍 : 디자인 원리와 패턴”으로 번역판이 나와 있다. 위의 Concurrent Programming in Java를 이어받은 최근의 역작이 바로 Java Concurrency in Practice(자바 병렬 프로그래밍)라고 생각한다. 자, 왜 이렇게 저자가 많은 이유를 살펴보자.

이 책의 저자들은 공통점이 하나 있는데, 다들 JCP의 JSR-166 : Concurrency Utilities 의 전문가들이다. Joshua bloch(조쉬아 블러시)는 현 그룹의 구성원으로 이름이 없지만, 초기 그룹 구성원으로 이름을 볼 수 있다. JSR-166은 java.util.concurrent를 제안하고 만들어낸 그룹으로 아래의 사람들이 자바에서는 최고의 멀티 스레드 전문가들이라고 할 수 있겠다.
* Brian Goetz(브라이언 게츠)
* Tim Peierls(팀 피얼스)
* Joshua bloch(조쉬아 블러시)
* Joseph Bowbeer(조셉 보위어)
* David Holmes(데이빗 홈즈)
* Doug Lea(더그 리) : JSR-166의 리더
 
따라서, 이 책이 왜 자바 스레드 분야의 명저가 됐는지 쉽게 이해할 수 있겠다. 이 책은 제목에 Practice가 들어가 있어서 그런지, 자바로 멀티 스레드 프로그래밍을 하면서 겪을 수 있는 상황과 그 상황의 대처방법을 자세히 기술하고 있다.
 
책 내용을 개략적으로 살펴보면..
1장에서는 자바 언어의 스레드와 스레드를 제대로 사용하기 위한 기본적인 지식에 대해서 설명하고 있다.
2장에서는 스레드로 프로그래밍하는 예를 설명하고 있다.
3장에서는 스레드로 가용성과 확장성을 어떻게 가져갈 것인지에 대한 내용인데, 개인적으로는 1장 2장을 충실하게 읽었다면 굳이 필요성을 못 느낄 수 있는 내용이 될 수도 있을것 같다.
4장에서는 락을 세밀하게 명시적으로 잘 쓰자 정도(?).. 그 이유는 다른 주제들은 꼭 스레드 이슈만인 것도 아닌거 같아서..
 
마지막으로, 자바로 멀티 스레드 프로그래밍을 하신다면 꼭 추천하고 싶은 책이다.

안드로이드 PhotoView 라이브러리의 OutOfMemory, ViewPager 사용시 좌/우 이동시 문제 및 해결..

이제 안드로이드는 매우 성숙한 플랫폼이 되었다. 이것에 대한 반증으로 안드로이드 앱을 개발하기 위해서 참고할 수 있는 라이브러리가 참 많아졌다. 개인적으로 사진을 보여주기 위해서 전에(2.2 프로요)는 제스처(Gesture)를 사용해서 구현을 했는데, PhotoView 라이브러리를 발견하고는 주로 이 라이브러리를 사용한다. 현재 PhotoView의 master 버전은 OutOfMemory 문제가 있다. 또한 ViewPager와 같이 사용하게 되면 문제가 발생한다.

OutOfMemory가 발생하는 문제는 PhotoViewAttacher의 cleanup 메서드에서 아래의 코드로 해결을 했다.

 
    public final void cleanup() {
        if (null == mImageView) {
            return; // cleanup already done
        }

        final ImageView imageView = mImageView.get();

        if (null != imageView) {
            // Remove this as a global layout listener
            ViewTreeObserver observer = imageView.getViewTreeObserver();
            if (null != observer && observer.isAlive()) {
                observer.removeGlobalOnLayoutListener(this);
            }

            // Remove the ImageView's reference to this
            imageView.setOnTouchListener(null);

            // make sure a pending fling runnable won't be run
            cancelFling();
            
            // 아래 부분 추가로 해결.. 
            Drawable d = imageView.getDrawable();
            if(d != null && d instanceof BitmapDrawable) {
            	Bitmap bm = ((BitmapDrawable)d).getBitmap();
            	if(bm != null)
            		bm.recycle();
            }
        }

        if (null != mGestureDetector) {
            mGestureDetector.setOnDoubleTapListener(null);
        }

        // Clear listeners too
        mMatrixChangeListener = null;
        mPhotoTapListener = null;
        mViewTapListener = null;

        // Finally, clear ImageView
        mImageView = null;
    }

자 다음으로 ViewPager를 사용하면, 아래처럼, 이미지가 잘린 상태로 다음 View가 보이게 된다. 왼쪽이 정상 이미지이고, 오른쪽 화면에서 중간에 잘리 이미지가 보이면서 다음 이미지가 보이게 된다.

PhotoView의 핵심인 PhotoViewAttacher 클래스를 확인해 보면, 아래의 코드를 볼 수 있다. 이 로직이 상위 그룹 즉 ViewPager의 TouchEvent의 Intercept 여부를 결정한다. 코드를 보면, parent 객체와 handled 변수가 false인 경우 Touch 이벤트 처리를 하지 않는다. 하지만, 이렇게 설정을 하게 되면, ViewPager를 사용하는 경우 문제가 생긴다. 스케일 업한 사진이 다 보이기도 전에 ViewPager가 이벤트를 받아서 다음/이전으로 넘어가 버린다.

            if (!handled && null != parent) {
                parent.requestDisallowInterceptTouchEvent(false);
            }

그래서, 소스와 이슈를 확인해 보니, 2013년 10월 27일에 이 이슈가 개발버전에 머지되었다.
머지된 코드는 아래와 같다. master에 이 코드가 머지되어 있지 않아서, 기존의 사용자는 코드레벨에서 아래의 코드를 복사해서 사용해야 문제를 해결할 수 있다.

if (!handled && null != parent && !mAllowParentInterceptOnEdge) {
                parent.requestDisallowInterceptTouchEvent(false);
            }