Press "Enter" to skip to content

Space4u

ViewPager에서 탭 구현시 옆 탭을 미리 읽는 문제..

문제라고 하기보다는 현재 보이는 탭의 옆 탭을 미리 읽어둬서 탭 슬라이드로 넘어갈때 자연스럽게 넘어가게 하는 기술이라 보겠다.
(액티비티 형태의 프로그램만 만지작 하다가 요즘 프래그먼트 형태의 프로그램을 만지작하다보니 삽질의 연속이다.)

하지만 옆 탭이 로딩하는데 통신같은 상당한 시간이 걸리거나, 심지어 프로그래스다이얼로그까지 나타나는 탭이라면 골치가 아파온다.

왜냐! 현재 탭은 이미 화면에 나타나서 잘 보이고 사용자의 입력을 기다릴 타이밍인데, 

옆 탭을 미리 로딩하면서 현재화면에 프로그래스다이얼로그가 나타난다? 켁…

(이걸 해결하기 위해 몇시간을 삽질했다… ㅜㅡ 알고보면 이렇게 간단한 것을…. )
(물론, 미리 로딩하는 걸 안하게 프로그램하는 방밥이 있을~지도 모른다…..만 안찾아봤다.. ㅡㅡ)

이제 하나하나 스텝별로 짚고 넘어가 볼까요?

상황을 하나 가정해 본다.

탭이 로딩될때 스레드로 통신을 해서 데이터를 화면에 보여주는 것이라고 하자…

현재 사용자에게 보이는 탭 화면이 자신인지는 다음과 같이 판단한다.

TabActivity는 탭을 감싸고 있는 Activity

tabIdex는 자기 자신이 TabActivity에 붙는 순번(인덱스)

탭이 표시되는 클래스의 onCreate나 onResum이나 onCreateView 등등에 아래와 같은 코드를 넣을 수 있겠죠?

if ( TabActivity.getCurrentPagerPosition() == tabIdx )
{
    // 내가 보이고 있다!!! 여기다 프로그래스다이얼로그를 뿌려주면 되것다.
}
else
{
    // 내가 보이는 중이 아니라면 미리 읽어들이는 거니깐 프로그래스다이얼로그는 표시하지 말자
}

// 필요한 스레드 생성해서 돌리기
if ( thread == null )
{
  thread = new Thread();
  thread.start();
}
// 쓰레드 동작 안하는 중
else if ( thread.isAlive() == false )
{
  // 앗싸리 새로 생성해서 다시 실행하는게 안전할라나???
  thread.start();
}
// 쓰레드가 아직 동작하는 중
else
{
   // 아무것도 안해도 되것죠? 이미 스레드가 돌고 있으니깐.
}

이렇게 해놓으면 미리 읽어들이는 중에서는 프로그래스 다이얼로그가 표시되지 않는다.

만일 사용자가 화면을 휙휙휙 넘겨서 쓰레드가 끝나기 전에 해당 화면으로 오면??? 

프로그래스 다이얼로그가 표시되어야 하는데 표시되지 않고 사용자가 뭔가를 입력할 수 있는 상황이 된다.

어랏??? 이것도 쬐끔 위험한 일이다.. 그래서 막아보자~~~

다음 코드를 넣어주면 된다.

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);

         if ( isVisibleToUser )
        {
            if ( thread != null )
            {
                // 스레드가 동작중이면
                if ( thread.isAlive( ) )
                {
                    // 한번도 표시된 적이 없다면
                    if ( progressDialog == null )
                    {
                        // 조회중 표시
                        progressDialog = ProgressDialog.show( TabActivity, “통신중”, “조회중…”, true, false );
                    }
                    // 표시중이지 않으면
                    else if ( progressDialog.isShowing() == false )
                    {
                        // 조회중 표시
                        progressDialog = ProgressDialog.show( TabActivity, “통신중”, “조회중…”, true, false );
                    }
                }
            }
        }   
}

마지막으로 이 프로그래스 다이얼로그는 쓰레드 종료 시점에 다음 코드로 종료해 주면 되것다.

if ( progressDialog != null )
{
     if ( progressDialog.isShowing() )
     {
          progressDialog.dismiss();
     }
}

작업환경 : 안드로이드 스튜디오 1.1.0
참고자료 : http://stackoverflow.com/questions/9323279/how-to-test-if-a-fragment-view-is-visible-to-the-user

Bitmap too large to be uploaded into a texture 에러 메시지 대처방법

내가 경험한 메시지는 정확하게 이렇게 나온다.

W/OpenGLRenderer﹕ Bitmap too large to be uploaded into a texture (5100×4212, max=4096×4096)



안드로이드에서 ImageView 에다가 좀 해상도가 나가는(?) 이미지를 올리면 이런 메시지가 나오는 경우가 있다.

실제 이미지 사이즈는 4096×4096보다 훨씬 작은데도 말이다. 
(나는 1700×1404 이었다 절반도 안되는데 막 이레… ㅡㅡ;)


황당한 것은 롤리팝(5.0)이 올라간 넥서스 5에서 퍽퍽 난다…. 죽지는 않고 이미지가 안나오고 흰 화면만 나올 뿐이다.

돌아버리는 줄알았다.. 

똑같은 apk를 프로요나 진저브레드에 설치해서 돌려보면 잘 돌아간다.

아놔… 이 시키들 뭘 바꾼겨??? 라는 생각을 했지만… 뭐… 갸들도 합리적이라 생각해서 뭔가를 바꿧겠지…



원인을 알아보자…

drawable 폴더에 있는 나의 이미지 파일은 drawable-mdpi 에 넣은거랑 동일하다. 

왜??? 거기가 1dp == 1px 이니깐… 근데… 내 안드로이드 기기가 xxhdpi(1080×1920)이라면 mdpi 꺼를 확대해서 사용한다.

몇배??? 

3배!!! ㅡㅡ;;;;

나의 경우는 1700*3 x 1404*3 = 5100 x 4212 딱 맞다~ 에러 메시지에 나온 얼토당토 않은 초고해상도가 이렇게 나온 것이었다.

췟!!! 이게 뭐다냥…


이제 해결을 해보자

우선 완전 간단하게 해결 하는 방법 : 
/drawable 에 있는 이미지 파일을 /drawable-nodpi 폴더로 이동한다. 
폴더가 없으면 /drawable 와 같은 레벨에 만들면 된다. dpi를 적용하지 않는 이미지가 저장되는 파일들이다. 
당근 xxhdpi 단말기에서도 확대를 하지 않고 그대로 쓴다.

해결은 당장 되지만 이미지의 퀄리티는 쫌 떨어져 보인다.


쬐끔 복잡하게 해결 하는 방법 : 
drawable-mdpi, hdpi, xhdpi, xxhdpi 에다가 각각의 화면 단위에 맞게 이미지를 만들어 주는 것이다.
같은 이미지를 해상도를 달리하여 저장하는 작업이기 때문에 쫌 까다롭겠지만 괸찮은 퀄리티의 이미지를 보여줄 수 있다.

C/C++ 매크로 동적(?) 사용하기

재밋는 동적 매크로

#define SHOW(id)    \
{\
    GetDlgItem(IDC_BUTTON##id)->ShowWindow(SW_SHOW);\
 }

이렇게 하면 

SHOW(4);

IDC_BUTTON4 리소스를 컨트롤 할 수 있다.

이런 식으로 호출 할 수 있다.

이놈의 리소스 ID는 작 맘대로 생겨 버려서… 
연번이 안되는 경우가 있어서 반복문을 사용하기 영~ 않좋다.

Windows 8 Pro K 라이센스로 윈10 설치…

2013년도에 Windows 8 Pro K 라이센스 프로모션이 있었어요.
그때 2만원이 안되는 가격에 삿죠. 핵 득템! 이었어요.

지금은 윈8에서 윈10으로 무료 업데이트도 안되는 시기인데…

혹시나 하여 윈10을 다운로드(순정) 받아서 Windows 8 Pro K 라이센스로 정품인증을 해봤어요.

윈도우8 , 8.1 링크 
http://www.microsoft.com/ko-kr/software-download/windows8

윈도우 10 링크
http://www.microsoft.com/ko-kr/software-download/windows10


정품인증 되네!!!! ㅋㅋㅋㅋㅋㅋㅋ 아이 조아라~~

윈8 프로 라이센스 키 있으신분 윈10 다운받아서 설치해 보세요~~~

윈8 키로 윈 8.1 바로 설치가 안된다는 글도 있던데.. 윈10은 설치할때 걍 윈8프로 라이센스 넣고 설치가 됩니다.

행복하세요~

C/C++에서 구조체(structure) 를 파일로 저장할때… 왜 쓰레기가 껴들어가지?

다 그런건 아닌데요.

스트럭처(구조체, structure)를 파일로 저장할때 신경질이 날때가 있습니다.

typedef struct tagMyStructure
{
    int nIdx;
    int nNo;
    short shAge;
    int nIncome;
} MYSTRUCTURE;

MYSTRUCTURE data;
data. nIdx = 0;
data.nNo = 10;
data.shAge = 40;
data.nIncome = 100000;

FILE    *hFile;
errno_t eNo = _tfopen_s( &hFile, _T( \temp\test.bin ), _T( “wb” ) );
fwrite( &data, sizeof( data ), 1, hFile );
fclose( hFile );

라고  구조체를 정의하고 필요한 값을 넣은다음에 파일에 써 넣으면 예상과 다른 결과를 마주하게 됩니다.

위에서 저장한 test.bin 파일을 헥사 뷰어 등으로 열어보면

원하는 거… (예상)는 다음과 같을겁니다.
(int : 4바이트, short는 2바이트 이니깐요…)

00 00 00 00 0A 00 00 00 28 00 A0 86 01 00

근데 실제로 헥사 뷰어로 열어보면

00 00 00 00 0A 00 00 00 28 00 CC CC A0 86 01 00

short 뒤에 두바이트가 끼어 들어가요!!!!
뭐뭐임!!!! 내가 원하는건 이게 아냐!!!
컴터야 왜 오동작하니….라고 생각할 수 있어요.

일단 급한건 해결방법
위에 스트럭쳐를 선언할때 위 아래로 다음과 같이 선언해 주세요

pragma pack(push, 2)

typedef struct tagMyStructure
{
    int nIdx;
    int nNo;
    short shAge;
    int nIncome;
} MYSTRUCTURE;

pragma pack(pop)

다시 컴파일해서 실행해보면 예상하는데로 결과가 잘 나옵니다.

이제 원인을 알아볼까요?

원인은 우리 컴터가 데이터를 32비트(즉 4바이트)단위로 처리를 하기 때문입니다.
뭐 … 성능때문에 메모리를 4바이트 단위로 읽어서 처리를 한다는게 기본 사상인데요.
한바이트씩 읽으면 4번할꺼 4바이트 한방에 읽으면 속도가 빨라지는 건 당연하겠죠. 그러나 그게… 인간이 느낄 수 있는 시간인지는 모른다에 한표… 

하여간… 그런 이유로 파일로 저장할때 구조체의 요소를 다 4바이트로 봐 버립니다. 젠장..
그래서 중간에 껴 있는 short 뒤에 2바이트가 껴들어가는거죠.
실제로 sizeof( data ) 로 구조체의 사이즈를 재면 16이 나옵니다.나는 12바이트짜리 구조체를 선언했는데 말이죠.. 
그래서 파일 저장도 16바이트가 되버리는데 short에는 2바이트만 정상적인 데이터가 있으니깐 쓰레기 2바이트가 껴 들어가게 됩니다.

이걸 정상화(?) 하기 위해서 #pragma pack(push, 2), #pragma pack(pop) 로 구조체를 싸 줬습니다.
요넘이 무슨 이야기냐…  2바이트 단위로 메모리 억세스해! 라는 소립니다.
긍게 short도 정상적으로 저장이 되고 sizeof( data ) 도 12바이트로 나오고… 잘 되요…

그렇습니다.