Search code examples
androidwebviewfragmentstatepageradapter

WebView with FragmentStatePagerAdapter goes blank on calling setCurrentItem


I am working on Swipe Views with Tabs. The code provided in the "EffectiveNavigation" project at the Creating Swipe Views with Tabs page provides a solid starting ground. Experimenting further I added an OnClickListener to the given TextView and added a setCurrentItem to the onClick method. This behaves as expected and the ViewPager jumps to the requested page.

/**
 * A dummy fragment representing a section of the app, but that simply displays dummy text.
 */
public static class DemoObjectFragment extends Fragment {

    public static final String ARG_OBJECT = "object";

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_collection_object, container, false);
        Bundle args = getArguments();
        ((TextView) rootView.findViewById(android.R.id.text1)).setText(
                Integer.toString(args.getInt(ARG_OBJECT)));

        ((TextView) rootView.findViewById(android.R.id.text1)).setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
              /*
               *setCurrentPagerItem(5); -> omitted here to reduce complexity              
              */
              mViewPager.setCurrentItem(5); 
            }
        });
        return rootView;
    }       
}

As the project I'm working on requires the loading of static webpages instead of text. I replaced the TextView with a WebView to load a different webpage at every swipe. This works perfectly well. Click events from the HTML side are handled by a JavascriptInterface I have implemented.

It is here that I'm facing a problem. The setCurrentPagerItem method works perfectly well when called outside of the JavascriptInterface. When called from within the JavascriptInterface the WebView shows a blank screen and stays so until a swipe to the right or left is made. A swipe to the right displays the next page to the one requested and a swipe to the left displays the requested page. LogCat shows no errors and this behaviour is consistent across a 4.3 based emulator and a Nexus 7 running 4.4.4. I shall provide the entire code below.

public class CollectionDemoActivity extends FragmentActivity {

/**
 * The {@link android.support.v4.view.PagerAdapter} that will provide fragments representing
 * each object in a collection. We use a {@link android.support.v4.app.FragmentStatePagerAdapter}
 * derivative, which will destroy and re-create fragments as needed, saving and restoring their
 * state in the process. This is important to conserve memory and is a best practice when
 * allowing navigation between objects in a potentially large collection.
 */
DemoCollectionPagerAdapter mDemoCollectionPagerAdapter;   


/**
 * The {@link android.support.v4.view.ViewPager} that will display the object collection.
 */
ViewPager mViewPager;

private static Context context;  

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_collection_demo);

    context = this;

    // Create an adapter that when requested, will return a fragment representing an object in
    // the collection.
    // 
    // ViewPager and its adapters use support library fragments, so we must use
    // getSupportFragmentManager.
    mDemoCollectionPagerAdapter = new DemoCollectionPagerAdapter(getSupportFragmentManager());

    // Set up action bar.
    final ActionBar actionBar = getActionBar();

    // Specify that the Home button should show an "Up" caret, indicating that touching the
    // button will take the user one step up in the application's hierarchy.
    actionBar.setDisplayHomeAsUpEnabled(true);

    final OnPageChangeListener mPageChangeListener = new OnPageChangeListener() {

        @Override
        public void onPageScrollStateChanged(int arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onPageSelected(int pos) {

            final Toast pageNo;
            pageNo = Toast.makeText(context,"PAGE "+(Integer.toString(pos+1))+"/100",Toast.LENGTH_SHORT);
              pageNo.show();
              Handler handler = new Handler();
              handler.postDelayed(new Runnable() {
                 @Override
                 public void run() {
                   pageNo.cancel(); 
                 }
              }, 100);  

        }

    };

    // Set up the ViewPager, attaching the adapter.
    mViewPager = (ViewPager) findViewById(R.id.pager);        
    mViewPager.setAdapter(mDemoCollectionPagerAdapter);
    mViewPager.setOnPageChangeListener(mPageChangeListener);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            // This is called when the Home (Up) button is pressed in the action bar.
            // Create a simple intent that starts the hierarchical parent activity and
            // use NavUtils in the Support Package to ensure proper handling of Up.
            Intent upIntent = new Intent(this, MainActivity.class);
            if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
                // This activity is not part of the application's task, so create a new task
                // with a synthesized back stack.
                TaskStackBuilder.from(this)
                        // If there are ancestor activities, they should be added here.
                        .addNextIntent(upIntent)
                        .startActivities();
                finish();
            } else {
                // This activity is part of the application's task, so simply
                // navigate up to the hierarchical parent activity.
                NavUtils.navigateUpTo(this, upIntent);
            }
            return true;
    }
    return super.onOptionsItemSelected(item);
}

private void setCurrentPagerItem(int item) { 

    mViewPager.setCurrentItem(item);
}


/**
 * A {@link android.support.v4.app.FragmentStatePagerAdapter} that returns a fragment
 * representing an object in the collection.
 */
public static class DemoCollectionPagerAdapter extends FragmentStatePagerAdapter {

    public DemoCollectionPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int i) {
        Fragment fragment = new DemoObjectFragment();
        Bundle args = new Bundle();
        args.putInt(DemoObjectFragment.ARG_OBJECT, i + 1); // Our object is just an integer :-P
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public int getCount() {
        // For this contrived example, we have a 100-object collection.
        return 100;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return "OBJECT " + (position + 1);
    }

}

/**
 * A dummy fragment representing a section of the app, but that simply displays dummy text.
 */
public static class DemoObjectFragment extends Fragment {

    public static final String ARG_OBJECT = "object";

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_collection_object, container, false);
        Bundle args = getArguments();

        final WebView webView = (WebView) rootView.findViewById(R.id.webView);             

        switch(args.getInt(ARG_OBJECT)) {

            case 1   :  
                    webView.loadUrl("file:///android_asset/html/index.html");  
                    break;

            default  :
                    webView.loadUrl("file:///android_asset/html/page_"+(Integer.toString(args.getInt(ARG_OBJECT)-1))+".html");
                    break;              
        }    

        WebSettings ws = webView.getSettings();        
        ws.setJavaScriptEnabled(true);              

        webView.addJavascriptInterface(new Object()
        {

          @JavascriptInterface
          public void toPage(String pageNo) {                 

              ((CollectionDemoActivity) getActivity()).setCurrentPagerItem(4);

          }
        }, "external");

        return rootView;
    }       
} 

}


Solution

  • I could be wrong but it sounds like you are not updating on the UIThread.

    You could try something like this.

    getActivity().runOnUiThread(new Runnable(){
                @Override
                public void run() {
                    ((CollectionDemoActivity) getActivity()).setCurrentPagerItem(4);
                }
            });