1

如何从 c++ qt 5.6 android 调用 getMemoryInfo?我不确定在调用 getSystemService api 时从 java/lang/Object 转换为 android/app/ActivityManager,但顺便说一句,我得到了有效的 QAndroidJniObject。到目前为止,这是我的代码。

osinfoandroid.h

#ifndef OSINFOANDROID_H
#define OSINFOANDROID_H

#include <QObject>

class OsInfoAndroid : public QObject {
    Q_OBJECT
public:
explicit OsInfoAndroid(QObject *parent = 0);
~OsInfoAndroid();
public Q_SLOTS:

void testgetmeminfo();
};

#endif  // OSINFOANDROID_H

osinfoandroid.cpp

#include "osinfoandroid.h"
#include <QDebug>
#include <QtAndroidExtras/QtAndroidExtras>

OsInfoAndroid::OsInfoAndroid(QObject *parent) : QObject(parent) {}

OsInfoAndroid::~OsInfoAndroid() {}

void OsInfoAndroid::testgetmeminfo() {
QAndroidJniObject cntact_service = QAndroidJniObject::getStaticObjectField(
  "android/content/Context", "ACTIVITY_SERVICE", "Ljava/lang/String;");
if (cntact_service.isValid()) {
qDebug() << Q_FUNC_INFO << "ACTIVITY_SERVICE OK GOT INTERNAL STRING";
} else {
    qDebug() << Q_FUNC_INFO << "ACTIVITY_SERVICE sad got nothing :(";
}
QAndroidJniObject ctx = QtAndroid::androidActivity().callObjectMethod(
  "getApplicationContext", "()Landroid/content/Context;");
if (ctx.isValid()) {
qDebug() << Q_FUNC_INFO << "got valid context";

} else {
    qDebug() << Q_FUNC_INFO << "sad got nothing context";
}

QAndroidJniObject actmgr = ctx.callObjectMethod(
  "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;",
  cntact_service.object<jstring>());
if (actmgr.isValid()) {
qDebug() << Q_FUNC_INFO << "ok got ActivityManager";
QAndroidJniObject meminfo("android/app/ActivityManager$MemoryInfo");
if(!meminfo.isValid ()){
    qDebug()<<Q_FUNC_INFO<<"SAD GOT INVALID MemoryInfo!";
    return;
}
qDebug()<<Q_FUNC_INFO<<"ok got valid MemoryInfo";
//CRASH HERE
QAndroidJniObject voidmeminfo = actmgr.callObjectMethod(
    "getMemoryInfo", "(Landroid/app/ActivityManager$MemoryInfo;)V",
    meminfo.object<jclass>());
    if (voidmeminfo.isValid()) {
  qDebug() << Q_FUNC_INFO << "OK CALLING getMemoryInfo FROM CPP SUKSES!! ";
    } else {
  qDebug() << Q_FUNC_INFO << "calling from c++ failed!!";
    }

 }
}

主文件

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <osinfoandroid.h>

int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);

QQmlApplicationEngine engine;
OsInfoAndroid osinfo;
engine.rootContext ()->setContextProperty ("osinfo",&osinfo);
engine.load(QUrl(QLatin1String("qrc:/main.qml")));

return app.exec();
}

AndroidManifest.xml

<?xml version="1.0"?>
<manifest package="org.androidgetmeminfocrash" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" android:versionCode="1" android:installLocation="auto">
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="-- %%INSERT_APP_NAME%% --">
    <activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="-- %%INSERT_APP_NAME%% --" android:screenOrientation="unspecified" android:launchMode="singleTop">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
        <meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
        <meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
        <meta-data android:name="android.app.repository" android:value="default"/>
        <meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
        <meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
        <!-- Deploy Qt libs as part of package -->
        <meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
        <meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
        <meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
        <!-- Run with local libs -->
        <meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
        <meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
        <meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/>
        <meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
        <meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
        <!--  Messages maps -->
        <meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
        <meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
        <meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
        <!--  Messages maps -->

        <!-- Splash screen -->
        <!--
        <meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/>
        -->
        <!-- Splash screen -->

        <!-- Background running -->
        <!-- Warning: changing this value to true may cause unexpected crashes if the
                      application still try to draw after
                      "applicationStateChanged(Qt::ApplicationSuspended)"
                      signal is sent! -->
        <meta-data android:name="android.app.background_running" android:value="false"/>
        <!-- Background running -->

        <!-- auto screen scale factor -->
        <meta-data android:name="android.app.auto_screen_scale_factor" android:value="false"/>
        <!-- auto screen scale factor -->
    </activity>
</application>
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="14"/>
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>

<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
     Remove the comment if you do not require these default permissions. -->
<!-- %%INSERT_PERMISSIONS -->

<!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
     Remove the comment if you do not require these default features. -->
<!-- %%INSERT_FEATURES -->

<uses-permission android:name="android.permission.GET_TASKS"/>
    <uses-permission android:name="android.permission.HARDWARE_TEST"/>
</manifest>

整个项目可以在这里下载

好的,问题看起来像是来自这里的调用

QAndroidJniObject voidmeminfo = actmgr.callObjectMethod(
    "getMemoryInfo", "(Landroid/app/ActivityManager$MemoryInfo;)V",
    meminfo.object<jclass>());

可以改为

actmgr.callMethod<void>(
    "getMemoryInfo", "(Landroid/app/ActivityManager$MemoryInfo;)V",
    meminfo.object<jobject>());

但我不确定是否使用 meminfo.object< jobject >()); 哪个是正确的 或 meminfo.object< jclass >());

所以,我想获取android MemoryInfo 的availMem 对象字段,在调用getMemoryInfo 函数后我添加了这段代码

QAndroidJniObject availmem=meminfo.getObjectField("availMem","J");
if(!availmem.isValid ()){
   qDebug() << Q_FUNC_INFO << "calling from c++ failed!!";
}

但是,上面的代码仍然在 android jelly bean 上产生明显的崩溃,任何指针?

我想要实现的等效java代码是这样的

ActivityManager activityManager = (ActivityManager)     context.getSystemService(ACTIVITY_SERVICE);
MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);

Log.i(TAG, " memoryInfo.availMem " + memoryInfo.availMem + "\n" );

所以现在,我正在使用基于上述项目源下载的具有完整 java 主体功能的第二种方法。尝试从 c++ 发出有效的活动上下文并在 java 中调用普通的静态方法。然后创建文件夹 com -> getmemorycrash 文件夹。我创建了一个java文件OsInfo.java,所以现在我的getmemoryinfo.pro变成了这样

QT += qml quick androidextras

CONFIG += c++11

SOURCES += main.cpp osinfoandroid.cpp
HEADERS +=  osinfoandroid.h

RESOURCES += qml.qrc

# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

DISTFILES += \
    android/AndroidManifest.xml \
    android/gradle/wrapper/gradle-wrapper.jar \
    android/gradlew \
    android/res/values/libs.xml \
    android/build.gradle \
    android/gradle/wrapper/gradle-wrapper.properties \
    android/gradlew.bat \
    android/src/com/getmemorycrash/OsInfo.java
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android

OsInfo.java

package com.getmemorycrash;
import java.lang.Object;
import android.app.ActivityManager;
import android.app.ActivityManager.MemoryInfo;
import java.lang.String;
import android.content.Context;
import android.util.Log;

public class OsInfo {
 static long getMemavail(Context context ){
    Log.d("ada","executing getMemavail");
    ActivityManager activityManager = (ActivityManager)     context.getSystemService(Context.ACTIVITY_SERVICE);
    MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
    activityManager.getMemoryInfo(memoryInfo);

    Log.i("mydebug", " memoryInfo.availMem " + memoryInfo.availMem + "\n" );
    return memoryInfo.availMem;
 }
}

最后的osinfoandroid.cpp,我添加了testgetmeminfomethod2函数,代码如下

void OsInfoAndroid::testgetmeminfomethod2()
{
QAndroidJniObject ctx = QtAndroid::androidActivity().callObjectMethod(
    "getApplicationContext", "()Landroid/content/Context;");
if (ctx.isValid()) {
  qDebug() << Q_FUNC_INFO << "got valid context";
} else {
  qDebug() << Q_FUNC_INFO << "sad got nothing context";
}
//crash here
QAndroidJniObject availmem=QAndroidJniObject::callStaticObjectMethod("com/getmemorycrash/OsInfo",
                                                                     "getMemavail",
                                                                     "(Landroid/content/Context;)J",
                                                                     ctx.object<jclass>());
if(!availmem.isValid ()){
      qDebug() << Q_FUNC_INFO << "calling from c++ failed!!";
 }  
}

所以,我的问题是为什么上面的函数又变成了段错误?java 代码一直执行到 Log android 函数,然后在返回时立即发生崩溃?

谢谢

4

1 回答 1

0

好的,我最终可以解决这个问题,如果它们是原始类型,则获取公共成员 java 类变量的正确函数,我可以使用第一种方法而不是在 QAndroidJniObject 上中继基于上述情况

jlong availmem=meminfo.getField<jlong>("availMem");
于 2017-02-19T12:25:06.050 回答