【问题标题】:Why extend the Android Application class?为什么要扩展 Android Application 类?
【发布时间】:2013-08-02 20:36:06
【问题描述】:

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

【问题讨论】:

  • 这只是我脑海中的一个想法,但您应该能够覆盖 onCreate 并显示一次性启动屏幕而不是 MainActivity,即第一次启动时的介绍屏幕用户打开应用程序。

标签: android android-application-class


【解决方案1】:

有时您想要存储数据,例如需要从多个活动中访问的全局变量 - 有时在应用程序中的任何地方。在这种情况下,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;
    }
}

更多信息请点击Application Class

【讨论】:

  • 请解释一下,为什么我们需要显式地创建 Application 类的单例对象,据我所知它本身就是一个单例。我们可以制作多个应用程序对象,如果可以,那么如何?后果是什么?请解释一下。
  • 不,可能只有一个应用程序类。 developer.android.com/guide/topics/manifest/…
  • 那为什么我们需要显式维护单例对象呢?操作系统不是为我们维护它吗?实际上,我遇到了一个代码,其中在活动类中创建了一个应用程序对象,而清单中没有提到它。我认为这是错误的,我也很好奇我们为什么要制作静态单例对象。你认为什么是最好的方法。感谢您的回复。
  • 谢谢我在这个链接上找到了我的答案developer.android.com/reference/android/app/Application.html
  • 其中 * singleton* 对象在哪里
【解决方案2】:

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

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

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

您永远不应该在 Application 对象中存储可变的实例数据,因为如果您假设您的数据将保留在那里,您的应用程序将不可避免地在某个时候崩溃并出现 NullPointerException。应用程序对象不能保证永远留在内存中,它会被杀死。与流行的看法相反,该应用程序不会从头开始重新启动。 Android 将创建一个新的 Application 对象并在用户之前所在的位置启动 Activity,从而给人一种应用程序从一开始就没有被杀死的错觉。

【讨论】:

    【解决方案3】:

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

    您可能会发现有用的其他一点是,按照操作顺序,应用程序在任何活动之前首先启动。在此时间范围内,如果您愿意,您可以在第一次活动之前准备任何必要的内务处理。

    2018-10-19 11:31:55.246 8643-8643/: application created
    2018-10-19 11:31:55.630 8643-8643/: activity created
    

    【讨论】:

      【解决方案4】:

      简介:

      1. 如果我们考虑手机中的apk 文件,它由 多个有用的块,例如Activitys、Services 和 其他人。
      2. 这些组件不定期相互通信,并且 不要忘记它们有自己的生命周期。这表明 它们可能在某个时间处于活动状态,而在另一时间处于不活动状态。

      要求:

      1. 有时我们可能需要一个场景,我们需要访问一个 变量及其在整个 Application 中的状态,无论 用户正在使用的Activity
      2. 一个例子是用户可能需要访问一个变量来保存他的 必须跨部门访问的人员信息(例如姓名) Application,
      3. 我们可以使用 SQLite 但创建一个Cursor 并再次关闭它 再次表现不佳,
      4. 我们可以使用Intents 来传递数据,但它很笨拙而且很活跃 根据内存可用性,它本身可能在特定情况下不存在。

      应用类的使用:

      1. 通过Application 访问变量,
      2. 您可以使用Application 启动某些操作,例如分析 等等,因为应用程序类在Activitys 或之前启动 Servicess 正在运行中,
      3. 有一个名为 onConfigurationChanged() 的重写方法,它是 当应用程序配置更改时触发(水平 垂直,反之亦然),
      4. 还有一个名为 onLowMemory() 的事件,当 Android 设备内存不足。

      【讨论】:

      • 在您的需求部分,为什么不使用 SharedPreferences?
      • 在第一个示例中,例如保存个人信息,可以使用 SharedPreferences。但是你在上一部分给出的例子消除了我的疑虑。谢谢!
      【解决方案5】:

      我看到这个问题缺少答案。我扩展 Application 因为我使用 Bill Pugh Singleton 实现 (see reference) 并且我的一些单身人士需要上下文。 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 单例模板可以节省大量时间。

      【讨论】:

        【解决方案6】:

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

        Typeface.createFromAsset()

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

        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。

        【讨论】:

        • 说得好。非常好的分解。
        【解决方案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() 获取它并将其类型转换为应用程序类。据我了解这个概念,应用程序类是由操作系统本身创建的,它应该只有一个由操作系统维护的实例。请解释一下,谢谢。
        • 你是对的。从应用程序中的任何应用程序组件调用 getApplication 会返回作为应用程序的单个应用程序派生实例。这由 Android 框架在内部处理。您需要做的就是将该返回的实例强制转换为扩展 Application 的自定义类。您还需要相应地设置清单,以便 Android 框架使用正确的类来实例化实例。
        【解决方案8】:

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

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

        【讨论】:

          【解决方案9】:

          使用扩展应用程序只是让您的应用程序确保在您的应用程序运行期间执行您想要的任何类型的操作。现在它可能是任何类型的变量,假设如果你想从服务器获取一些数据,那么你可以将你的 asynctask 放在应用程序中,这样它就会每次连续获取,这样你就可以自动获得更新的数据。使用这个链接更多知识......

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

          【讨论】:

          • 它不是线程,因此“用于在整个应用程序运行期间您想要的任何类型的操作。”不是真的。
          【解决方案10】:

          您可以在不创建对象的情况下访问任何类的变量,如果它由应用程序扩展。它们可以被全局调用,并且它们的状态一直保持到应用程序没有被杀死。

          【讨论】:

            【解决方案11】:

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

            我更喜欢使用显式 Intent 将数据从 Activity 传递到 Activity,或者使用 SharedPreferences。还有一些方法可以使用接口将数据从 Fragment 传递到其父 Activity。

            【讨论】:

            • 扩展应用类有很多用途。一个非常有用的方法是捕获应用程序中所有未捕获的异常。所以这是非常方便的东西
            • +1 表示"prefer to pass data from Activity to Activity with explicit Intents, or use SharedPreferences"。我们应该始终尽可能地消除全局状态,并使用标准的 Android 工具进行全局状态管理,而不是静态变量/单例等。
            • 为什么?为 android 在某个时候在不同的进程中运行它们做准备,或者任何应用程序都可以重用任何组件,而这是有意限制的?只传递数据对象而不是序列化它们可以节省 CPU 和内存。为同一设备上的内部进程切换打包东西无论如何都不理想。我真的看不到这样使用意图服务的意义(只需使用新线程执行其他线程)。真的很多让编码人员感到困惑的东西都来自于几乎所有谷歌添加的“助手”都是制作的,就好像活动在不同的计算机上运行一样。
            【解决方案12】:

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

            • 您可以在应用程序启动时添加您需要的内容,方法是在 Application 类中重写 onCreate。

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

            【讨论】:

            • 使用应用程序作为应用程序全局变量的垃圾场是一种很大的代码气味。您应该使用自己的自定义、更具体的类作为单例或使用静态变量来完成此操作。
            • @Austin 为什么会有味道?
            • 是的,为什么有气味?如前所述,Application 类位于层次结构的顶部,我可以打赌我的午餐钱,一个自定义的单例类在它下面。因此,如果迫在眉睫,并且您的手机内存不足,我会说自定义单例是第一个被杀死的,而不是 Application 类(本质上是您的整个应用程序)。
            【解决方案13】:

            Application 类是一个单例,您可以从任何 Activity 或任何其他拥有 Context 对象的地方访问它。

            您还可以获得一点生命周期。

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

            【讨论】:

            • "您还可以获得一点生命周期。"你可能想改写一下。
            • 我的意思是你得到了一些生命周期调用,但没有活动或片段那么多。例如,Application 类没有 onDestroy()。
            • 这个类是自动创建的吗?
            • 是的。只要您在 AndroidManifest.xml 中正确指定它。
            • 不,它不是自动创建的。您必须创建它,然后在清单文件中声明它
            猜你喜欢
            • 2013-09-04
            • 2012-02-05
            • 2016-01-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-09-07
            • 1970-01-01
            相关资源
            最近更新 更多