Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to resume an activity when using a viewPager

I've been having trouble with the viewPager i'm trying to add to my app.

I have a SearchResultActivity that has a drawer in it. with the following layout:

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<FrameLayout
    android:id="@+id/content_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

<ListView
    android:id="@+id/left_drawer"
    android:layout_width="240dp"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:background="#111"
    android:choiceMode="singleChoice"
    android:divider="@android:color/transparent"
    android:dividerHeight="0dp" />

because I'm using fragments, when first arriving at this activity, I open use a transaction to open a RecipeHeadlinesFragment in the Activity's onCreate method:

    @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.drawer_main);
    mSearchType = getIntent().getIntExtra(SEARCH_TYPE, -1);
    if (mSearchType == ICON_SEARCH) {
        mVeggieNamesIcons = getIntent().getStringArrayListExtra(
                VEGGIE_NAME_ARR);
        mVeggieUrlsIcons = getIntent().getStringArrayListExtra(
                VEGGIE_URLS_ARR);
    } else if (mSearchType == QUERY_SEARCH) {
        mQuery = getIntent().getStringExtra(QUERY);
    }
    // Generate title
    title = new String[] { "Search for a recipe", "My profile",
            "Title Fragment 3" };

    // Generate subtitle
    subtitle = new String[] { "", "", "Subtitle Fragment 3" };

    // Generate icon
    icon = new int[] { R.drawable.action_about, R.drawable.action_settings,
            R.drawable.collections_cloud };

    // Locate DrawerLayout in drawer_main.xml
    mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);

    // Locate ListView in drawer_main.xml
    mDrawerList = (ListView) findViewById(R.id.left_drawer);

    // Set a custom shadow that overlays the main content when the drawer
    // opens
    mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow,
            GravityCompat.START);

    // Pass results to MenuListAdapter Class
    mMenuAdapter = new MenuListAdapter(this, title, subtitle, icon);

    // Set the MenuListAdapter to the ListView
    mDrawerList.setAdapter(mMenuAdapter);

    // Capture button clicks on side menu
    mDrawerList.setOnItemClickListener(new DrawerItemClickListener());

    // Enable ActionBar app icon to behave as action to toggle nav drawer
    getSupportActionBar().setHomeButtonEnabled(true);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

    // ActionBarDrawerToggle ties together the the proper interactions
    // between the sliding drawer and the action bar app icon
    mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
            R.drawable.menubutton, R.string.drawer_open,
            R.string.drawer_close) {

        public void onDrawerClosed(View view) {
            getActionBar().setTitle("");
            // getActionBar().setBackgroundDrawable(d)
            super.onDrawerClosed(view);
            invalidateOptionsMenu();
        }

        public void onDrawerOpened(View drawerView) {
            getActionBar().setTitle("menu");
            // getActionBar().setBackgroundDrawable(new
            // ColorDrawable(Color.GREEN));
            super.onDrawerOpened(drawerView);
            invalidateOptionsMenu();
        }
    };

    mDrawerLayout.setDrawerListener(mDrawerToggle);
    // Check whether the activity is using the layout version with
    // the fragment_container FrameLayout. If so, we must add the first
    // fragment
    if (findViewById(R.id.content_frame) != null) {
        if (savedInstanceState == null) {
            Bundle args = new Bundle();
            args.putInt(SEARCH_TYPE, mSearchType);
            if (mSearchType == QUERY_SEARCH) {
                args.putString(QUERY, mQuery);
            } else if (mSearchType == ICON_SEARCH) {
                args.putStringArrayList(VEGGIE_NAME_ARR, mVeggieNamesIcons);
                args.putStringArrayList(VEGGIE_URLS_ARR, mVeggieUrlsIcons);
            }

            recipeHeadlines.setArguments(args);
            // Add the fragment to the 'fragment_container' FrameLayout
            FragmentTransaction ft = getSupportFragmentManager()
                    .beginTransaction().replace(R.id.content_frame,
                            recipeHeadlines);
            ft.commit();
        } else {
            return;
        }
    }

    getActionBar().setIcon(R.color.transparent);
}

The RecipeHeadlinesFragment is a sherlockListFragment. i've created an onArticleSelectedListener interface in it, and made the activity implement it, such that when a list item is selected, the activity's onArticleSelected method is called and a RecipeTabsFragment is initiated and passed to the front using another transaction:

    public void onArticleSelected(int position, RecipeObj obj) {
    // The user selected the headline of an article from the
    // HeadlinesFragment

    // Capture the article fragment from the activity layout
    RecipeTabsFragment articleFrag = (RecipeTabsFragment) getSupportFragmentManager()
            .findFragmentById(R.id.pager);

    if (articleFrag != null) {
        // If article frag is available, we're in two-pane layout...

        // Call a method in the ArticleFragment to update its content
        articleFrag.updateArticleView(position, obj);
        // todo update data

    } else {
        // If the frag is not available, we're in the one-pane layout and
        // must swap frags...

        // Create fragment and give it an argument for the selected article
        RecipeTabsFragment newFragment = new RecipeTabsFragment();
        Bundle args = new Bundle();
        args.putParcelable(RecipeTabsFragment.ARG_RECIPE, obj);
        args.putInt(RecipeTabsFragment.ARG_POSITION, position);
        newFragment.setArguments(args);
        FragmentTransaction transaction = getSupportFragmentManager()
                .beginTransaction();

        // Replace whatever is in the fragment_container view with this
        // fragment,
        // and add the transaction to the back stack so the user can
        // navigate back
        transaction.replace(R.id.content_frame, newFragment);


        // Commit the transaction
        transaction.commit();
    }
}

this is my RecipeTabsFragment code:

public class RecipeTabsFragment extends SherlockFragment {
// Declare Variables
final static String ARG_POSITION = "position";
final static String TAB_POSITION = "tab";
final static String ARG_RECIPE = "recipeData";

View rootView;
ActionBar mActionBar;
TextView mRecipeTitle;
TextView mRecipeBloger;
RatingBar mRecipeRatingBar;

int mCurrentPosition = -1;
int mCurrentTab = 0;

static ViewPager mPager;
Tab tab;
FragmentStatePagerAdapter mAdapter;
static final int NUM_ITEMS = 3;
// View rootView;
EditText editsearch;

ProgressDialog mProgressDialog;
// ImageAndName[] mTemplist = {};
GridView gridview;

private RecipeObj mRecipeData;
// The container Activity must implement this interface so the frag can
// deliver messages
public interface OnNameSetter {
    /** Called by HeadlinesFragment when a list item is selected */
    public void setName(String name);
    public String getName();
}


public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

}

@Override
public void onPrepareOptionsMenu(Menu menu) {
    //initialize the recipe title,bloger and rating view on the action bar
    MenuItem item = menu.findItem(R.id.data_item);

    mRecipeTitle = (TextView) item.getActionView().findViewById(
            R.id.tv_title_ab);
    mRecipeBloger = (TextView) item.getActionView().findViewById(
            R.id.tv_bloger_ab);
    mRecipeRatingBar = (RatingBar) item.getActionView().findViewById(
            R.id.rb_list_item_ab);

    //set the actual data to the view
     mRecipeTitle.setText(mRecipeData.getFields().getName());
    super.onPrepareOptionsMenu(menu);
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.recip_detail, menu);
    super.onCreateOptionsMenu(menu, inflater);
}

@SuppressWarnings("null")
@Override
public void onStart() {
    super.onStart();
    Bundle args = getArguments();
    if (args != null) {
        // Set article based on argument passed in
        updateArticleView(args.getInt(ARG_POSITION), (RecipeObj) args.getParcelable(ARG_RECIPE));



    } else if (mCurrentPosition != -1) {
        // Set article based on saved instance state defined during
        // onCreateView

        updateArticleView(mCurrentPosition, mRecipeData);
    }
}

public void updateArticleView(int position, RecipeObj data) {

    mRecipeData = data;
    mCurrentPosition = position;
}

public void onResume() {
    super.onResume();
    //allows to put data on action bar that is not a action widget
    getSherlockActivity().supportInvalidateOptionsMenu();
    mActionBar = getSherlockActivity().getSupportActionBar();
    mActionBar.setTitle("");

    FragmentManager fm = getSherlockActivity().getSupportFragmentManager();
    final ArrayList<String> titles = new ArrayList<String>();
    titles.add("tab1");
    titles.add("tab2");
    titles.add("tab3");
    mAdapter = new FragmentStatePagerAdapter(fm){

        @Override
        public Fragment getItem(int position) {
            switch (position) {
            case 0:
                // Your current main fragment showing how to send arguments to
                // fragment
                RecipeArticle fragment1 = new RecipeArticle();
                Bundle data1 = new Bundle();
                data1.putParcelable(RecipeTabsFragment.ARG_RECIPE, mRecipeData);
                fragment1.setArguments(data1);
                  fragment1.setName(titles.get(position));
                return fragment1;
            case 1:
                // Calling a Fragment without sending arguments
                RecipePreparation fragment2 = new RecipePreparation();
                Bundle data2 = new Bundle();
                data2.putParcelable(RecipeTabsFragment.ARG_RECIPE, mRecipeData);
                fragment2.setArguments(data2);
                 fragment2.setName(titles.get(position));
                return fragment2;
            case 2:
                Fragments3 fragment3 = new Fragments3();
                // Bundle data2 = new Bundle();
                // data2.putParcelable(IngrFragment.ARG_RECIPE, recipeData);
                // fragment2.setArguments(data2);
                 fragment3.setName(titles.get(position));

                return fragment3;
            default:
                return null;
            }
        }

        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return NUM_ITEMS;
        }
        @Override
         public int getItemPosition(Object item) {
                OnNameSetter fragment = (OnNameSetter)item;
                String title = fragment.getName();
                int position = titles.indexOf(title);

                if (position >= 0) {
                    return position;
                } else {
                    return POSITION_NONE;
                }
            }

    };
    mPager = (ViewPager) rootView.findViewById(R.id.pager);
    mPager.setAdapter(mAdapter);
    mAdapter.notifyDataSetChanged();
    mPager.setOnPageChangeListener(new OnPageChangeListener() {

        @Override
        public void onPageScrollStateChanged(int arg0) {

        }

        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {

        }

        //
        // @Override
        public void onPageSelected(int arg0) {

            mActionBar.getTabAt(arg0).select();
        }

    });

    mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    // Create first Tab
    tab = mActionBar
            .newTab()
            .setText(getString(string.ingrdients))
            .setTabListener(
                    new TabListener<RecipeArticle>(this
                            .getSherlockActivity(), "SearchPage1",
                            RecipeArticle.class));
    tab.setIcon(R.drawable.ing);
    mActionBar.addTab(tab);

    // Create second Tab
    tab = mActionBar
            .newTab()
            .setText(getString(string.prepration))
            .setTabListener(
                    new TabListener<RecipePreparation>(this
                            .getSherlockActivity(), "SearchPage2",
                            RecipePreparation.class));
    tab.setIcon(R.drawable.how);
    mActionBar.addTab(tab);

    // Create third Tab
    tab = mActionBar
            .newTab()
            .setText(getString(string.comments))
            .setTabListener(
                    new TabListener<Fragments3>(this.getSherlockActivity(),
                            "SearchPage3", Fragments3.class));
    tab.setIcon(R.drawable.why);
    mActionBar.addTab(tab);
    setHasOptionsMenu(true);
    mActionBar.getTabAt(mCurrentTab).select();

}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    if (savedInstanceState != null) {
        mCurrentPosition = savedInstanceState.getInt(ARG_POSITION);
        mRecipeData = savedInstanceState.getParcelable(ARG_RECIPE);
        mCurrentTab = savedInstanceState.getInt(TAB_POSITION);

    }
    rootView = inflater.inflate(R.layout.ingr_tabs, container, false);


    return rootView;
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    // Save the current article selection in case we need to recreate the
    // fragment
    outState.putInt(ARG_POSITION, mCurrentPosition);
    outState.putInt(TAB_POSITION, mCurrentTab);
    outState.putParcelable(ARG_RECIPE, mRecipeData);
}


public static class TabListener<T extends Fragment> implements
        ActionBar.TabListener {
    private Fragment mFragment;
    private final SherlockFragmentActivity mActivity;
    private final String mTag;
    private final Class<T> mClass;

    /**
     * Constructor used each time a new tab is created.
     * 
     * @param sherlockFragmentActivity
     *            The host Activity, used to instantiate the fragment
     * @param tag
     *            The identifier tag for the fragment
     * @param clz
     *            The fragment's Class, used to instantiate the fragment
     */
    public TabListener(SherlockFragmentActivity sherlockFragmentActivity,
            String tag, Class<T> clz) {
        mActivity = sherlockFragmentActivity;
        mTag = tag;
        mClass = clz;
    }

    /* The following are each of the ActionBar.TabListener callbacks */

    public void onTabSelected(Tab tab, FragmentTransaction ft) {

        mPager.setCurrentItem(tab.getPosition());

    }

    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
    }

    public void onTabReselected(Tab tab, FragmentTransaction ft) {
        // User selected the already selected tab. Usually do nothing.
    }
}

}

and this is the RecipeTabsFragment layout, ingr_tabs.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:tag="ingr_screen"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<android.support.v4.view.ViewPager
    android:id="@+id/pager"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" >
</android.support.v4.view.ViewPager>

Now, for some reason, while being in the RecipeTabsFragment, and leaving the app temporarily (whether exiting to the home menu, or the device goes to sleep mode) and returning to the app, the app crashes and the following exception occurs:

## 08-26 14:39:30.640: E/AndroidRuntime(5520): FATAL EXCEPTION: main
08-26 14:39:30.640: E/AndroidRuntime(5520): java.lang.RuntimeException: Unable to resume activity {development.example.vegancookbook/development.example.vegancookbook.SearchResultActivity}: java.lang.IllegalStateException: Observer android.support.v4.view.ViewPager$PagerObserver@414db9b0 was not registered.
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2456)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2484)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1185)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.os.Handler.dispatchMessage(Handler.java:99)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.os.Looper.loop(Looper.java:137)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.app.ActivityThread.main(ActivityThread.java:4507)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at java.lang.reflect.Method.invokeNative(Native Method)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at java.lang.reflect.Method.invoke(Method.java:511)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at dalvik.system.NativeStart.main(Native Method)
08-26 14:39:30.640: E/AndroidRuntime(5520): Caused by: java.lang.IllegalStateException: Observer android.support.v4.view.ViewPager$PagerObserver@414db9b0 was not registered.
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.database.Observable.unregisterObserver(Observable.java:64)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.support.v4.view.PagerAdapter.unregisterDataSetObserver(PagerAdapter.java:294)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.support.v4.view.ViewPager.setAdapter(ViewPager.java:409)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at development.example.vegancookbook.RecipeTabsFragment.onResume(RecipeTabsFragment.java:196)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.support.v4.app.Fragment.performResume(Fragment.java:1521)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:963)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1460)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:472)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.support.v4.app.FragmentStatePagerAdapter.finishUpdate(FragmentStatePagerAdapter.java:163)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.support.v4.view.ViewPager.setAdapter(ViewPager.java:415)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at development.example.vegancookbook.RecipeTabsFragment.onResume(RecipeTabsFragment.java:196)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.support.v4.app.Fragment.performResume(Fragment.java:1521)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:963)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1086)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.support.v4.app.FragmentManagerImpl.dispatchResume(FragmentManager.java:1887)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.support.v4.app.FragmentActivity.onResumeFragments(FragmentActivity.java:460)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.support.v4.app.FragmentActivity.onPostResume(FragmentActivity.java:449)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at com.actionbarsherlock.app.SherlockFragmentActivity.onPostResume(SherlockFragmentActivity.java:69)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.app.Activity.performResume(Activity.java:4552)
08-26 14:39:30.640: E/AndroidRuntime(5520):     at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2446)
08-26 14:39:30.640: E/AndroidRuntime(5520):     ... 10 more
 ##

does anyone have a clue on whats wrong?? another thing that happens and might be related, is that whilst being in the RecipeTabsFragment, and pressing the back button, I get back to the main activity of my app, and not to the RecipeHeadlinesFragment, though that's the actual place i've been to before the RecipeTabsFragment. Help anyone? EDIT: So I think I found the reason for the main problem I was asking about... when I was in my fragement, I called the getSherlockActivity() to get the FragmentManager instead of calling the fragment's getChildFragmentManager(). problem solved.

like image 750
nitzanwe Avatar asked Aug 26 '13 12:08

nitzanwe


1 Answers

I found what the problem was, and I better answer my question for future generations... I used getSupportFragmentManager() inside the fragment instead of using getChildFragmentManager(). that's all.

like image 71
nitzanwe Avatar answered Sep 19 '22 16:09

nitzanwe