0

I am trying to add a ViewPager to my Android app as a one-time setup screen for the user. But the problem I am facing is that the app keeps crashing when the orientation of the screen is changed amidst the setup process.

If the app is opened in either portrait or landscape mode and used without any orientation change, it works fine. But if the orientation is changed during runtime, using the method setCurrentItem(int position) on the ViewPager crashes the app.

Here's my Fragment class -

package com.cosine.arc;


import android.content.Context;
import android.graphics.Typeface;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

/**
 * A simple {@link Fragment} subclass.
 */
public class WelcomeFragment extends Fragment {

private int mPosition;
private Context mContext;
private ViewPager mPager;

private final int[] welcomeFragments = {R.layout.fragment_welcome1};

public WelcomeFragment() {
    // Required empty public constructor
}

public WelcomeFragment(Context context, ViewPager viewPager, int position) {

    this.mPosition = position;
    this.mContext = context;
    this.mPager = viewPager;

}

@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {

    View view = null;

    try {
        switch (mPosition) {

            case 0:
                view = inflater.inflate(R.layout.fragment_welcome1, container, false);

                Typeface robotoLight = Typeface.createFromAsset(getActivity().getAssets(), "fonts/Roboto-Light.ttf");
                TextView welcomeTxt1x2 = (TextView) view.findViewById(R.id.welcome_text_1_2);

                Button startButton = (Button) view.findViewById(R.id.welcome_btn_1_1);


                startButton.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        mPager.setCurrentItem(1);
                    }
                });
                welcomeTxt1x2.setTypeface(robotoLight);
        }
    } catch (NullPointerException e) {
        e.printStackTrace();
    }

    return view;
}

}

And here's my FragmentActivity class with the FragmentStatePagerAdapter class within it -

package com.cosine.arc;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.PagerAdapter;

public class IntroActivity extends FragmentActivity {

private static int NUM_PAGES = 3;

private NonSwipeableViewPager mPager;
private PagerAdapter mPagerAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_intro);

    mPager = (NonSwipeableViewPager) findViewById(R.id.intro_pager);
    mPagerAdapter = new IntroSliderAdapter(getSupportFragmentManager());
    mPager.setAdapter(mPagerAdapter);

}

@Override
public void onBackPressed() {
    if (mPager.getCurrentItem()==0) {
        super.onBackPressed();
    }
    else {
        mPager.setCurrentItem(mPager.getCurrentItem()-1);
    }
}

public int getCurrentItem() {
    return mPager.getCurrentItem();
}

public NonSwipeableViewPager getPagerUpdate() {

    return mPager;
}

private class IntroSliderAdapter extends FragmentStatePagerAdapter {

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

    @Override
    public Fragment getItem(int position) {
        return new WelcomeFragment(getBaseContext(), mPager, position);
    }

    @Override
    public int getCount() {
        return NUM_PAGES;
    }

}
}

And here is the error log -

04-07 15:25:13.774 12186-12186/com.cosine.arc E/AndroidRuntime: FATAL EXCEPTION: main
   Process: com.cosine.arc, PID: 12186 java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v4.view.ViewPager.setCurrentItem(int)' on a null object reference
   at com.cosine.arc.WelcomeFragment$1.onClick(WelcomeFragment.java:58)
   at android.view.View.performClick(View.java:5612)
   at android.view.View$PerformClick.run(View.java:22288)
   at android.os.Handler.handleCallback(Handler.java:751)
   at android.os.Handler.dispatchMessage(Handler.java:95)
   at android.os.Looper.loop(Looper.java:154)
   at android.app.ActivityThread.main(ActivityThread.java:6123)
   at java.lang.reflect.Method.invoke(Native Method)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)

fragment_welcome1.xml -

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.cosine.arc.WelcomeFragment">

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimary">

    <TextView
        android:id="@+id/welcome_text_1_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/welcome_to_"
        android:textColor="@android:color/white"
        android:textSize="36sp"
        android:padding="16dp"
        android:layout_marginTop="16dp"
        android:gravity="center"/>

    <ImageView
        android:id="@+id/welcome_img_1_1"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:src="@drawable/ic_logo"
        android:layout_below="@id/welcome_text_1_1"
        android:layout_centerHorizontal="true"/>

    <TextView
        android:id="@+id/welcome_text_1_2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/welcome_img_1_1"
        android:text="@string/lets_get_things_started_"
        android:textSize="42sp"
        android:textColor="@android:color/white"
        android:padding="16dp"
        android:layout_marginTop="32dp"/>

    <Button
        android:id="@+id/welcome_btn_1_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="@android:color/white"
        android:text="Start"
        android:textColor="@android:color/black"
        android:layout_margin="16dp"
        android:layout_alignParentRight="true"
        android:drawableRight="@mipmap/ic_arrow_right_light"/>

</RelativeLayout>

Please do note that I have two different layout files fragment_welcome1.xml and fragment_welcome1.xml-land.

Swap
  • 480
  • 2
  • 7
  • 21

1 Answers1

0

On orientation change, you will have to save the instance of the fragment if you want to retain the references. Have a look at this answer, hope it helps you. In a nutshell, i think you will need to save the instance of the fragment in your container activity's onSaveInstanceState(), and then recreate your saved fragment when orientation changes.

Please note that making config changes in the manifest is not the recommended way to save the instance of the fragment. Making config changes will lead to memory leaks.

Community
  • 1
  • 1
Kaveesh Kanwal
  • 1,753
  • 17
  • 16
  • This method works well when the `Fragment` class is used in the layout resource file. But I followed the official Android documentation for [Using ViewPager for Screen Slides](https://developer.android.com/training/animation/screen-slide.html) and it did not use the `Fragment` class for the purpose and hence I avoided it in my project as well. I've added my layout resource file to the question, please check. – Swap Apr 07 '17 at 10:27
  • It will work when you dynamically add new fragments to your container activity. You can save state of fragments when device is rotated, and you can also save values which are set in your POJO classes. Have a look at [this link](http://stackoverflow.com/questions/7951730/viewpager-and-fragments-whats-the-right-way-to-store-fragments-state) – Kaveesh Kanwal Apr 07 '17 at 10:43