Evgenii Legotckoi
Evgenii Legotckoi19 февраля 2018 г. 2:13

Android. Java vs Qt QML - Урок 001. Hello World

Любопытства ради решил сравнить два варианта написания приложений под Андроид. Когда-то давно начинал заниматься программированием под Андроид на Java, но со временем перешёл на разработку Desktop приложений на Qt QML. Но теперь вновь решил освежить в памяти некоторые аспекты, чтобы убедиться, что Qt QML мне нравится больше.

Сразу приведу результат двух Hello world`ов. Они конечно не будут на 100 процентов идентичны, но должны быть похожи. В качестве базового примера возьму пустую Activity, которая создаётся в Android Studio.

Первый образец - это Hello World на Java


Второй образец - это Hello World на Qt QML

В целом приложения похожи, внешний вид отличается немного в рендеринге текста, и в дополнительных эффектах. Во всём остальном приложения одинаковы.

Для начала начнём с Java приложения.

Создание проекта на Java

Шаг 1 - Выберем пункт создания нового проекта

Шаг 2 - Дадим имя проекту

Шаг 3 - выберем минимальный SDK проекта

Шаг 4 - Выберем тип проекта - Empty Activity

Шаг 5 - Настройка Activity

На этом проект будет создан и настроен. Можете сразу его собрать и запустить на вашем смартфоне. У меня размер apk , собранного в режиме debug составил пример 170 кБ.

Программный код

А теперь посмотрим на то, как выглядит программный код приложения.

Приложения под Андроид на Java состоят из двух программных слоёв:

  1. XML-вёрстка приложения, которая представляет из себя интерфейс приложения, его внешний вид. И фактически не имеющей никакой программной логики.
  2. Java-логика приложения, которая отвечает именно за всю бизнес логику и т.д. и т.п.

XML-вёрстка

Если честно... вёрстка всех свойств внешнего вида приложения в XML выглядит довольно громоздкой, при том, что нет возможности использовать какую-либо программную логику для изменения свойств или текста элементов. Эта сложность особенно будет очевидна, когда приходится описывать достаточно сложные интерфейсы.

Но посмотрим xml-код.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.evileg.javahelloworld.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

Здесь можно увидеть, что описывается само поле с текстом Hello World, но не описывается внешний вид ToolBar

а, который присутствует в активити. Наличие ToolBar
а определяется через контекст активити, которая используется в данном случае.

А вот в QML к сожалению придётся писать такой же ToolBar самостоятельно.

Java код

Сам Java код будет небольшим, поскольку понадобится только переопределить метод создания Activity , чтобы установить в неё XML вёрстку. А то, какую Активити стартовать, определяем в AndroidManifest.xml .

package com.evileg.javahelloworld;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

Создание проекта на Qt QML

Шаг 1 - Выберем создание пустого Qt Quick приложения

Шаг 2 - Выберем место расположения проекта

Шаг 3 - выбор системы сборки

Можете выбрать по вкусу:

  • qmake
  • cmake
  • qbs

Не знаете, что выбрать, выбирайте qmake

Шаг 4 - Выбор версии библиотеки Qt

Выбирайте последнюю стабильную версию (она должны быть у вас установлена)

Шаг 5 - Выбор комплекта сборки

Вот чем мне нравится Qt, так это тем, что приложения на QML, можно собирать как под Desktop, так и под Android устройства. То есть, если вы не тестируете платформозависимый функционал, то можно смело собирать под десктоп и вести всё тестирование на вашем ПК и только периодически проверять, как приложение работает на Android устройстве.

Шаг 6 - Выбор системы контроля версий

Для Hello World`а нам не понадобится система контроля версий.

Программный код

Проекты на Qt QML как правило состоят из двух программных слоёв, как и в случае с Java.

  • C++ слой - на нём может быть написана основная бизнес-логика, сложные расчёты, работа с сетью и т.д.
  • QML слой - на нём реализуется внешний вид приложения, а также некоторая логика, впрочем ничто не мешает реализовать всю бизнес-логику на QML, если приложение и возможности буду позволять. Также QML достаточно хорошо поддерживает JavaScript, на котором и будет реализовываться эта логика.

То есть в некоторых случаях ничто не мешает вообще не использовать C++.

main.cpp

Данный файл создаётся по умолчанию. В данном случае мы запускаем движок QML и отрисовываем содержимое main.qml файла.

#include <QGuiApplication>
#include <QQmlApplicationEngine>

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

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

QMLHelloWorld.pro

Проектный файл Qt, в нём прописываются все ресурсы, а также исходные файлы проекта с настройками сборки. Он также необходимы здесь помимо файла AndroidManifest.xml

QT += quick
CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += main.cpp

RESOURCES += qml.qrc \
    images.qrc

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

# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_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_PACKAGE_SOURCE_DIR = $$PWD/android

main.qml

А вот и самое интересное. В этом файле понадобится создать не только текст HelloWorld, но и создать ToolBar с иконкой и именем программы. Иконку я взял из проекта на Java и добавил её в ресурсы проекта на Qt QML.

import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.3
import QtQuick.Controls.Material 2.1

ApplicationWindow {
    visible: true
    width: 360
    height: 520
    title: qsTr("Hello World")

    header: ToolBar {
        height: 48

        Rectangle {
            anchors.fill: parent
            color: "#080808"

            Image {
                id: ico
                height: 36
                width: 36
                anchors {
                    left: parent.left
                    leftMargin: 10
                    top: parent.top
                    topMargin: 6
                }
                source: "qrc:/images/ic_launcher.png"
            }


            Text {
                anchors {
                    verticalCenter: parent.verticalCenter
                    left: ico.right
                    leftMargin: 4
                }

                text: qsTr("QmlHelloWorld")
                font.pixelSize: 18
                color: "white"
            }
        }
    }

    Label {
        anchors.centerIn: parent
        text: qsTr("Hello World!")
        font.pixelSize: 14
    }
}

Кода получилось однозначно больше, чем в файле вёрстки XML для приложения на Java. Но давайте разберёмся. Так получилось потому, что в Qt QML изначально нет никаких Активити. Вообще работа всего приложения происходит в одной единственной активити, и нет никакой необходимости переключаться между этими активити. Сделать поведение программы, подобное смене Активити, можно с помощью Loader, StackView, SwipeView и многих других компонентов. А здесь используется компонент окна, который имеет место для размещения ToolBar

а, нужно всего лишь написать вёрстку данного ToolBar
а

Так вот, если бы подобный ToolBar присутствовал изначально, то написание текста Hello World оказалось бы менее громоздким, чем в случае с Java. То есть было бы таким

import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Controls 2.3
import QtQuick.Controls.Material 2.1

ApplicationWindow {
    visible: true
    width: 360
    height: 520

    Label {
        anchors.centerIn: parent
        text: qsTr("Hello World!")
        font.pixelSize: 14
    }
}

Против этого в XML

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.evileg.javahelloworld.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

И если честно, вариант с QML выглядит более читаемым.

Система сборки и AndroidManifest.xml

Система сборки в обоих случаях использовалась Gradle.

Что касается AndroidManifest.xml, то в случае с Java никаких дополнительных манипуляций не производилось. Тогда как в случае с Qt понадобилось добавить иконки запуска. О работе с AndroidManifest.xml в Qt можно почитать подробнее в этой статье .

Заключение

В обоих случаях можно получить два одинаковых приложения, а вот в нюансах разработки можно будет определиться, что и кому будет удобнее.

Оба варианта предлагают работать в двух слоях

  • Java + XML
  • QML + C++

Но в случае с QML/C++ всю логику можно написать только на QML, а в первом случае в XML можно написать только вёрстку.

Первоначальный Hello World будет написан достаточно быстро на Java. Достаточно будет только создать проект, а чтобы получить подобный результат на Qt QML, то придётся ещё немного кода написать. Однако, в ряде случаев придётся писать значительно меньше кода на QML, чем на Java/XML.

Из минусов Qt я бы сразу отметил то, что есть платформозависимые моменты, которые всё равно придётся решать через Java, например события от ОС Android. Однако... также некоторые проблемные части проекта решают через C++, в проекте на Java, поэтому тут скорее будет паритет.

Из плюсов Qt отметил бы то, что в последних версиях они поддерживают Material Design , что также облегчит разработку приложения, когда дизайнера нет как такового в проекте.

Размер собранного APK, здесь конечно выигрывает Java. В debug режиме выходной APK с Java вышел всего 170 кБ, тогда как APK от Qt вышел 10 мБ, в релиз сборке размер APK Qt будет примерно 5-6 мБ, но я бы не назвал это настолько критичным, поскольку многие крупные приложения в Google Play весят 40-60 мБ и в итоге размеры сравняются.

Остальные аспекты рассмотрим в следующих статьях.

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

ГВ
  • 16 ноября 2019 г. 16:16

Разрешите узнать, как вы получили qt+qml приложение размером в 10мб(даже релизных). Дело в том, что пустое приложение, хоть и со стек вью, обходится мне на все 40мб пространства. Или же вы воспользовались ministro? Спасибо за ответ!

Добрый день. На тот момент ничего не использовал дополнительно и никаких специальных настроек не делал. Просто собрал и получилось 10 мб.

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
SH
  • Sak Hax
  • 25 апреля 2024 г. 14:00

C++ - Тест 001. Первая программа и типы данных

  • Результат:33баллов,
  • Очки рейтинга-10
г
  • ги
  • 23 апреля 2024 г. 15:51

C++ - Тест 005. Структуры и Классы

  • Результат:41баллов,
  • Очки рейтинга-8
l
  • laei
  • 23 апреля 2024 г. 9:19

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:10баллов,
  • Очки рейтинга-10
Последние комментарии
k
kmssr8 февраля 2024 г. 18:43
Qt Linux - Урок 001. Автозапуск Qt приложения под Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий Кононенко5 февраля 2024 г. 1:50
Qt WinAPI - Урок 007. Работаем с ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25 декабря 2023 г. 10:30
Boost - статическая линковка в CMake проекте под Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJo25 декабря 2023 г. 8:38
Boost - статическая линковка в CMake проекте под Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
Gvozdik18 декабря 2023 г. 21:01
Qt/C++ - Урок 056. Подключение библиотеки Boost в Qt для компиляторов MinGW и MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Сейчас обсуждают на форуме
G
Gar22 апреля 2024 г. 5:46
Clipboard Как скопировать окно целиком в clipb?
DA
Dr Gangil Academics20 апреля 2024 г. 7:45
Unlock Your Aesthetic Potential: Explore MSC in Facial Aesthetics and Cosmetology in India Embark on a transformative journey with an msc in facial aesthetics and cosmetology in india . Delve into the intricate world of beauty and rejuvenation, guided by expert faculty and …
a
a_vlasov14 апреля 2024 г. 6:41
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
Павел Дорофеев
Павел Дорофеев14 апреля 2024 г. 2:35
QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
f
fastrex4 апреля 2024 г. 4:47
Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…

Следите за нами в социальных сетях