-1

So, I am writing a navigation part of my app and have dynamically created fragments inside an activity.

I want, when a user hits either the next or previous arrow, for the app to find out what fragment is in the activity and replace it with either the next or previous fragment. In order to do that, I created a switch statement to check on what fragment is being displayed.

I thought that I would be able to do this by using

getSupportFragmentManager().findFragmentById(R.id.activity_public_internet)

but that doesn't seem to work in the switch statement.

So I then tried

getFragmentManager().findFragmentById(R.id.public_internet_intro_fragment).getId()

and that doesn't work either.

Here is the full code. Any help will be fully appreciated. And feel free to tell me if there is a better way to do it.

public void goPrev(View view) {
        switch(getSupportFragmentManager().findFragmentById(R.id.activity_public_internet).getId()) {
            case R.id.public_internet_intro_fragment:
                Intent intent = new Intent(this, LearnActivity.class);
                startActivity(intent);
                break;
            case R.id.public_internet_topic_fragment:
                Fragment introFragment = new PublicInternetIntroFragment();
                FragmentTransaction exampleTransaction = getFragmentManager().beginTransaction();
                exampleTransaction.replace(R.id.activity_public_internet, introFragment);
                exampleTransaction.addToBackStack(null);
                exampleTransaction.commit();
                break;
            case R.id.public_internet_example_fragment:
                Fragment topicFragment = new PublicInternetTopicFragment();
                FragmentTransaction topicTransaction = getFragmentManager().beginTransaction();
                topicTransaction.replace(R.id.activity_public_internet, topicFragment);
                topicTransaction.addToBackStack(null);
                topicTransaction.commit();
                break;
        }
    }

    public void goNext(View view) {
        switch(getFragmentManager().findFragmentById(R.id.public_internet_intro_fragment).getId()) {
            case R.id.public_internet_intro_fragment:
                Fragment topicFragment = new PublicInternetTopicFragment();
                FragmentTransaction topicTransaction = getFragmentManager().beginTransaction();
                topicTransaction.replace(R.id.activity_public_internet, topicFragment);
                topicTransaction.addToBackStack(null);
                topicTransaction.commit();
                break;
            case R.id.public_internet_topic_fragment:
                Fragment exampleFragment = new PublicInternetExampleFragment();
                FragmentTransaction exampleTransaction = getFragmentManager().beginTransaction();
                exampleTransaction.replace(R.id.activity_public_internet, exampleFragment);
                exampleTransaction.addToBackStack(null);
                exampleTransaction.commit();
                break;
            case R.id.public_internet_example_fragment:
                Intent intent = new Intent(this, LearnActivity.class);
                startActivity(intent);
                break;
        }
    }

When checking the error log, a Null Pointer Exception is raised after attempting to invoke int android.app.Fragment.getId()

EDIT: Added PublicInternetActivity.java

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.NavUtils;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;

public class PublicInternetActivity extends ActionBarActivity{
    private static final String tag_public_internet_intro_fragment = "public_internet_intro_fragment";
    private static final String tag_public_internet_topic_fragment = "public_internet_topic_fragment";
    private static final String tag_public_internet_example_fragment = "public_internet_example_fragment";

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

        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        setContentView(R.layout.activity_public_internet);

        introFrag();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu items for use in the action bar
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu_learn, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        if (id == R.id.action_home) {
            goHome();
            return true;
        }
        else {
            return super.onOptionsItemSelected(item);
        }
    }

    public void introFrag() {
        Fragment introFragment = new PublicInternetIntroFragment();
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.replace(R.id.activity_public_internet, introFragment);
        transaction.addToBackStack(null);
        transaction.commit();
    }

    public void goHome() {
        Intent homeIntent = NavUtils.getParentActivityIntent(this);
        NavUtils.navigateUpTo(this, homeIntent);
    }

    public void pushNewFragment( Fragment newFrag, String tag) {
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

        transaction.replace(R.id.activity_public_internet, newFrag, tag);
        transaction.addToBackStack(tag);
        transaction.commit();
    }

    public String getActiveFragmentTag() {
        if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
           return null;
        }
        String tag = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1).getName();
        return tag;
    }

    public void goPrev(View view) {
        switch(getActiveFragmentTag()) {
            case tag_public_internet_intro_fragment:
                Intent intent = new Intent(this, LearnActivity.class);
                startActivity(intent);
                break;
            case tag_public_internet_topic_fragment:
                Fragment introFragment = new PublicInternetIntroFragment();
                pushNewFragment(introFragment, tag_public_internet_intro_fragment);
                break;
            case tag_public_internet_example_fragment:
                Fragment topicFragment = new PublicInternetTopicFragment();
                pushNewFragment(topicFragment, tag_public_internet_topic_fragment);
                break;
        }
    }

    public void goNext(View view) {
        switch(getActiveFragmentTag()) {
            case tag_public_internet_intro_fragment:
                Fragment topicFragment = new PublicInternetTopicFragment();
                pushNewFragment(topicFragment, tag_public_internet_topic_fragment);
                break;
            case tag_public_internet_topic_fragment:
                Fragment exampleFragment = new PublicInternetExampleFragment();
                pushNewFragment(exampleFragment, tag_public_internet_example_fragment);
                break;
            case tag_public_internet_example_fragment:
                Intent intent = new Intent(this, LearnActivity.class);
                startActivity(intent);
                break;
        }
    }
}
OliP
  • 103
  • 3
  • easy way is use fragment with TAG or check these ans: http://stackoverflow.com/q/6750069/1168654 – Dhaval Parmar May 26 '15 at 16:25
  • Looking at the error log, it is a Null Pointer Exception, which says to me that there is not a fragment in the page when the method is run. – OliP May 26 '15 at 16:43

2 Answers2

0

This looks very complicated, I would suggest something more simple.

Use Fragment.instantiate to create a Fragment and replace the current one. If the order of your Fragments is fixed, keep an Array with the name of the class of each Fragment in it (in the good order).

Then, keep a pointer to know where you are in your Array, and each time you go to the next/previous Fragment, increment your pointer accordingly.

This way,you don't have to implement case by case handling, which seems to be very error-prone. You should consider the cases where

pointer == 0 and pointer == length-1.

This way, you can have any number of Fragments the one after the other. Note that however, it only works for a determined order. If you want something more complicated, you should extend the Fragment class and add logic into your subclass.

Gordak
  • 2,060
  • 22
  • 32
0

Try to do it this way:

public void pushNewFragment( Fragment newFrag, String tag) {
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

    transaction.replace(R.id.activity_public_internet, newFrag, tag);
    transaction.addToBackStack(tag);
    transaction.commit();
}

public String getActiveFragmentTag() {
    if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
       return null;
    }
    String tag = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1).getName();
    return tag;
}

public void goPrev(View view) {
    switch(getActiveFragmentTag()) {
        case tag_public_internet_intro_fragment:
            Intent intent = new Intent(this, LearnActivity.class);
            startActivity(intent);
            break;
        case tag_public_internet_topic_fragment:
            Fragment introFragment = new PublicInternetIntroFragment();
            pushNewFragment(introFragment, tag_public_internet_intro_fragment);
            break;
        case tag_public_internet_example_fragment:
            Fragment topicFragment = new PublicInternetTopicFragment();
            pushNewFragment(introFragment, tag_public_internet_topic_fragment);
            break;
    }
}

EDIT

from the documentation:

Get fragments that exist in the activity, with findFragmentById() (for fragments that provide a UI in the activity layout) or findFragmentByTag() (for fragments that do or don't provide a UI).

Normally we use ids for static fragments (embedded in the activity layout and that you don't need to change in runtime). For dynamic Fragments which is your case it's better to use tags.

Best of luck

MAB
  • 953
  • 7
  • 14
  • If you don't want to use a switch over String (introduced in JAVA 1.7) you can change the switch by an if statement – MAB May 26 '15 at 17:25
  • Many thanks. So, feel free to tell me if this is the wrong way of doing this completely. I have those fragments in their own separate fragment xml files so doing it like that won't be right? – OliP May 26 '15 at 18:05
  • Updated the answer to explain the difference between using ids and tags – MAB May 26 '15 at 18:52
  • In this case, the tag_public_internet_intro_fragment etc would need to be a set of variables that I would need to set? – OliP May 26 '15 at 19:56
  • Exactly, the best way to do it I think is to define a final static TAG in each fragment. For example you can replace tag_public_internet_intro_fragment by PublicInternetIntroFragment.TAG – MAB May 26 '15 at 20:09
  • Edited and added the file as it stands now. Still doesn't seem to be working. Error message is: "Attempt to invoke virtual method 'int java.lang.String.hashCode()' on a null object reference" – OliP May 26 '15 at 20:34
  • in the introFrag() method you should do the same as in the switch case: replace by pushnewFragment(). You didn't notice that it's a duplicated code? I suspect it's the source of the null pointer exception, because you add the first fragment without tag and after that you're trying to get it. – MAB May 26 '15 at 21:46
  • That's a good point. I'm an idiot. Thank you very much. It works now! :D – OliP May 28 '15 at 16:29