未调用静态对象的Android ctor

Posted

技术标签:

【中文标题】未调用静态对象的Android ctor【英文标题】:Android ctor for static object not called 【发布时间】:2016-12-26 16:39:41 【问题描述】:

主要使用 Qt 和 QML 编写一个 android 应用程序,我正在尝试遵循 example for sending notifications。当我运行示例时,事情按预期工作,但是当我将几乎相同的代码放入我的应用程序时,它不会为其中一个静态对象调用 ctor,因此事情会失败。这是我的 Java 代码:

package com.me.myApp;

import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.util.Log;

public class NotificationClient extends org.qtproject.qt5.android.bindings.QtActivity 
    private static final String TAG = "myApp::NotificationClient";
    private static NotificationManager m_notificationManager;
    private static Notification.Builder m_builder;
    private static NotificationClient m_instance;

    public NotificationClient() 
        Log.d(TAG, "Doing ctor");
        m_instance = this;
    

    public static void notify(String s) 
        Log.d(TAG, "Doing the update thing");
        if(m_instance == null) 
            Log.d(TAG, "I have a null instance");
        
        try 
            if (m_notificationManager == null) 
                m_notificationManager = (NotificationManager)m_instance.getSystemService(Context.NOTIFICATION_SERVICE);
                m_builder = new Notification.Builder(m_instance);
//              m_builder.setSmallIcon(R.drawable.icon);
                m_builder.setContentTitle("A message from Qt!");
            

            m_builder.setContentText(s);
            m_notificationManager.notify(1, m_builder.build());
        
        catch (Exception ex) 
            Log.d(TAG, "Notify error: " + ex.toString());
        
    

查看日志文件,它进入了notify() 函数,但m_instancenull,因为从未调用过NotificationClient ctor。

什么会导致这种情况发生?

【问题讨论】:

【参考方案1】:

Android Qt 应用程序是一个薄 Java 层的组合,它在启动时调用打包为动态 so 库的 Qt 应用程序。更多详细信息可以在 Vatra 先生 @KDAB 举办的精彩系列文章的 first 博客文章中找到。

Java 层恰好是主要活动以及一些实用程序类,可在Qt code base 中找到。

当创建一个新的 Android 项目时,Qt Creator 会自动生成一个manifest 文件,该文件使用 Qt 中可用的默认类。只要您使用默认设置,一切正常。

在您的情况下,您必须扩展默认的主要活动以添加您的自定义 Java 代码,导致主要活动的新名称 (NotificationClient)。然而,清单指向(仍然)可用的基类,即您的清单中有:

android:name="org.qtproject.qt5.android.bindings.QtActivity"

在这种情况下,超类 ctor 被调用,因此 static 变量未分配有效值,从而导致 nullPointerException 问题。在清单中设置正确的新主要活动可以解决问题:

android:name="com.me.myApp.NotificationClient"

我建议您仔细阅读上面链接的博客文章系列,因为它们可以轻松理解 Android Qt 项目中的 Java C++ 交互。

【讨论】:

【参考方案2】:

m_instance(不遵循 Java 命名约定)仅在 NotificationClient 构造函数中初始化,但它是 static 成员。除此之外,这意味着每个实例初始化都会不可预测地改变该值,构造函数永远不会在您的代码中实际调用。一个类型的静态成员不会神奇地调用它的构造函数;它只有在代码要求时才会被构造。

您永远不应该假设某事会以某种方式发生,您应该通过研究文档知道会发生什么。 https://docs.oracle.com/javase/tutorial/java/javaOO/objectcreation.html https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html

如果没有显式初始化,成员值将保持其默认值;对于您的NotificationClient 成员,该值为null

【讨论】:

我的代码几乎一字不差地取自 qt 示例。再次查看他们的示例,我没有看到 java NotificationClient 对象的任何显式初始化。根据您的描述,示例编写不正确,它的工作原理只是一个意外?

以上是关于未调用静态对象的Android ctor的主要内容,如果未能解决你的问题,请参考以下文章

android 内存泄漏出现的情况

Android NDK开发之Jni调用Java对象

自动对象和静态局部对象

在 C++17 中在对象的生命周期之外调用非静态成员函数

Xposed怎样hook 静态变量的调用

Unity中调用Android jar包或arr包方法