Composition with android.app.Activity
The source of wisdom "Effective Java 2nd" says "Favor composition over inheritance" (item 16). Now when it comes to Android Activities, it's simple to extends from one but you break encapsulation and the code may break when the superclass is modified. I tried to compose . Here is the code of the component Activity:
public class SimpleActivity extends Activity{
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView textview = new TextView(this);
textview.setText("This is the Artists tab");
setContentView(textview);
}
}
Here is the开发者_高级运维 composed. For each Activity's lifecycle methods, I call the forward methods.
public class ComposedActivity extends Activity {
private SimpleActivity act;
public ComposedActivity(){
act = new SimpleActivity();
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
act.onCreate(savedInstanceState);
}
}
But the app keeps crashing caused by: java.lang.NullPointerException. What am I doing wrong ? Just asking out of curiosity. What do you recommend to expand an Activity without inheritance ?
You can't really have an activity inside another activity. If you want to use composition for Android components, have a look at fragments.
You can use composition without using fragments simply by factoring your logic into plain Java classes (POJOs) that are not Android components. If they need access to an activity, you can pass a references to the target activity in the constructor. Or better yet, have your activities implement some interface have them hold a reference to it, not to concrete activities.
You have a NullPointerException
because SimpleActivity.onCreate()
is called directly by ComposedActivity
while it is supposed to be called thru the use of an Intent
. So when Activity
, superclass of SimpleActivity
, tries to retrieve the Intent
that was used to activate it, it finds null
and crashes as this is unexpected.
On top of this ComposedActivity
extends Activity
but you didn't call super.onCreate()
from ComposedActivity.onCreate()
. This normally leads the following exception to be thrown:
android.app.SuperNotCalledException:
Activity did not call through to super.onCreate()
But reading your question, this is probably by mistake that ComposedActivity
extends Activity
. The way I understood the question, ComposedActivity
should not inherit from Activity
but delegate all the Activity
stuff to SimpleActivity
.
Anyway, and despite the source of wisdom that Effective Java is, another source of wisdom promotes the inheritance from Activity
as a best practice. More seriously, even if the code we find in tutorials in sometimes questionable, I think inheriting from Activity
is from far the best way to implement an Activity
: this was designed that way by Android.
I wrote a library supporting composition for Activities and Fragments. https://github.com/passsy/CompositeAndroid
You have to extend a CompositeActivity
and than you're able to add plugins which have the same methods to override like the Activity itself.
Example
public class MainActivity extends CompositeActivity {
public MainActivity() {
addPlugin(new DevOptionsPlugin());
}
}
The Plugin adds a item to the options menu and handles the clicks
public class DevOptionsPlugin extends ActivityPlugin {
public static final String DEVELOPER_OPTIONS_TEXT = "Developer options";
@Override
public boolean onCreateOptionsMenu(final Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(DEVELOPER_OPTIONS_TEXT);
return true;
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
if (DEVELOPER_OPTIONS_TEXT.equals(item.getTitle())) {
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse("mycompany://appname/devoptions"));
try {
// note: simply calling startActivity(intent); is not allowed because the call order
// would be different. The code before super.startActivity in this plugin would be executed
// first before a plugin added later and is more specialized.
getActivity().startActivity(intent);
} catch (ActivityNotFoundException e) {
Toast.makeText(getActivity(), "Couldn't open Activity", Toast.LENGTH_SHORT).show();
}
// not calling super!!!
return true;
}
return super.onOptionsItemSelected(item);
}
}
精彩评论