简体   繁体   English

在API中使用静态工厂方法

[英]Use static factory method in API

I am writing a small library that is basically a single custom Activity: 我正在编写一个基本上是单个自定义活动的小型库:

package com.example.android.somelibrary;

public class CustomActivity extends Activity {

    private static final String EXTRA_SOME_THING = "CustomActivity.EXTRA_SOMETHING";

    public static Intent newIntent(Context context, int arg1) {
        Intent intent = new Intent(context, CustomActivity.class);
        intent.putExtra(EXTRA_SOME_THING arg1);
        return intent;
    }

    //... other methods
}

I want users of this library be able to extend this activity: 我希望该库的用户能够扩展此活动:

package com.example.android.myproject;

public class MyCustomActivity extends CustomActivity {
    //... some methods
}

But I want users to be able to rely on my public factory newInstance() : 但我希望用户能够依赖我的公共工厂newInstance()

// start MyCustomActivity
int someInt = 0;
Intent intent = MyCustomActivity.newIntent(getApplicationContext(), someInt);
startActivity(intent);

However, when I try to start an activity this way I get an error: 但是,当我尝试以这种方式启动活动时,出现错误:

android.content.ActivityNotFoundException: Unable to find explicit activity class {com.example.android.myproject/com.example.android.somelibrary.CustomActivity}; have you declared this activity in your AndroidManifest.xml?

I have both activities declared in their respective manifests: CustomActivity in SomeLibrary's manifest, and MyCustomActivity in MyProject's manifest. 我在各自的清单中声明了这两个活动:SomeLibrary清单中的CustomActivity和MyProject清单中的MyCustomActivity。

I get confused because if I change the start activity call everything works fine: 我很困惑,因为如果我更改启动活动调用,一切都会正常进行:

Intent intent = new Intent(context, MyCustomActivity.class);
startActivity(intent);

This makes me think that I've set all of my module dependencies correctly in MyProject . 这使我认为我已经在MyProject正确设置了所有模块依赖项。 Is this just a limit of Java? 这仅仅是Java的限制吗? Can I not call static methods in this way (call parent method on child)? 我不能以这种方式调用静态方法(在子级上调用父方法)吗?

This isn't going to work. 这行不通。

CustomActivity.newIntent() is a static method defined on the CustomActivity class. CustomActivity.newIntent()是在CustomActivity类上定义的静态方法。 That static method returns an Intent that points at CustomActivity.class. 该静态方法返回一个指向CustomActivity.class的Intent。

So when you call MyCustomActivity.newIntent(), what do you get? 因此,当您调用MyCustomActivity.newIntent()时,会得到什么? An intent that points at CustomActivity.class. 指向CustomActivity.class的意图。 Because that's what the method defined in CustomActivity does. 因为这就是CustomActivity中定义的方法。 Firing that intent won't work, because CustomActivity is not defined in your app's manifest. 触发该意图将不起作用,因为在应用的清单中未定义CustomActivity。 And that doesn't matter, anyway, because you want to fire up MyCustomActivity, not CustomActivity. 无论如何,这并不重要,因为您要启动MyCustomActivity,而不是CustomActivity。

What you'd like is a static method that "knows" which class name it is invoked upon. 您想要的是一个静态方法,它“知道”将调用哪个类名。 Unfortunately, this is not possible in Java. 不幸的是,这在Java中是不可能的。

Now, having said that... I'm going to show you how to do it. 现在,这么说...我将向您展示如何做到这一点。 I don't recommend it, though. 不过,我不建议这样做。 (I'll say why a bit later) (稍后再说为什么)

Anyway, like I said: static methods don't know what class they're invoked on. 无论如何,就像我说的那样:静态方法不知道在哪个类上调用它们。 Instance methods do, though. 实例方法可以。 So you could do this: 因此,您可以这样做:

public class CustomActivity extends Activity {

    private static final String EXTRA_SOME_THING = "CustomActivity.EXTRA_SOMETHING";

    public Intent newIntent(Context context, int arg1) {
        Intent intent = new Intent(context, getClass());
        intent.putExtra(EXTRA_SOME_THING arg1);
        return intent;
    }

    //... other methods
}

Same thing, but: 同样的事情,但是:

  • It's an instance method, not a static 这是一个实例方法,而不是静态方法
  • Instead of saying CustomActivity.class (which always points at the CustomActivity class), we say getClass() (which dynamically returns the class of the current instance) 我们说的是getClass()(它动态返回当前实例的类),而不是说CustomActivity.class(它总是指向CustomActivity类)。

Then if we extend CustomActivity with MyCustomActivity, we can create a MyCustomActivity intent like so: 然后,如果我们使用MyCustomActivity扩展CustomActivity,我们可以创建一个MyCustomActivity意图,如下所示:

Intent i = new MyCustomActivity().newIntent(getActivity(), 1);

And it will work. 它将起作用。

Why don't I recommend this: 我为什么不建议这样做:

  • It's ugly and weird. 丑陋又怪异。 If you want to do something and the language makes it ugly and gross, hansolov("Let the language win"); 如果您想做某事并且语言使它变得丑陋和粗糙,则请使用hansolov(“让语言取胜”);
  • The technique it enables is not a good idea. 它启用的技术不是一个好主意。

Let me go on about that a bit. 让我继续讲一下。 Inheritance is little like injection molded plastic: we see this technique used to make tools that we rely on every day, but if we do it at home, we're probably going to make a mess. 继承有点像注塑成型的塑料:我们看到这种技术用来制造我们每天依赖的工具,但是如果我们在家做,那很可能会一团糟。

That's because inheritance is harder than it looks. 那是因为继承比看起来要难。 If three activities all need to use one argument of a specific type, does that mean that they should all be the SAME KIND of activity? 如果三个活动都需要使用一种特定类型的参数,那是否意味着它们都应该成为活动的同一种? Probably not. 可能不是。 I don't have the space or the time to get into it (and others have said it better than I ever could), but suffice to say that there are a lot of gotchas with sharing code in this way. 我没有足够的空间或时间来学习它(其他人说得比以往任何时候都更好),但是足以说有很多这样共享代码的陷阱。

Does that mean that they can share some code in another way? 这是否意味着他们可以通过其他方式共享某些代码? Sure! 当然! Put the implementation in another class and call through in your own static newIntent() method. 将实现放在另一个类中,并使用自己的静态newIntent()方法进行调用。 It's a little more code, but it doesn't have this pitfall. 还有更多代码,但是没有这个陷阱。 So I recommend doing that instead. 因此,我建议改为这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM