开发者

Composition with android.app.Activity

开发者 https://www.devze.com 2023-03-31 23:39 出处:网络
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

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);
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消