FragmentManager and FragmentTransaction - abstract classes?


#1

I am going through my notes and got stuck when I got to the part [color=#FF0000]Adding a UI Fragment to the FragmentManager[/color].

First, there’s the code to get the FragmentManager:

Then there’s the code that gets a FragmentTransaction and calls the add() and commit() methods:

fm.beginTransaction() .add(R.id.fragmentContainer, fragment) .commit();

When I look up these two classes in the developer.android.com site’s documentation, they are both abstract classes with abstract methods, but neither has a class that extends them (no “Known Direct Subclasses”).

So, how can the above code return an instance of either class? Are there undocumented (secret) classes that extend them?

Thank you!


#2

There are!

If you find this question interesting, it is worth taking a second to download the source for the latest version of android: http://source.android.com/. Once you have it, you can spelunk and find interesting things all day. FragmentManager’s secret implementation isn’t one of them, though - it’s FragmentManagerImpl, or something boring along those lines.

FragmentTransaction is interesting, though, because its implementation is named BackStackRecord. Which means that the FragmentTransaction object you construct is the exact same object used to keep track of your FragmentManager’s private back stack of transactions.


#3

I’m still kind of confused about this. How are you able to return a FragmentManager object when calling getSupportFragmentManager() if the class is abstract?
Also, beginTransaction(), add(…), and commit() are all abstract. Doesn’t that mean the implementation of those methods aren’t complete? How are you able to call these methods?
Thanks


#4

Under the hood, there is a concrete implementation. You can see this for yourself. Try adding the following line to your code:

Log.i(TAG, "Implementation class for FragmentManager: " + getSupportFragmentManager().getClass().getName()); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); Log.i(TAG, "Implementation class for FragmentTransaction: " + transaction.getClass().getName());


#5

I think the concrete implementation of FragmentManager is designed to the private inner class of it…


#6

Ok thanks! That makes more sense. What’s the point then of listing them as abstract in Android documentation?


#7

I think …
FragmentManager(FM) is controller to manage Fragment’s Back Stack mechanism associated with FragmentTransaction(FT).
And only one FM instance is needed per fragment instance like Singletone.
And FM’s instantiation have to be done by that mechanism associated with the lifecycle of FM.
And it is needed to hide and encapsulate the FM/FT’s logic.

   Those above are the reason of that FM & FT is Abstract class and their concrete implementation is private (member) inner class.
   And also maybe Android team's Design decision. it is related to Design Patterns too.

#8

I was actually wondering if the instructions using the abstract classes were some kind of convenience instructions that look like Java instructions but were really some kind of link/call to the Android OS (kernel?). My imagination got away from me.

I never saw anything like this in Oracle’s Java documentation (yet anyway). They document the final classes they use for things.

And with no JavaDoc, we get no help with intellisense either. As far as we know we are calling the abstract method of an abstract class. :open_mouth:

So for me, my OCD nature got restless, but not enough to make me want to read through the source code, which would just cause information overload at this point.


#9

There’s nothing magical going on with the abstract class - it’s plain old Java. Remember that the entire purpose of an abstract class or an interface is to allow for you to use a very general type, even if that general type has no concrete implementation. Let’s say that you’re writing a Priest class that can take confessional:

public class Priest { public void takeConfession(Parishioner p) { Log.i(TAG, "Parishioner confessed his sins: " + p.getConfession() + "; five hundred hail maries!"); } }

Now, say that you have a guy named Fred Jenkins. We’ll represent him with a class, FredJenkins. FredJenkins is a Parishioner, so he can confess his sins:

public class FredJenkins extends Parishioner { public String getConfession() { return "I stole my dog's chew toy!"; } }

Fred Jenkins is a real person, which means you can have an instance of FredJenkins. You can’t have an instance of Parishioner, though, because a Parishioner is a general idea:

public abstract class Parishioner { public abstract String getConfession(); }

Of course, there’s nothing saying that FredJenkins has to be a public class. When you’re writing your Church class, FredJenkins could be entirely private:

[code]public class Church {
private class FredJenkins extends Parishioner {
public String getConfession() {
return “I stole my dog’s chew toy!”;
}
}

public void performConfessional() {
    Parishioner parishioner = new FredJenkins();
    Priest priest = new Priest();
    priest.takeConfession(parishioner);
}

}[/code]

In this case, the Priest class can’t see FredJenkins at all - just like how you can’t see the concrete implementation of FragmentManager or FragmentTransaction. Under the hood, though, it works exactly the same as if FredJenkins were public.

Now, how can you call a method on a class you can’t see? Now you’re getting into dynamic dispatch. And the end of this post. :slight_smile: