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

ViewPager에서 현재 페이지가 제일 나중에 로딩되게?

0 추천
ViewPager내에 WebView를 이용해서 HTML을 로딩하려고 합니다.

HTML내에는 audio 태그를 이용해서 autoplay 를 하고자 하구요.

그런데 예를 들어 5페이지로 점프를 하게 되면 5,4,6 페이지의 순서로

instantiateItem이 호출됩니다. (ViewPager의 특성상 현재,이전,이후 페이지를 로딩)

그래서 화면 자체는 5페이지가 나오지만, 6페이지(이후 페이지)의 audio가 play되네요.

OnPageChangeListener를 이용해도 해결이 안되네요.

해결책이 없을까요?

로딩되는 순서를 5,4,6이 아니라 4,6,5로 바꿀수 있으면 문제가 해결될 것 같은데,

그런 방법이 없을까요?
익명사용자 님이 2014년 7월 14일 질문

2개의 답변

+1 추천

 ViewPager는 원래 현재 페이지의 이전 페이지와 다음 페이지를 미리 생성하는 특성을 가지고 있고

(터치 슬라이드 이벤트에 바로 이전이나 다음 페이지가 함께 보여야 하기 때문이죠)

setoffscreenpagelimit로 설정한 페이지만큼 메모리내에 페이지를 가지고 있습니다. (default는 1)

그래서 질문하신 것과 같은 동작을 하려면 실제 페이지가 지금 화면에 보여지고 있는가를 판별하는 알고리즘이 필요합니다.

근데 그 알고리즘은 instantiateItem에서 생성하고 있는 아이템이 뭔가(View인지 Fragment인지 등등..)에 따라 구현이 달라지기 때문에

그 부분에 대해 추가적인 내용이 있어야 도와드릴 수 있겠네요.

b22n (22,940 포인트) 님이 2014년 7월 14일 답변
b22n님 답변 감사드립니다.
제가 테스트 했던 소스 올립니다.
한번 봐주시면 큰 도움을 될 것 같습니다.

일단 아래 URL에 있는 샘플을 사용했구요..
http://thorbek.net/online/2014/03/17/sliding-webview-fragments-with-viewpager/

관련소스는 아래와 같습니다.
제가 글 올리는게 익숙치 않아서 보기 불편하시더라도 조금 이해 부탁드립니다.

-----------MainActivity.java -------------
public class MainActivity extends FragmentActivity  {

    private String gsPath = "file:///sdcard/Android/data/test/";
    private String gsURL = "";
   
    @Override
    public void onBackPressed() {
        super.onBackPressed();
    }

    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
       
        try {
            pageAdapter = new MyPageAdapter(getSupportFragmentManager());             
            // Add any number of items to the list of your Fragment
            for (int i=0; i<10; i++) {
                gsURL = gsPath + "000" + i + ".html";
                pageAdapter.addItem(gsURL, "");
            }
            
            myPager = (ViewPager)findViewById(R.id.viewPager);
     
            // This gives the number of Fragments loaded outside the view.
            // Here set to the number of Fragments minus one, i.e., all Fragments loaded.
            // This might not be a good idea if there are many Fragments.
            //pager.setOffscreenPageLimit(pageAdapter.getCount() - 1);
            myPager.setOffscreenPageLimit(1);
            myPager.setAdapter(pageAdapter);

            Button btnGoto = (Button)findViewById(R.id.btnGoto);
            btnGoto.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    myPager.setCurrentItem(5, true);
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // A helper class to keep a list of the Fragments and titles.
    private class MyPageAdapter extends FragmentPagerAdapter {
        private List<Fragment> fragments;
        private List<String> titles;
           
        public MyPageAdapter(FragmentManager fm) {
               super(fm);
               this.fragments = new ArrayList<Fragment>();
               this.titles    = new ArrayList<String>();
        }
           
        public void addItem(String url, String title) {
            Fragment myFragment = new MyWebView();
            Bundle args = new Bundle();
            args.putString("url", url);
            myFragment.setArguments(args);
            this.fragments.add(myFragment);
            this.titles.add(title);
        }
           
        @Override
        public Fragment getItem(int position) {
            return this.fragments.get(position);
        }
           
        public CharSequence getPageTitle(int position) {
            return this.titles.get(position);
        }
           
        @Override
        public int getCount() {
            return this.fragments.size();
        }
    }
     
    private MyPageAdapter pageAdapter  = null;
    private ViewPager myPager          = null;
}

---------- MyWebView.java --------------
public class MyWebView extends Fragment {
     
    private WebView webView;
      
    @SuppressLint("SetJavaScriptEnabled")
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        // get the url to open
        Bundle args = getArguments();
        String url = args.getString("url");
        // set up the WebView
        webView = (WebView) getView().findViewById(R.id.webView);
        webView.setWebViewClient(new MyBrowser());
        webView.getSettings().setLoadsImagesAutomatically(true);
        webView.getSettings().setJavaScriptEnabled(true);
        webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
        webView.loadUrl(url);
    }
     
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
         
        View view = inflater.inflate(R.layout.web_view, container, false);
        return view;       
    }  
 
    private class MyBrowser extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
           view.loadUrl(url);
           return true;
        }
    }
}

---------- activity_main.xml ---------------
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <Button
        android:id="@+id/btnGoto"
        android:text="goto"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</FrameLayout>

---------------- web_view.xml ---------------------
<?xml version="1.0" encoding="utf-8"?>
<WebView  xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/webView"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
/>

-------------- 0001.HTML은 아래와 같은 식으로 사용 --------------
<audio id="player" src="./mp3/0001.mp3" autoplay></audio>
프로젝트의 요구사항을 정확히 모르지만, 일반적으로 유추했을 땐
이 경우는 뷰페이져가 웹 페이지는 앞 뒤 페이지 그대로 미리 로딩하되
audio의 플레이만 프레그먼트가 보이는 중일 때 실행되도록 하는 것이 자연스러울 것 같습니다.
일단 html 코드에서 autoplay를 제거하고 따로 player를 재생시키는 자바스크립트 함수를 만들어 MyWebView에서 호출가능하게 하는데 까지 구성하시고,
FragmentPagerAdapter의 소스를 보면 아시겠지만 fragment가 현재 페이지로 선택되면 setMenuVisibility(boolean menuVisible)  함수로 메뉴의 상태를 셋팅하기 때문에 MyWebView 의 setMenuVisibility함수를 오버라이딩해서 menuVisible값이 true일때 player를 재생하는 구조로 가시면 됩니다.
상세한 답변 감사드립니다.
autoplay를 빼고 스크립트로 시도도 해봤는데 마찬가지로 다음 페이지가 호출이 되더라구요.
암튼 말씀해주신대로 다시 한번 시도해 보도록 하겠습니다.
감사합니다.
0 추천
instantiateItem에서 바로 URL을 로딩하는 것 같습니다.

페이지가 실제로 보여질 때 로딩하도록 수정하면 될 것 같습니다.
익명사용자 님이 2014년 7월 14일 답변
답변 감사드립니다. ^^;
그런데 페이지가 실제로 보여질 때 라는게 구체적으로 어느 부분을 말씀하시는건지요?
OnPageChangeListener 쪽을 말씀하시는건가요?
아무리 바꿔봐도 계속 다음페이지의 음원이 재생되네요..
...