© EVILEG 2015-2018
Рекомендует хостинг
TIMEWEB

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

Qt, JAVA, Android, QML

Любопытства ради решил сравнить два варианта написания приложений под Андроид. Когда-то давно начинал заниматься программированием под Андроид на 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 мБ и в итоге размеры сравняются.

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

Комментарии

Комментарии

Только авторизованные пользователи могут оставлять комментарии.
Пожалуйста, Авторизуйтесь или Зарегистрируйтесь
24 сентября 2018 г. 17:42
edorofeeva

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

  • Результат 100баллов,
  • Очки рейтинга10
24 сентября 2018 г. 17:37
edorofeeva

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

  • Результат 66баллов,
  • Очки рейтинга-1
23 сентября 2018 г. 14:38
No Names

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

  • Результат 60баллов,
  • Очки рейтинга-1
Последние комментарии
24 сентября 2018 г. 15:09
Евгений Легоцкой

Qt Linux - Урок 001. Автозапуск Qt приложения под Linux

А вот здесь у меня есть пример использования supervisor. https://evileg.com/ru/post/3/ Вся статья вам там не интересна, интересен только шаг с настройкой supervisor. Он получается ...
24 сентября 2018 г. 15:00
avovana

Qt Linux - Урок 001. Автозапуск Qt приложения под Linux

Не могли бы дать ссылку на пример? Какое-то рабочее использование. Т.е. у меня есть Qt Gui App, которое я бы хотел запускать при старте системы и в случае, если оно грохнется. Если о чем Вы го...
24 сентября 2018 г. 14:55
Евгений Легоцкой

Qt Linux - Урок 001. Автозапуск Qt приложения под Linux

Если честно, то я не уверен, что это вообще можно реализовать через *.desktop файл. Я сделал предположение на основе того, что вы сказали про *.desktop и рестарт. Все варианты, котор...
24 сентября 2018 г. 14:47
avovana

Qt Linux - Урок 001. Автозапуск Qt приложения под Linux

Просто сейчас правлю сам файл example.desktop. Пытаюсь понять какую пару key=value мне нужно дописать.
24 сентября 2018 г. 14:42
Евгений Легоцкой

Qt Linux - Урок 001. Автозапуск Qt приложения под Linux

Ну я имел ввиду, что дописать в коде вот сюда то, о чём вы говорили про рестарт QString autorunContent("[Desktop Entry]\n" "Type=Application\n" ...
Сейчас обсуждают на форуме
24 сентября 2018 г. 16:47
Евгений_Канусовский@1981

Чтение файлов в python

Добрый вечер Евгений и форумчане! Столкнулся с проблемой чтения файлов в python: файлы с обычным текстом в формате las и txt читаются, например: ~Version information VERS.          ...
24 сентября 2018 г. 13:29
Евгений Легоцкой

Трансляция видео с помощью VLC по RTP

Добрый день! Я не сталкивался, но предположу, что нужно настроить Input Codec в VLC. В настройках есть секция Input Codec, возможно, что там установлено низкое разрешение. ...
21 сентября 2018 г. 8:25
Евгений Легоцкой

Прокси-модель, содержащая на 1 столбец больше, чем модель-источник.

Попробуйте ещё PySide 2 - это официально поддерживаемый пакет привязок Python к Qt, возможно, что там не будет таких проблем.
20 сентября 2018 г. 20:06
Евгений Легоцкой

Qt Installer Framework

Добрый день. Зачем собирать Qt Installer Framework-то из исходников? Я ещё понимаю Qt собирают из исходников статически (хотя тоже считаю по большей части бесполезной тратой времени),...
Присоединяйтесь к нам в социальных сетях