为什么要扩展Android Application类?


168

扩展Application类可以声明全局变量。还有其他原因吗?


这只是一个想法,但您应该能够覆盖onCreate并显示一个一次性启动屏幕,而不是MainActivity,即用户首次打开该应用程序时的简介屏幕。
btse 2013年

Answers:


29

暂时,我想不出一个真正的场景,在该场景中,扩展Application要么比另一种方法更可取,要么需要完成某件事。如果您有一个昂贵且经常使用的对象,则可以在检测到该对象当前不存在时在IntentService中对其进行初始化。应用程序本身在UI线程上运行,而IntentService在其自己的线程上运行。

我更喜欢使用明确的Intent将数据从Activity传递到Activity,或使用SharedPreferences。还有一些方法可以使用接口将数据从片段传递到其父活动。


39
扩展应用程序类有许多用途。一种非常有用的方法是捕获应用程序中所有未捕获的异常。所以这很方便
png

3
你是怎样做的 ?
serj 2015年

8
为+1 "prefer to pass data from Activity to Activity with explicit Intents, or use SharedPreferences"。我们应该永远消除全球状态,尽我们所能,并使用标准的Android工具,在全球国家管理的,而不是静态瓦尔/单身等
阿列克Karaberov

9
为什么?准备在某个时候以不同的进程或其他方式运行它们,并且每个组件都可以被任何应用重用,从而为android做准备,而这是有意限制的吗?仅传递数据对象而不是序列化它们可以节省CPU和内存。打包用于同一设备内部进程内部切换的东西无论如何都不理想。我真的没看到像这样的intentservice的使用(只是用new做其他线程)。实际上,使编码人员感到困惑的很多东西都来自,几乎所有由google添加的“帮助者”都是按照活动在单独的计算机上运行来制作的。
Lassi Kinnunen

127

介绍:

在此处输入图片说明

  1. 如果我们apk在移动设备中考虑文件,则该文件包含多个有用的块,例如Activity,,Services和其他。
  2. 这些组件不会定期相互通信,并且不会忘记它们具有自己的生命周期。表示它们可能一次处于活动状态,而另一时间处于非活动状态。

要求:

  1. 有时,我们可能需要一种场景,Application无论Activity用户使用什么,都需要访问整个变量及其状态。
  2. 一个例子是,用户可能需要访问一个变量,该变量包含必须在 Application,,
  3. 我们可以使用SQLite,但是一次创建Cursor并关闭它的性能不好,
  4. 我们可以使用Intents传递数据,但它的笨拙和活动本身在某些情况下可能不存在,具体取决于内存的可用性。

应用类别的用途:

  1. 访问整个变量Application
  2. 您可以使用Application来启动诸如分析之类的某些操作。由于应用程序类是在运行Activity或 之前Services运行的,
  3. 有一个称为onConfigurationChanged()的重写方法,该方法在更改应用程序配置时(水平到垂直,反之亦然)触发,
  4. 还有一个称为onLowMemory()的事件,当Android设备内存不足时会触发该事件。

在您的“需求”部分中,为什么不使用SharedPreferences?

在第一个示例中,例如用于保存个人信息,可以使用SharedPreferences。但是您在最后一部分中给出的示例消除了我的怀疑。谢谢!
萨拉·辛格

63

应用程序类是具有应用程序完整生命周期的对象。它是您作为应用程序的最高层。示例可能的用法:

  • 您可以通过覆盖Application类中的onCreate来添加启动应用程序时所需的内容。

  • 存储从活动跳转到活动的全局变量。像Asynctask。

    等等


4
使用Application作为应用程序全局变量的转储场是一个很大的代码味道。您应该使用自己的自定义,更具体的类作为单例或使用静态变量来完成此任务。
奥斯丁

5
@奥斯汀为什么会有气味?
Relm

1
是的,为什么要闻?如前所述,Application类位于层次结构的顶部,我敢打赌,自定义类位于其下方。因此,如果一推再推,而您的手机内存不足,我想说的是自定义单例是第一个被杀死的单例,而不是Application类(本质上是您的整个应用)。
达威

31

有时您想要存储数据,例如需要从多个“活动”中访问的全局变量(有时在应用程序中的任何地方)。在这种情况下,Application对象将为您提供帮助。

例如,如果要获取每个http请求的基本身份验证数据,则可以在应用程序对象中实现身份验证数据的方法。

之后,您可以在以下任何活动中获取用户名和密码:

MyApplication mApplication = (MyApplication)getApplicationContext();
String username = mApplication.getUsername();
String password = mApplication.getPassword();

最后,请记住将Application对象用作单例对象:

 public class MyApplication extends Application {
    private static MyApplication singleton;

    public MyApplication getInstance(){
        return singleton;
    }
    @Override
    public void onCreate() {
        super.onCreate();
        singleton = this;
    }
}

有关更多信息,请单击应用程序类


2
请向我解释一下,据我所知,为什么我们需要显式地使Application类成为单例对象,因为它本身就是单例。我们可以制作多个应用程序对象吗?结果是什么?请解释一下。
Syed Raza Mehdi


那么为什么我们需要显式维护单例对象呢?操作系统不是为我们维护它吗?实际上,我遇到了一个代码,其中在活动类中有一个应用程序对象,清单中没有提到它。我认为这是错误的,我也很好奇为什么我们要制作静态单例对象。您认为最好的方法。感谢回复。
Syed Raza Mehdi

1
谢谢,我在此链接上找到了我的答案developer.android.com/reference/android/app/Application.html
Syed Raza Mehdi

*单例对象在哪里
aNdRO博士17年

8

Application类是一个单例,您可以从任何活动或具有Context对象的任何其他位置访问。

您还将获得一些生命周期。

您可以使用应用程序的onCreate方法实例化昂贵但频繁使用的对象,例如分析助手。然后,您可以在任何地方访问和使用这些对象。


6
“您还将获得生命周期的一点点。” 您可能想重新措辞。
wtsang02

2
我的意思是,您会收到一些生命周期调用,但不如活动或片段那么多。例如,Application类没有onDestroy()。
乔恩·汉考克

该类是自动创建的吗?
Konstantin Konopko 2015年

是。只要您在AndroidManifest.xml中正确指定它即可。
乔恩·汉考克

不,它不会自动创建。您必须先创建它,然后在清单文件中声明
Ojonugwa Jude Ochalifu 2015年

7

最好使用应用程序类。示例:假设您需要在启动完成后重新启动警报管理器。

public class BaseJuiceApplication extends Application implements BootListener {

    public static BaseJuiceApplication instance = null;

    public static Context getInstance() {
        if (null == instance) {
            instance = new BaseJuiceApplication();
        }
        return instance;
    }

    @Override
    public void onCreate() {
        super.onCreate();


    }

    @Override
    public void onBootCompleted(Context context, Intent intent) {
        new PushService().scheduleService(getInstance());
        //startToNotify(context);
    }

我想知道为什么我们需要对应用程序对象进行静态引用,在这里我们可以使用getApplication()获得它,并将其类型转换为应用程序类。据我了解的这一概念,应用程序类是由OS本身构成的,它应该只有一个由OS维护的实例。请解释,谢谢。
Syed Raza Mehdi

没错 从应用程序中的任何应用程序组件调用getApplication都会返回单个应用程序派生实例即您的应用程序。这是由Android框架内部处理的。您需要做的只是将返回的实例转换为扩展Application的自定义类。您还需要相应地设置清单,以便Android框架使用适当的类来实例化实例。
马特·韦尔克

5

不是答案而是观察:请记住,扩展应用程序对象中的数据不应与活动的实例绑定,因为您可能同时运行同一活动的两个实例(一个实例前景,一个不可见)

例如,您通常通过启动器启动活动,然后将其“最小化”。然后,您启动另一个应用程序(例如Tasker),该应用程序将启动您的活动的另一个实例,例如,以便创建快捷方式,因为您的应用程序支持android.intent.action.CREATE_SHORTCUT。如果随后创建了快捷方式,并且该活动的快捷方式创建调用修改了应用程序对象的数据,则在后台运行的活动一旦被带回到前台,将开始使用此修改后的应用程序对象。


4

我看到这个问题缺少答案。我扩展Application是因为我使用Bill Pugh Singleton实现(请参阅参考资料),并且我的某些单例需要上下文。本Application类如下所示:

public class MyApplication extends Application {

    private static final String TAG = MyApplication.class.getSimpleName();

    private static MyApplication sInstance;

    @Contract(pure = true)
    @Nullable
    public static Context getAppContext() {
        return sInstance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate() called");
        sInstance = this;
    }
}

单例看起来像这样:

public class DataManager {

    private static final String TAG = DataManager.class.getSimpleName();

    @Contract(pure = true)
    public static DataManager getInstance() {
        return InstanceHolder.INSTANCE;
    }

    private DataManager() {
        doStuffRequiringContext(MyApplication.getAppContext());
    }

    private static final class InstanceHolder {
        @SuppressLint("StaticFieldLeak")
        private static final DataManager INSTANCE = new DataManager();
    }
}

这样,我不需要每次使用单例时都具有上下文,并且可以用最少的代码来进行惰性同步初始化。

提示:更新Android Studio单例模板可以节省大量时间。


3

我认为您可以将Application类用于很多事情,但是它们都与您在启动任何Activity或Services之前需要做一些事情有关。例如,在我的应用程序中,我使用自定义字体。而不是打电话

Typeface.createFromAsset()

从每个活动中从Assets文件夹中获取我的字体的引用(这很糟糕,因为每次调用该方法时都保留对资产的引用,这会导致内存泄漏),我从onCreate()Application类中的方法执行此操作:

private App appInstance;
Typeface quickSandRegular;
...
public void onCreate() {
    super.onCreate();

    appInstance = this;
    quicksandRegular = Typeface.createFromAsset(getApplicationContext().getAssets(),
                       "fonts/Quicksand-Regular.otf");
   ...
   }

现在,我还有一个定义如下的方法:

public static App getAppInstance() {
    return appInstance;
}

还有这个:

public Typeface getQuickSandRegular() {
    return quicksandRegular;
}

因此,在我的应用程序中的任何地方,我要做的就是:

App.getAppInstance().getQuickSandRegular()

对我来说,Application类的另一种用法是在需要启动连接的活动和服务之前,先检查设备是否已连接到Internet,然后再采取实际行动。


1
说得好。很好分解。
Oluwatobi Adenekan,

3

来源:https : //github.com/codepath/android_guides/wiki/Understanding-the-Android-Application-Class

在许多应用程序中,无需直接使用应用程序类。但是,自定义应用程序类有一些可接受的用法:

  • 创建第一个活动之前需要运行的专门任务
  • 需要在所有组件之间共享的全局初始化(崩溃报告,持久性)
  • 静态方法可轻松访问静态不可变数据,例如共享的网络客户端对象

永远不要将可变实例数据存储在Application对象内部,因为如果您假设数据将保留在其中,则应用程序不可避免地会在某个时刻崩溃,并出现NullPointerException。无法保证应用程序对象永远保留在内存中,它将被杀死。与普遍的看法相反,该应用不会从头开始重启。Android将创建一个新的Application对象,并在用户之前所在的位置开始活动,以使人们产生一种幻想,即该应用程序从未被杀死。


1

您可以访问任何类的变量,而无需创建对象(如果由Application扩展)。可以全局调用它们,并保持其状态,直到不终止应用程序为止。


1

扩展应用程序的使用仅会使您的应用程序在整个应用程序运行期间确保进行任何所需的操作。现在它可以是任何类型的变量,并且假设您要从服务器获取一些数据,则可以将asynctask放入应用程序中,以便每次连续获取,从而可以自动获取更新的数据。.使用此链接了解更多...

http://www.intridea.com/blog/2011/5/24/how-to-use-application-object-of-android


它不是线程,因此“对于在整个应用程序运行期间进行的任何类型的操作”。是不正确的。
Lassi Kinnunen

1

要添加其他说明,您可能希望将变量存储在应用程序范围内,用于任何长时间运行的线程或其他需要绑定到不使用活动(应用程序不是活动)的应用程序的对象。例如无法请求绑定的服务。则首选绑定到应用程序实例。这种方法唯一明显的警告是,对象在应用程序运行期间一直存在,因此需要对内存进行更多的隐式控制,否则您将遇到与内存相关的问题,例如泄漏。

您可能会发现有用的其他事情是,按照操作顺序,应用程序首先在任何活动之前启动。在此时间范围内,您可以根据需要准备在第一次活动之前进行的所有必要的客房清洁。

2018-10-19 11:31:55.246 8643-8643/: application created
2018-10-19 11:31:55.630 8643-8643/: activity created
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.