Quantcast
Channel: Planet Qt
Viewing all 15410 articles
Browse latest View live

Felgo: Release 3.6.0: Modal Dialogs and iOS Storyboard Support for Qt & Felgo

$
0
0

Felgo 3.6.0 adds the new AppModal component to display modal dialogs in your apps. You can use this component for both full-screen and custom-height modal dialogs.
On iOS, you can now use Storyboard files to create your app launch screen. This update also adds new components and several improvements and fixes.


Francesc M. Qt Blog: How to pin tabs in QTabWidget

Latest from LearnPyQt: PyQt5/PySIde2 Book Create GUI Applications with Python & Qt5 (4th Edition) now available

$
0
0

Hello! This morning I released a new update to my PyQt5 book Create GUI Applications, with Python & Qt5. This is an enormous update, expanding it from 258 to 665 pages and adding 211 complete code examples.

To celebrate the milestone the book is available this week with 20% off. Readers get access to all future updates for free, so it's a great time to snap it up!

render_pyqt5_small.png

This is the 4th Edition of the book and adds a number of entirely new chapters including MVC-like model views, SQL database-views, plotting with matplotlib & PyQtGraph, custom widgets & bitmap graphics, concurrent programming with threads and processes and theming Qt applications.

Existing chapters have been expanded with more examples and step-by-step guides to using them. All source code shown in the book is available as standalone, runnable, examples to try out and experiment with.

book-pages.png

Chapters have been updated and expanded with new examples and more detailed explanations and diagrams. Cross-platform screenshots show how your application will look on different systems. Starting from the basic principles of GUI development in Python and building up to more complex topics.

modelviews.png

Learn how to use Qt's MVC-like model views architecture to sync data with widgets, including querying and editing SQL databases from within your applications.

themes.png

Tired of the default application look? Use styles, palettes and Qt Style Sheets to completely customize the look and feel of your applications.

Examples of customised bars.

Discover how to create your own widgets to use in your Qt applications. Starting from the basics of bitmap graphics and building up to a fully-customizable widgets.

concurrent.png

Use threads an processes to perform long-running calculations or communicate with remote services, without locking up your applications. Receive data back from threads and processes and display progress bars. Stop and pause running jobs from your UI.

plotting.png

Visualize data inside your applications, using matplotlib or PyQtGraph. Sync plots with external threads to create live updating dashboards to visualize data in real-time.

There is also a PySide2 edition of the book available, which features largely the same content, with examples converted to "Qt for Python". Purchasing either book gets you access to both editions, including any future updates of either.

Feedback, as always is very welcome!

Get the PyQt5 book
Get the PySide2 book

Francesc M. Qt Blog: New GitQlient v1.1.1 (+ Mac)

$
0
0

There is available a patch for the version 1.1 of GitQlient.

The new patch version solves a problem with new repositories. The problem prevented users to work with repositories that have no commits. That applies to both new repositories (via init new repo) and already created repos that don’t have any commits.

I took advantage of this issue to release also a release for OSX. It’s as functional as I would expect to have it in the next 1.2.0. However, I’d like if people can test it before going into the next release.

The binaries

You can find the binaries for GitQlient v1.1.1 on the release section on the GitHub repo:

New GitQlient v1.1.1 (+ Mac) first appeared on My C++ & Qt blog - Cesc M..

pat26 MARGINALIA blog: Qt & Android: Job Scheduler

$
0
0

Description

This tutorial describes how to schedule tasks in a Qt app for Android using Android's JobScheduler API. If your Android app needs to perform a repetitive task whether the app is active or not, you should consider creating an Android app with a JobService to perform the work.  You can add one or more job services, where each one defines a different task that is performed in the future based upon specified conditions.  The tasks can even survive application restarts and device reboots.


Source code

The following highlights the steps needed to create an Android app using Qt and Android JobScheduling API.  The complete sample app is found in Github at https://github.com/pgulotta/JobServiceExample.

Getting Started 

Create a new Qt Quick empty project naming it JobServiceExample.  The app will link against the Qt Android Extras module, so add this line to the project file:  

   android:QT += androidextras

 

This sample app displays a message box, so you need to add entry to support the QMessageBox class. 

   QT += widgets 


Create Android Package Templates files. This can be easily done with QtCreator. If you are creating the Templates manually and you need assistance, refer to the Qt for Android  documentation. 


Verify the app was generated correctly by building all Android ABI's and deploying your new app onto an  Android device or emulator.  Upon successfully running your new Android app, it's time to make the changes needed to create a job scheduling service. 

 

Update AndroidManifest.xml

In the AndroidManifest.xml, name the package following the normal java package naming conventions. The JobServiceExample package name is com.example.jobserviceexample. The AndroidManifest.xml file should contain an entry similar to this.

  

     xmlns:android="http://schemas.android.com/apk/res/android" 

     android:versionName="100" android:versionCode="100" android:installLocation="auto">


There are several other changes to make to the AndroidManifest.xml and now is as good a time as any.  The job scheduling api requires a minimum android version.  Specify the supported Android sdk, with an entry such as this.

  


In the AndroidManifest.xml file , the JobServiceExample must be declared as a service with the BIND_JOB_SERVICE permission.  The name JobServiceExample is the name of the Java class you will be creating.

  

     android:permission="android.permission.BIND_JOB_SERVICE"/>


Because Android will run the job, per the job's defined schedule, after the system has finished booting, the RECEIVE_BOOT_COMPLETED permission is needed.

  


The sample app scheduled task is to append a line of text composed of a time stamp to a file periodically.  Thus, the permission WRITE_EXTERNAL_STORAGE is required.

  


Please refer to the sample app, if you are unsure as to what the AndroidManifest.xml entries are.


JobScheduler Java API

An Android service is a component that runs in background and has no user interface. The service will continue to run even if the application exits.  The work or task you are scheduling is known as a 'job' and is defined in a Java class which enables Android to perform the work, even when the app is not active. Refer to Android documentation for details. 


Java files belong to the package specified in the AndroidManifest.xml file.  Java files called by Qt application must be placed in a directory which conforms to the path hierarchy defined by the package name.  Create a java class called JobServiceExample.class which extends android.app.job.JobService in the directory ...JobServiceExample/android/src/com/example/jobserviceexample. This Java class is an Android Service that extends the Android JobService class.  Since JobServiceExample class extends the JobService class, a couple of methods must be implemented: onStartJob(), which is called by the system when the job has begun executing, and onStopJob(), which is called by the system if the job is cancelled before finishing. Note, JobServiceExample class runs on the main thread so the task should be run on a  worker thread. 


   @Override

   public boolean onStartJob( JobParameters jobParameters )

  {

     Log.i( TAG, "JobServiceExample.onStartJob : jobParameters.getJobId() = " +

       jobParameters.getJobId() );

     try {

       Thread thread = new Thread( new ExampleWork( this ) );

       thread.start();

       thread.join();

     } catch ( Exception e ) {

       e.printStackTrace();

     }

     return false;  // Returns false from when job has finished. onStopJob will not be invoked

   }


   @Override

   public boolean onStopJob( JobParameters jobParameters )

   {

     // This method is typically not invoked

     Log.i( TAG, "JobServiceExample.onStopJob : jobParameters.getJobId() = " +

       jobParameters.getJobId() );

     return false;  // Returns false to end the job entirely

   }



The class ExampleWork specified above implements Runnable.  For this example, the task is to append a line of text composed of a timestamp to a file.


   @Override

   public void run()

   {

     ...

    doWork( mContext );

     ...

   }

 

public static void doWork( Context context )

 {

  try {

    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    String textToAppend = dateFormat.format(new Date());

    File path = Environment.getExternalStoragePublicDirectory( 

      Environment.DIRECTORY_DOWNLOADS );

    String filename =  path.getAbsolutePath() + File.separatorChar + 

    "JobServiceExampleLog.txt";

    Log.i( TAG, "ExampleWork.doWork path =" + filename + " appending text " + textToAppend);

    BufferedWriter writer = new BufferedWriter(new FileWriter(filename, true));

    writer.newLine();

    writer.write(textToAppend);

    writer.close();

  } catch ( IOException e ) {

    e.printStackTrace();

  }

 }


Schedule a job by using Android's JobScheduler java class. Using this class, Android can efficiently batch your job with other jobs that need network access. JobScheduler can request retries and when needed Android will rescheduled the work; the work is guaranteed.  In the sample project JobServiceExample, the class ExampleJobScheduler illustrates scheduling.  A unit of work is encapsulated by a java JobInfo class specifying the scheduling criteria. The JobInfo.Builder class is used to configure how the scheduled task should run.


   public static void scheduleJob (Context context, int intervalinMS )

  {

     handleJob(context, intervalinMS );

  }

   private static void handleJob (Context context, long intervalinMS)

   {

     ...

     ComponentName serviceComponent = 

     new ComponentName( context, JobServiceExample.class );

     ...

     JobScheduler jobScheduler = context.getSystemService( JobScheduler.class );

     ...

     JobInfo.Builder builder = new JobInfo.Builder( JOB_ID, serviceComponent );

     ...

     builder.setPeriodic( intervalinMS );  // job runs within the intervalinMS; API 21

     builder.setPersisted( true ); // persist this job across device reboots; API 21

     builder.setRequiredNetworkType( JobInfo.NETWORK_TYPE_ANY ); //  API 21

     builder.setRequiresDeviceIdle(false); //  API 21

     int result = jobScheduler.schedule( builder.build() );

     String resultText = ( JobScheduler.RESULT_SUCCESS == result ) ? 

     "successfully" : "failed";

     Log.i ( TAG, "ExampleJobScheduler.handleJob scheduled for intervalinMS of " + 

     intervalinMS + " is "  + resultText );

    ...

  }



QML

In this example app, the QML UI, main.qml,  allows the user to schedule how frequently the task is executed.

  ...

  Button {

   text: qsTr("Apply")

   anchors.horizontalCenter: parent.horizontalCenter

   onClicked: Controller.scheduleJobService(scheduleModelId.

     get(scheduleSelectorId.currentIndex).intervalMS)

   }

   ...



Qt & C++

The FrontController C++ class  exposes the job  scheduling function to the QML interface.


Q_INVOKABLE void scheduleJobService(int intervalinMS);

 ...

   void FrontController::scheduleJobService( int intervalinMS )

   {

     QAndroidJniObject::callStaticMethod

     ( "com/example/jobserviceexample/JobServiceExample","scheduleJobService",

       "(Landroid/content/Context;I)V",

       QtAndroid::androidActivity().object(), intervalinMS);

   }


The Permissions C++ class is called when the application starts for check for and request of needed permissions.

   void Permissions::requestExternalStoragePermission()

   {

     ...

     QtAndroid::PermissionResult request = QtAndroid::checkPermission( 

       "android.permission.WRITE_EXTERNAL_STORAGE" );

     if ( request == QtAndroid::PermissionResult::Denied ) {

       QtAndroid::requestPermissionsSync( QStringList() <<  

       "android.permission.WRITE_EXTERNAL_STORAGE" );

       request = QtAndroid::checkPermission( 

       "android.permission.WRITE_EXTERNAL_STORAGE" );

       if ( request == QtAndroid::PermissionResult::Denied ) {

         mPermissionGranted = false;

         if ( QtAndroid::shouldShowRequestPermissionRationale( 

         "android.permission.READ_EXTERNAL_STORAGE" ) ) {

            QAndroidJniObject 

            ( "com/example/jobserviceexample/ShowPermissionRationale",

            "(Landroid/app/Activity;)V",

            QtAndroid::androidActivity().object());

            QAndroidJniEnvironment env;

            if ( env->ExceptionCheck() ) {

              env->ExceptionClear();

        }

     }

   } else {

    mPermissionGranted = true;

   }

  } else {

   mPermissionGranted = true;

  }

  ...

}


The communication between the C++ Qt/QML and Java needs to be specified  in main.cpp.

   #include

   #include "frontcontroller.h"

   #include "permissions.hpp"


   int main(int argc, char *argv[])

   {

   ...

   QQmlApplicationEngine engine;

   FrontController frontController{app.parent()};

   engine.rootContext()->setContextProperty( "Controller", &frontController );

   const QUrl url(QStringLiteral("qrc:/main.qml"));

   QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,

    &app, [url](QObject *obj, const QUrl &objUrl) {

      if (!obj && url == objUrl)

        QCoreApplication::exit(-1);

     }, Qt::QueuedConnection); engine.load(url);


    Permissions permissions;

    permissions.requestExternalStoragePermission();

    if ( permissions.getPermissionResult() ) {

      qInfo( "Successfully obtained required permissions, app starting" );

      return app.exec();

    } else {

      qWarning( "Failed to obtain required permissions, app terminating" );

    }

  }


Test it Out

Upon successfully building the app, run the JobServiceExample app and schedule a job by selecting the "Recording interval" and pressing "Apply".  Quit the app.  On Android, the file /storage/emulated/0/Download/JobServiceExampleLog.txt will be updated at the specified time interval.  Upon rebooting the Android, you can observe, the file /storage/emulated/0/Download/JobServiceExampleLog.txt will continue to be updated at the specified time interval.  The sample app, JobServiceExample, logs often to help you follow along.

     



Conclusion

To code a job scheduler in your QT Android application, there are many small steps, but this is true with all Android app development.  Android job scheduling  is a powerful, performant, robust feature that enables the Android OS to shoulder the burden of executing tasks based upon specific conditions. It's a nice tool to have in your toolbox.






KDAB on Qt: Heaptrack Version 1.2.0 Released

$
0
0

We have just released version 1.2.0 of Heaptrack, the fast heap memory profiler for C++/Linux applications.

A bit of Background

The Heaptrack fast heap memory profiler allows you to track all heap memory allocations at run-time. Afterwards, you can use the accompanying GUI tool to find optimization opportunities in your code by analyzing the recorded profiling data.

If you’d like to read a bit more about Heaptrack, you can do so here.

Overview of 1.2.0 Release

The Heaptrack version 1.2.0 release is a maintenance release and brings a couple of important bug fixes and improvements. As a result of these bugfixes and improvements, Heaptrack is more stable and error resistant while recording data.

Additionally, due to some minor tweaks to the graphical analysis tool, it is more efficient to use. You’ll find that the performance of the analysis step is slightly improved too.

Finally, an important bug in the data-diffing algorithm is fixed, which should make that feature more useful again.

You can find a list of the commits that went into this release here.

How to get it?

You can download sources for Heaptrack from the KDE mirrors. Alternatively, wait for your distribution to pick up this release and then it will provide a binary package for you to install.

 

If you need help with using Heaptrack, or with performance tooling in general, do note that we also offer a training course on debugging and profiling Qt applications. KDAB also offers on-site workshops and mentoring to aid you in optimizing your C++ application performance. I’ll gladly teach you how to use Heaptrack effectively!

The post Heaptrack Version 1.2.0 Released appeared first on KDAB.

KDAB on Qt: Containers whitepaper

$
0
0

Software developed for embedded applications is often distinct from its desktop and cloud cousins due to the constraints of embedded hardware and the integration of non-mainstream devices. But problem-solving technologies developed in other places tend to migrate to embedded systems once the hardware catches up. Containers are one of these – and they’re not just for cloud developers anymore…

The post Containers whitepaper appeared first on KDAB.

KDAB on Qt: Choosing a CPU

$
0
0

When building an embedded systems product, among your earliest decisions is the choice of hardware. More specifically, on what CPU should you base your design? Today’s system-on-chip processors have a huge array of resources to contribute to your solution: multiple cores and on-board DSPs, graphics engines and display controllers, peripheral support and connectivity interfaces, and more. Because a new hardware platform entails a costly investment it makes sense to consider your hardware selection wisely. This whitepaper examines the i.MX 8 processor to see if it makes sense for your project.

The post Choosing a CPU appeared first on KDAB.


KDAB on Qt: Choosing a Software Stack

$
0
0

One of the most difficult choices when starting any new software project is selecting the programming language and framework your team will use to create it. Should you stick with Qt because it’s the best tool for the job? Should you switch to something using web- based technology or designed explicitly for mobile? This whitepaper can help you structure your decision-making process around the software options that might be the best fit for you and give you the necessary guidance to head in that direction.

The post Choosing a Software Stack appeared first on KDAB.

KDAB on Qt: Meeting C++ 2020

$
0
0

 

 

The Schedule, Talks and Speakers are now online for this ever growing ‘partly virtual ‘event for the European C++ community. KDAB is proud to be a Gold sponsor this year.

This year’s online conference features eleven talks in one track. On November 14th you can see a talk from KDAB’s Marc Mutz: Partially-Formed Objects For Fun And Profit.

While the details are on the website, here’s the full talks list and their speakers:

  • How C++20 changes the way we write code by Timur Doumler
  • Hidden Features and Traps of C++ Move Semantics by Nicolai Josuttis
  • C++ Concepts vs Rust Traits vs Haskell Typeclasses vs Swift Protocols by Conor Hoekstra
  • Template Shenanigans: Testing, debugging and benchmarking template code by Jonathan O’Connor
  • Building an Intuition for Composition by Sy Brand
  • The Static Initialization Order Fiasco – How to Properly Initialize Global State by Jonathan Müller
  • Lambdas, uses and abuses by Dawid Zalewski
  • OO Considered Harmful by Phil Nash
  • Calling Functions: A Tutorial by Klaus Iglberger
  • 40 Years Of Evolution from Functions to Coroutines by Rainer Grimm
  • Partially-Formed Objects For Fun And Profit by Marc Mutz

Meeting C++ 2020 is planned as a hybrid event, where a few folks can attend in Berlin according to the COVID-19 rules. The larger part of the conference will happen online.

Sign up for Meeting C++ 2020.

Find out more about Meeting C++ and how it’s grown, from Jens Weller, who created the event.

About KDAB

If you like this blog and want to read similar articles, consider subscribing via our RSS feed.

Subscribe to KDAB TV for similar informative short video content.

KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.

The post Meeting C++ 2020 appeared first on KDAB.

KDAB on Qt: Hotspot Version 1.3.0 Released

$
0
0

We are pleased to announce a new release of our Hotspot Linux perf performance analysis GUI, Hotspot version 1.3.0!

Hotspot is a replacement for perf reportthat takes a perf.data file, parses and evaluates its contents, and then displays the result in a graphical form. You can read a bit more about Hotspot here: https://www.kdab.com/hotspot-gui-linux-perf-profiler/

Overview of New Features and Improvements

With this new release, Hotspot has become much faster at interpreting data for large, complex applications; analyzing perf.data files for firefox,e.g. with its monster libxul, is now magnitudes faster than it was in the previous releases of Hotspot.

On top of that, we now properly support analysis of zstd compressed data files, for example, those obtained via perf record -z. This support feature easily reduces the size of the perf.data files by one to two orders of magnitude.

The timeline has been improved and now shows tick marks on the time axes, as well as smart time unit prefixes when zoomed in:

Hotspot version 1.3.0

You can view the original request for this feature here: https://github.com/KDAB/hotspot/pull/238

Additionally, hotspot can now demangle rustc symbols:

You can view the original request for this feature here: https://github.com/KDAB/hotspot/issues/239

Finally, we’ve updated the perfparser submodule with a plethora of fixes and improvements. Better support for fork-based parallelism is among the numerous improvements that we’ve made.

How can you get the new release?

You can download Hotspot version 1.3.0 from KDAB’s GitHub at this link, where you can also find the list of fixes in this version: https://github.com/KDAB/hotspot/releases/tag/v1.3.0

Try it out and let us know what you think! Please report issues on GitHub, but we are also open to any kind of feedback through the comment field below. If you want to learn more about perf and hotspot, also consider attending one of our Linux specific profiling and debugging training classes.

The post Hotspot Version 1.3.0 Released appeared first on KDAB.

The Qt Company Blog: Qt 5.15.1 Released

$
0
0

We have released Qt 5.15.1, the first patch release of Qt 5.15 LTS. As a patch release, Qt 5.15.1 does not add any new functionality but provides many bug fixes and other improvements.

The Qt Company Blog: Qt Design Studio 1.6 released

$
0
0

We are happy to announce the final release of Qt Design Studio 1.6

The Qt Company Blog: Qt for Python 5.15.1 Released!

$
0
0

We are happy to announce that 5.15.1 is finally out!

On this release, we managed to fix some old bugs like adding __ne__ and __eq__ operators by default to every PySide type, and improve the compatibility that we had with Nuitka, a Python compiler. Still there are some corner cases that needs to be improved, but we are looking forward to being fully compatible. Additionally, there were some corner cases regarding our threading story that are now solved.

To improve our QML interaction, we now have a new type, QEnum, which can be used as a decorator for Qt objects and Python Enum-based classes, this was required for some changes that will be available in Qt for Python 6.0, so stay tuned!

There were a couple of missing bindings that somehow, we didn’t catch before, and we also include a new tutorial on widget styling, and a couple of new examples around regular expressions and custom C++ widgets with Shiboken.

From the features planned for Qt 6.0, we wanted to go ahead and incorporate one of those for 5.15 Python users, and that’s why we made an exception and we are including in this release the first __feature__ functionality, snake_case.  This will enable you to use snake_case functions for all the Qt API, for example label.set_text(“...”), instead of label.setText(“...”).
You can check one of our previous tutorials, and see how the code looks like with this feature on the Expenses tutorial.

Additionally, some issues regarding C++ language support that manifested in Qt 6.0 were fixed in shiboken.

We are focusing most of our efforts into the next major release but we will keep an eye on JIRA to see if you find any issue with the 5.15.1 release.

For more details on the release, check all the changes included here: https://code.qt.io/cgit/pyside/pyside-setup.git/tree/dist/changes-5.15.1?h=5.15

We appreciate the external contributions we have been getting 🎉 and we encourage you to drop by our many community platforms, to get involve in the Qt for Python development!

The Qt Company Blog: Development hosts and targets in Qt 6.0

$
0
0

There are significant updates in Qt 6 that also impact the underlying way in which the development host OS and target OS are supported. The most significant changes affecting development hosts and targets include how Qt integrates to the graphics system (Blog: Technical vision for Qt 6), the C++ minimum version update from C++ 11 to C++ 17, and the transition from QMake to CMake. We have also taken the opportunity to clean up and reorganize quite a few OS-specific bits (Blog: Qt 6.0 feature freeze).


The Qt Company Blog: Qbs 1.17.0 released

The Qt Company Blog: Qt for MCUs 1.4 released

$
0
0

A new release of Qt for MCUs is available as of today in the Qt Installer. If you are new to Qt, you can try it out here. Version 1.4 introduces a new font engine that can display a wider range of text without bloating the memory footprint. The release also include API improvements and bug fixes, enhancing usability and stability.

pat26 MARGINALIA blog: Qt & Android: Job Scheduler

$
0
0

Description

This tutorial describes how to schedule tasks in a Qt app for Android using Android's JobScheduler API. If your Android app needs to perform a repetitive task whether the app is active or not, you should consider creating an Android app with a JobService to perform the work.  You can add one or more job services, where each one defines a different task that is performed in the future based upon specified conditions.  The tasks can even survive application restarts and device reboots.


Source code

The following highlights the steps needed to create an Android app using Qt and Android JobScheduling API.  The complete sample app is found in Github at https://github.com/pgulotta/JobServiceExample.

Getting Started 

Create a new Qt Quick empty project naming it JobServiceExample.  The app will link against the Qt Android Extras module, so add this line to the project file:  

   android:QT += androidextras

 

This sample app displays a message box, so you need to add entry to support the QMessageBox class. 

   QT += widgets 


Create Android Package Templates files. This can be easily done with QtCreator. If you are creating the Templates manually and you need assistance, refer to the Qt for Android  documentation. 


Verify the app was generated correctly by building all Android ABI's and deploying your new app onto an  Android device or emulator.  Upon successfully running your new Android app, it's time to make the changes needed to create a job scheduling service. 

 

Update AndroidManifest.xml

In the AndroidManifest.xml, name the package following the normal java package naming conventions. The JobServiceExample package name is com.example.jobserviceexample. The AndroidManifest.xml file should contain an entry similar to this.

  

     xmlns:android="http://schemas.android.com/apk/res/android" 

     android:versionName="100" android:versionCode="100" android:installLocation="auto">


There are several other changes to make to the AndroidManifest.xml and now is as good a time as any.  The job scheduling api requires a minimum android version.  Specify the supported Android sdk, with an entry such as this.

  


In the AndroidManifest.xml file , the JobServiceExample must be declared as a service with the BIND_JOB_SERVICE permission.  The name JobServiceExample is the name of the Java class you will be creating.

  

     android:permission="android.permission.BIND_JOB_SERVICE"/>


Because Android will run the job, per the job's defined schedule, after the system has finished booting, the RECEIVE_BOOT_COMPLETED permission is needed.

  


The sample app scheduled task is to append a line of text composed of a time stamp to a file periodically.  Thus, the permission WRITE_EXTERNAL_STORAGE is required.

  


Please refer to the sample app, if you are unsure as to what the AndroidManifest.xml entries are.


JobScheduler Java API

An Android service is a component that runs in background and has no user interface. The service will continue to run even if the application exits.  The work or task you are scheduling is known as a 'job' and is defined in a Java class which enables Android to perform the work, even when the app is not active. Refer to Android documentation for details. 


Java files belong to the package specified in the AndroidManifest.xml file.  Java files called by Qt application must be placed in a directory which conforms to the path hierarchy defined by the package name.  Create a java class called JobServiceExample.class which extends android.app.job.JobService in the directory ...JobServiceExample/android/src/com/example/jobserviceexample. This Java class is an Android Service that extends the Android JobService class.  Since JobServiceExample class extends the JobService class, a couple of methods must be implemented: onStartJob(), which is called by the system when the job has begun executing, and onStopJob(), which is called by the system if the job is cancelled before finishing. Note, JobServiceExample class runs on the main thread so the task should be run on a  worker thread. 


   @Override

   public boolean onStartJob( JobParameters jobParameters )

  {

     Log.i( TAG, "JobServiceExample.onStartJob : jobParameters.getJobId() = " +

       jobParameters.getJobId() );

     try {

       Thread thread = new Thread( new ExampleWork( this ) );

       thread.start();

       thread.join();

     } catch ( Exception e ) {

       e.printStackTrace();

     }

     return false;  // Returns false from when job has finished. onStopJob will not be invoked

   }


   @Override

   public boolean onStopJob( JobParameters jobParameters )

   {

     // This method is typically not invoked

     Log.i( TAG, "JobServiceExample.onStopJob : jobParameters.getJobId() = " +

       jobParameters.getJobId() );

     return false;  // Returns false to end the job entirely

   }



The class ExampleWork specified above implements Runnable.  For this example, the task is to append a line of text composed of a timestamp to a file.


   @Override

   public void run()

   {

     ...

    doWork( mContext );

     ...

   }

 

public static void doWork( Context context )

 {

  try {

    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    String textToAppend = dateFormat.format(new Date());

    File path = Environment.getExternalStoragePublicDirectory( 

      Environment.DIRECTORY_DOWNLOADS );

    String filename =  path.getAbsolutePath() + File.separatorChar + 

    "JobServiceExampleLog.txt";

    Log.i( TAG, "ExampleWork.doWork path =" + filename + " appending text " + textToAppend);

    BufferedWriter writer = new BufferedWriter(new FileWriter(filename, true));

    writer.newLine();

    writer.write(textToAppend);

    writer.close();

  } catch ( IOException e ) {

    e.printStackTrace();

  }

 }


Schedule a job by using Android's JobScheduler java class. Using this class, Android can efficiently batch your job with other jobs that need network access. JobScheduler can request retries and when needed Android will rescheduled the work; the work is guaranteed.  In the sample project JobServiceExample, the class ExampleJobScheduler illustrates scheduling.  A unit of work is encapsulated by a java JobInfo class specifying the scheduling criteria. The JobInfo.Builder class is used to configure how the scheduled task should run.


   public static void scheduleJob (Context context, int intervalinMS )

  {

     handleJob(context, intervalinMS );

  }

   private static void handleJob (Context context, long intervalinMS)

   {

     ...

     ComponentName serviceComponent = 

     new ComponentName( context, JobServiceExample.class );

     ...

     JobScheduler jobScheduler = context.getSystemService( JobScheduler.class );

     ...

     JobInfo.Builder builder = new JobInfo.Builder( JOB_ID, serviceComponent );

     ...

     builder.setPeriodic( intervalinMS );  // job runs within the intervalinMS; API 21

     builder.setPersisted( true ); // persist this job across device reboots; API 21

     builder.setRequiredNetworkType( JobInfo.NETWORK_TYPE_ANY ); //  API 21

     builder.setRequiresDeviceIdle(false); //  API 21

     int result = jobScheduler.schedule( builder.build() );

     String resultText = ( JobScheduler.RESULT_SUCCESS == result ) ? 

     "successfully" : "failed";

     Log.i ( TAG, "ExampleJobScheduler.handleJob scheduled for intervalinMS of " + 

     intervalinMS + " is "  + resultText );

    ...

  }



QML

In this example app, the QML UI, main.qml,  allows the user to schedule how frequently the task is executed.

  ...

  Button {

   text: qsTr("Apply")

   anchors.horizontalCenter: parent.horizontalCenter

   onClicked: Controller.scheduleJobService(scheduleModelId.

     get(scheduleSelectorId.currentIndex).intervalMS)

   }

   ...



Qt & C++

The FrontController C++ class  exposes the job  scheduling function to the QML interface.


Q_INVOKABLE void scheduleJobService(int intervalinMS);

 ...

   void FrontController::scheduleJobService( int intervalinMS )

   {

     QAndroidJniObject::callStaticMethod

     ( "com/example/jobserviceexample/JobServiceExample","scheduleJobService",

       "(Landroid/content/Context;I)V",

       QtAndroid::androidActivity().object(), intervalinMS);

   }


The Permissions C++ class is called when the application starts for check for and request of needed permissions.

   void Permissions::requestExternalStoragePermission()

   {

     ...

     QtAndroid::PermissionResult request = QtAndroid::checkPermission( 

       "android.permission.WRITE_EXTERNAL_STORAGE" );

     if ( request == QtAndroid::PermissionResult::Denied ) {

       QtAndroid::requestPermissionsSync( QStringList() <<  

       "android.permission.WRITE_EXTERNAL_STORAGE" );

       request = QtAndroid::checkPermission( 

       "android.permission.WRITE_EXTERNAL_STORAGE" );

       if ( request == QtAndroid::PermissionResult::Denied ) {

         mPermissionGranted = false;

         if ( QtAndroid::shouldShowRequestPermissionRationale( 

         "android.permission.READ_EXTERNAL_STORAGE" ) ) {

            QAndroidJniObject 

            ( "com/example/jobserviceexample/ShowPermissionRationale",

            "(Landroid/app/Activity;)V",

            QtAndroid::androidActivity().object());

            QAndroidJniEnvironment env;

            if ( env->ExceptionCheck() ) {

              env->ExceptionClear();

        }

     }

   } else {

    mPermissionGranted = true;

   }

  } else {

   mPermissionGranted = true;

  }

  ...

}


The communication between the C++ Qt/QML and Java needs to be specified  in main.cpp.

   #include

   #include "frontcontroller.h"

   #include "permissions.hpp"


   int main(int argc, char *argv[])

   {

   ...

   QQmlApplicationEngine engine;

   FrontController frontController{app.parent()};

   engine.rootContext()->setContextProperty( "Controller", &frontController );

   const QUrl url(QStringLiteral("qrc:/main.qml"));

   QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,

    &app, [url](QObject *obj, const QUrl &objUrl) {

      if (!obj && url == objUrl)

        QCoreApplication::exit(-1);

     }, Qt::QueuedConnection); engine.load(url);


    Permissions permissions;

    permissions.requestExternalStoragePermission();

    if ( permissions.getPermissionResult() ) {

      qInfo( "Successfully obtained required permissions, app starting" );

      return app.exec();

    } else {

      qWarning( "Failed to obtain required permissions, app terminating" );

    }

  }


Test it Out

Upon successfully building the app, run the JobServiceExample app and schedule a job by selecting the "Recording interval" and pressing "Apply".  Quit the app.  On Android, the file /storage/emulated/0/Download/JobServiceExampleLog.txt will be updated at the specified time interval.  Upon rebooting the Android, you can observe, the file /storage/emulated/0/Download/JobServiceExampleLog.txt will continue to be updated at the specified time interval.  The sample app, JobServiceExample, logs often to help you follow along.

     



Conclusion

To code a job scheduler in your QT Android application, there are many small steps, but this is true with all Android app development.  Android job scheduling  is a powerful, performant, robust feature that enables the Android OS to shoulder the burden of executing tasks based upon specific conditions. It's a nice tool to have in your toolbox.






The Qt Company Blog: Qt for MCUs 1.4 released

$
0
0

A new release of Qt for MCUs is available as of today in the Qt Installer. If you are new to Qt, you can try it out here. Version 1.4 introduces a new font engine that can display a wider range of text without bloating the memory footprint. The release also includes API improvements and bug fixes, enhancing usability and stability.

The Qt Company Blog: Asynchronous APIs in Qt 6

$
0
0

As readers may already know, Qt provides several multithreading constructs (threads, mutexes, wait conditions, etc.), and higher level APIs like QThreadPool, Qt Concurrent and other related classes. Those who are not familiar with Qt threading support yet or want to learn more, can participate in our online training sessions (available here and here). In this post we will concentrate on higher level asynchronous APIs and changes introduced in Qt 6.

Viewing all 15410 articles
Browse latest View live