ViewPager 완전정복 - setUserVisibleHint를 사용한 예제

Posted by ITPangPang
2016. 11. 2. 23:18 안드로이드(android)/ViewPager


ViewPager 완전정복

(setUserVisibleHint를 사용한 예제)



ㆍ 이번글에서는 ViewPager를 사용할때 나름 굉장히

    중요한 setUserVisibleHint에 대해 알아보도록 하겠습니다.


ㆍ 이 부분은 앱에서 필요로 하는데 존재자체를 모르면

    굉장히 애 먹을 수 있는 부분입니다.


ㆍ 하지만 모든 ViewPager에 필요한게 아니고, 

    몰라도 돌려서 처리하는 방법이 있으니..



바로 전에 글

끝에서 잠시 얘기했던

상황을 예로 들겠습니다


ViewPager를 탭으로 안쓰고

한 페이지내에서

무언가 처리하는 과정에서

사용하는 경우라고 가정합시다


한 사용자가

과일가게 앱을 이용하는데

사과구매하려고 합니다.


사과를 구매하기 위해서는

첫페이지에서 구매할 개수

정하고, 두번째 페이지에서

결제금액을 확인할 수 있습니다

(금액확인 및 갯수 수정도 가능합니다)


앱 개발자는

 ViewPager를 사용하여

위의 상황대로

앱을 개발한다고 가정했을때


첫페이지

구매할 사과의 갯수를 적는 EditText

결제페이지로 이동하기 위한 Button

을 생성합니다.



두번째 페이지

구매하는 사과의 갯수(확인차)를 나타낼 TextView

결제할 금액을 나타낼 TextView

구매할 사과의 갯수를 +,- 할 수 있는 Button 2개


이 정도의 Widget들이 필요할 것입니다


위의 상황 그대로

앱을 만들었을때 나와야

되는 결과입니다.



결과를 보니

첫번째 페이지에서 사과의 갯수를

입력하고 두번째 페이지로 이동하니

자동으로 결제할 금액이 나오네요


위에처럼 앱을 만들려면

우리는 ViewPager에 무슨 짓을

해야할까요?


제목에 적었드시

setUserVisibleHint

사용해서 위의 화면처럼

만들 수 있습니다.

(물론 다른방법도 있겠죠)


ViewPager, Fragment 생명주기


위의 결과 코드 전체를

적진 않겠습니다.


그냥 분석하는 글이기 때문에

중간중간 코드만 테스트하면서

써보겠습니다.


ViewPager 분석글마다

아마 적었던 것 같은데


ViewPager는 좌우 페이지를

미리 그려놓고 준비한다!


위 말을 계속 하고

이전글에서는 Log를 찍어서

확인해봤었죠.


사과구매앱 페이지의

생명주기를 보면


앱을 실행하여 갯수를

적을 수 있는 첫번째 페이지가

열릴때, 


열림과 동시에 두번째 결제금액

페이지까지 미리 그려놓습니다

(이전글에서 Log로 다음 페이지의

onCreateView를 타는 것을 확인했었죠)


그래서

우리는 앱이 실행되고

첫번째 페이지가 우리 눈에

뜨는 순간을 제외하고는


일반적으로

onCreateView를 태울 수 있는

방법은 없습니다



위의 말을 왜 자꾸하는가 하면

1페이지에서 사과 5개를 입력했는데


2페이지에 넘어가면서 5개라는걸

눈치채고 5 x 5000원 해서 25000원을

찍어놔야되는데


그 5개의 정보를 받을수가 없습니다.


onCreatView에서 아무리

갯수*5000원 적어놔봤자

호출이 안되기 때문에 의미가 없는거죠

(꼼수 제외하고 일반적인 경우입니다...)


위에 상황을 해결하기 위해서

우리는 setUserVisibleHint

추가해줍니다



setUserVisibleHint

사용자 눈에 보이는 순간,

안보이는 순간을 알아낼 수 있습니다


두번째

Fragment(사과 결제금액 페이지)에서

코드를 이렇게 달아줍니다

@Override
public void setUserVisibleHint(boolean isVisibleToUser)
{
if(isVisibleToUser)
{
//두번째 페이지 사용자 눈에 보임
}
else
{
//두번째 페이지 사용자 눈에 안보임
}
super.setUserVisibleHint(isVisibleToUser);
}


위 코드가 무슨 말인가 하면


사용자가 첫번째 페이지에 있을때는

else를 타고


두번째 페이지에 들어오는 순간

if에 들어옵니다


두번째 페이지가 들어오는 순간을

우리는 잡을 수 있습니다.


그럼 여기서 위에서 하고 싶었던

사과갯수 * 5000원을 써주면 됩니다.


@Override
public void setUserVisibleHint(boolean isVisibleToUser)
{
if(isVisibleToUser)
{
count = ((MainActivity)getActivity()).tempCount;
tv.setText("사과 "+count+"개"); //사과 갯수 확인 TextView
tv2.setText(count*price+"원"); //결제예상금액 TextView
}
else
{
try
{
Log.d("TEST", "LifeCycle invisible(second)");
}
catch (Exception e)
{
e.printStackTrace();
}

}
super.setUserVisibleHint(isVisibleToUser);
}



count = ((MainActivity)getActivity()).tempCount;


이 부분은

 Fragment와 Fragment가

다이렉트로 통신할 수 없기에


Fragment - Activity - Fragment

값을 넘겨주어야 합니다



첫번째 페이지에서

사과의 갯수를 적고 결제버튼을

누르는 순간

메인 액티비티에 값을 넘깁니다

btn.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
((MainActivity)getActivity()).tempCount = Integer.parseInt(et.getText().toString());
((MainActivity)getActivity()).vp.setCurrentItem(1);
}
});


이 값을

두번째 Fragment에서

사용자눈에 보이는 순간 가져와서

사용하는 것입니다.


setUserVisibleHint

유용하게 쓰이는 경우는

많습니다


2번째 페이지가 열릴때 Animation을 보여줘야 한다

>if(invisibleToUser)에서 startAnimation


2번째 페이지에서 첫번째 페이지로 넘길때 페이지에 찍힌값들 초기화

>else(사용자눈에 안보일때)에서 초기화 시키면 되겠죠


첫번째 페이지에서 입력하는 숫자만큼 View 동적생성(나중에 만들어 볼 예정)


등등...



사용할 곳은 많겠죠.?


마지막으로 자세하게 

정리를 해보겠습니다


앱 실행(첫번째 페이지 보이는 순간)

invisible(첫번째 Fragment)

invisible(두번째 Fragment)

visible(첫번째 Fragment)

onCreateView(두번째 Fragment)

onCreateView(첫번째 Fragment)


첫번째 페이지 -> 두번째페이지 전환시

invisible(첫번째 Fragment)

visible(두번째 Fragmgnet)


두번째페이지 -> 첫번째페이지 전환시

invisible(두번째 Fragment)

visible(첫번째 Fragment)


나름 중요한 부분입니다.


첫번째, 

앱 실행시 onCreateView보다

invisible을 먼저 탄다는 점


이 말은 invisible에

생성 및 초기화하지도 않은

객체들을 그냥 사용하게 되면

NullPoint 에러가 뜨게 됩니다.


그러므로 invisible에 코드를 넣을때는

그 객체가 null값인지 아닌지 체크하는

조건을 꼭 걸어주어야 합니다.


두번째,

계속 말해왔던 앱 실행시를

제외하는 경우에는

onCreateView를 안탄다!

(물론 위 예를 들었던 2페이지로

구성되어있을때입니다.


3페이지면 3페이지로 갈 때 1페이지는 파괴되고

2페이지로 갈때 다시 1페이지는 생성되겠죠?

이전글에서 봤던 내용..)


이것으로

setUserVisibleHint에 대해서는

간단하게 알아보았고,


그 다음 내용은

- addOnPageChangeListener에 대해서

이것이 될 것 같습니다.


끝!