Tutorial: Data Sources for Android¶
In this tutorial you learn how to start developing a data source for Kanzi applications for Android. You learn how to:
Create a data source using Kanzi Java API.
Use Android APIs to back the data source.
Ensure compatibility with Kanzi Studio Preview where the Android APIs are not available.
This tutorial assumes that you are familiar with developing Android applications, Java programming language, and that you understand the basics of working with Kanzi Studio. The best entry points for getting familiar with Kanzi Studio are:
Before you start this tutorial, make sure that you have your Kanzi development environment for Android set up. For developing application logic with Kanzi Engine for Android, you need:
Android Studio 4.1.3 or newer
You can download and install Android Studio from here.
Android Gradle plugin 4.1.3 or lower
Gradle 6.7.1 or lower
64-bit JDK 8 (1.8.0) or newer
We recommend using the JDK that is bundled with the Android Studio installation.
CMake 3.5.1 or newer
Android API level:
Kanzi Android framework (droidfw) requires Android API level 26 (Android version 8.0.0) or newer.
Kanzi application framework (appfw) requires Android API level 21 (Android version 5.0) or newer.
Java language version:
Kanzi Android framework (droidfw) requires Java 8 (1.8) or higher.
Kanzi application framework (appfw) requires Java 7 (1.7) or higher.
See Requirements for Android application development with Kanzi.
Assets for the tutorial¶
You can find the completed application of this tutorial in the <KanziWorkspace>/Tutorials/Android data source/Completed
directory.
Create a project in Kanzi Studio¶
In this section you create a Kanzi application with an empty data source by creating a project in Kanzi Studio.
To create a project in Kanzi Studio:
In Kanzi Studio create a project and in the New Project window set:
Name to Android data source
Template to Android application with Java plugin
Android application with Java plugin template creates a Kanzi Studio project with a Kanzi Android framework-based application that contains a Kanzi Engine Java plugin.
Use the Kanzi Android framework (droidfw) when you want to create an application for the Android platform, and you intend to use Android APIs and services extensively.
Kanzi Android framework (droidfw) is a framework dedicated for developing Kanzi applications for Android. It exposes the Kanzi Java API, which allows you to write application and plugin code entirely in Java or Kotlin. You do not need to write any C++ or JNI code, but you can still use native Kanzi plugins. Kanzi Android framework (droidfw) provides strong integration with the Android UI, including support for multiple simultaneous Kanzi-based Views and flexible composition of Kanzi and Android UI elements.
In Android Studio open the
Android data source/Application/configs/platforms/android_gradle
project.
Configure one-way data source¶
In this section you create a widget that shows the battery level of the Android device.
To create the battery level widget:
In Android Studio:
In
androiddatasourceplugin
>java
>com.rightware.kanzi.androiddatasourceplugin
in theAndroidDataSourceDataSource
class:Add a constant that defines the name of the battery level data object.
In the
initialize()
method, replace the existing data source setupwith
To build the Kanzi Engine plugin JAR used by Kanzi Studio, in the Gradle tool window in androiddatasource > androiddatasourceplugin > Tasks > kanzi run exportJarDebug or exportJarRelease.
In Kanzi Studio in the Node Tree delete the Viewport 2D node.
You can delete the Viewport 2D node because you do not create any 3D content in this tutorial.
In the Rootpage create a Flow Layout 2D node and name it Controls.
In the Properties add and set the Horizontal Alignment and Vertical Alignment properties to Center.
In the Node Tree in the Controls node create an Empty Node 2D node, name it Battery Widget, and in the Properties add and set:
Layout Width to 150
Layout Height to 200
From the Asset Packages > Factory Content drag the Progress Indicator to the Battery Widget node in the Node Tree.
In the Node Tree select the Progress Indicator prefab placeholder and in the Properties add and set:
Layout Width to 150
Layout Height to 150
Ring Thickness to 0.3
In the Node Tree in the Battery Widget node create a Text Block 2D node and in the Properties add and set:
Horizontal Alignment to Center
Vertical Alignment to Bottom
Text to Battery
In the Library > Kanzi Engine Plugins right-click the AndroidDataSource plugin and select Update Kanzi Engine Plugin.
This way you update the plugin and take into use the changes that you made in the Android Studio plugin project.
In the Window main menu select Data Sources.
Use the Data Sources window to create, set, and delete the data sources in your project, and to connect data objects from a data source to nodes and resources in your project.
Add the data source to the Kanzi Studio project:
In the Data Sources window select Create Data Source and set:
Name to Android data source
Data Source Type to AndroidDataSourceDataSource
You can see the BatteryLevel data object in the Data Sources window.
In the Node Tree select the RootPage node, in the Properties add the Data Context > Data Context property, and set it to Android data source.
By setting the Data Context property you tell your application from which data source it receives data. When you set the Data Context property for a node, all its child nodes inherit the value of the Data Context property. If you want to use a different data context for one of the child nodes, add the Data Context property to that node and set it to the data context you want to use.
In the Node Tree select the Progress Indicator node, in the Properties click + Add Binding, and in the Binding Editor set:
Property to Progress
Expression to
In Kanzi Studio select File > Export > Export KZB.
Update the data source to get the battery level from the Android system APIs.
It is possible to create the data source with a pattern that is simpler than presented here. However, if the data source itself uses the Android API, it causes the Kanzi Studio Preview to terminate when using this plugin on Windows. This happens because the Android APIs are not available. This tutorial demonstrates a pattern that allows the Android APIs to be conditionally used on Android, while still allowing the data source to return dummy data when run in the context of Kanzi Studio Preview.
In Android Studio, create an interface named
DataProvider
.To create a dummy implementation of the interface that is used on non-Android platforms, create a class named
DummyDataProvider
.To create an Android implementation of the interface that is used on Android, create a class named
AndroidDataProvider
.package com.example.androiddatasourceplugin; import android.content.Context; import android.os.BatteryManager; class AndroidDataProvider implements DataProvider { private final BatteryManager mBatteryManager; public AndroidDataProvider(Object context) { Context androidContext = (Context) context; mBatteryManager = (BatteryManager) androidContext.getSystemService(Context.BATTERY_SERVICE); } @Override public float getBatteryLevel() { int batLevel = mBatteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY); return ((float) batLevel) / 100.0f; } }
Update the
AndroidDataSourceDataSource
to use the new providers.Import the Kanzi classes that provide the functionality for the content that you want create.
Add a data member for the data provider:
In the
initialize()
method select the data provider:
Update the definition of the battery level data object to retrieve the value from the interface:
In Android Studio, build and run the app.
When the app is running on the Android device, the battery widget displays the current battery level of the device.
Configure two-way data source¶
In this section you create a widget that you can use to control the WiFi connectivity state on the Android device.
To create a WiFi widget:
In Android Studio update the data source to include the WiFi related information:
In the
DataProvider
interface add:In the
DummyDataProvider
class add:In the
AndroidDataProvider
class:Import the Android classes that provide the functionality for the content that you want create.
Add new members:
Constructor changes:
New methods:
@Override public void setWifiEnabled(boolean enabled) { mWifiManager.setWifiEnabled(enabled); } @Override public boolean isWifiEnabled() { return mWifiManager.isWifiEnabled(); } @Override public boolean isNetworkConnected() { NetworkCapabilities capabilities = mConnectivityManager.getNetworkCapabilities(mConnectivityManager.getActiveNetwork()); if (capabilities == null) return false; return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI); }
In the
AndroidDataSourceDataSource
class:Import the Kanzi classes that provide the functionality for the content that you want create.
Add new members:
In the
initialize()
function update the data source:root.addChild( DataObjectBool.create(domain, NETWORK_CONNECTED, mDataProvider.isNetworkConnected()).get()); ObjectRef<DataObjectBool> enabledRef = DataObjectBool.create(domain, WIFI_ENABLED, mDataProvider.isWifiEnabled()); root.addChild(enabledRef.get()); // Register a Notification handler to update WiFi state when Data Source changes. DataObjectBool wifiEnabled = enabledRef.get(); wifiEnabled.addModifiedNotificationHandler(new ModifiedSubscriptionFunction() { @Override public void handle() { mDataProvider.setWifiEnabled(wifiEnabled.getValue()); } });
In the androiddatasourceplugin >
manifests
>AndroidManifest.xml
and app >manifests
>AndroidManifest.xml
files add these permissions:To build the Kanzi Engine plugin JAR used by Kanzi Studio, run the
exportJarDebug
orexportJarRelease
Gradle target.
In Kanzi Studio in the Data Sources window click the Refresh button to read the updated data source contents from the plugin.
Create the WiFi widget UI:
In the Node Tree in the Controls node create an Empty Node 2D node, name it WiFi Widget, and in the Properties add and set:
Layout Width to 150
Layout Height to 200
Layout.Item > Horizontal Margin property Left property field to 40
In the WiFi Widget node create an Image node, name it Icon Connected, in the Properties in the Image property click + Import Image... and select the
<KanziWorkspace>/Tutorials/Android data source/Assets/WiFi-Connected.png
file.Layout Width to 150
Layout Height to 150
In the Properties add a binding and set:
Property to Visible
Expression to
With this binding you make the Icon Connected image visible when the value of the NetworkConnected data object is
true
.In the Node Tree duplicate the Icon Connected node and rename it to Icon Disconnected.
For the Icon Disconnected node:
Click the binding to edit it and in the Binding Editor add
!
to the beginning of the binding expression.With this binding you make the Icon Disconnected image visible when the value of the NetworkConnected data object is
false
.Use the
<KanziWorkspace>/Tutorials/Android data source/Assets/WiFi-Disconnected.png
image.
From the Asset Packages > Factory Content drag the Toggle Button to the WiFi Widget node in the Node Tree.
In the Node Tree select the Toggle Button node and in the Properties:
Add a binding and set:
Binding Mode to Two way
Property to Toggle State
Expression to
You create a two-way connection between the toggle state of the Toggle Button node and the WifiEnabled data object.
Add the Vertical Alignment property and set it to Bottom
In Kanzi Studio select File > Export > Export KZB.
In Android Studio, build and run the app.
When the app is running on the Android device, the WiFi widget displays the connected or disconnected icon based on the WiFi connectivity status of the device.
Update data sources based on external changes¶
Until now, the data read from Android at application startup is constant. This step updates the data source to repond to Android callbacks and update the datasource when the WiFi or battery level are changed.
Create a new interface named
DataChangeListener
to accept data changes when they occur.Modify
AndroidDataProvider
to receive the updated data from Android.Import the Android classes that provide the functionality for the content that you want create.
Add a member that holds a reference to a
DataChangeListener
.Modify the
AndroidDataProvider
constructor to receive and store aDataChangeListener
.Add listener callbacks for the WiFi state and battery level:
// Battery level listener private final BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); float batteryLevel = level / (float) scale; mDataChangeListener.updateBatteryLevel(batteryLevel); } }; // WiFi state listener that indicates whether WiFi is enabled. private final BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { int wifiStateExtra = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN); switch (wifiStateExtra) { case WifiManager.WIFI_STATE_ENABLED: mDataChangeListener.updateWifiEnabled(true); break; case WifiManager.WIFI_STATE_DISABLED: mDataChangeListener.updateWifiEnabled(false); break; } } }; // Network state listener that indicates whether an Internet connection is availabile. private final ConnectivityManager.NetworkCallback mNetworkCallback = new ConnectivityManager.NetworkCallback() { @Override public void onAvailable(Network network) { super.onAvailable(network); NetworkCapabilities capabilities = mConnectivityManager.getNetworkCapabilities(network); if (capabilities != null) { mDataChangeListener.updateNetworkConnection(capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)); } } @Override public void onLost(Network network) { super.onLost(network); mDataChangeListener.updateNetworkConnection(false); } };
To register the callbacks with Android, add this code to the
AndroidDataProvider
constructor:// To get the WiFi connectivity state changes, register the WiFi state receiver. IntentFilter intentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION); androidContext.registerReceiver(mWifiStateReceiver, intentFilter); // Listen to connectivity state changes. mConnectivityManager.registerDefaultNetworkCallback(mNetworkCallback);
Modify
AndroidDataSourceDataSource
to handle data updates:Change the class to implement the
DataChangeListener
interface.Add an implementation of the
DataChangeListener
interface.private boolean mUpdateInProgress = false; @Override public void updateBatteryLevel(float batteryLevel) { DataObjectReal batteryObject = (DataObjectReal) mRoot.get().lookupDataContext(BATTERY_LEVEL); if (batteryObject != null) { mUpdateInProgress = true; batteryObject.setValue(batteryLevel); mUpdateInProgress = false; } } @Override public void updateNetworkConnection(boolean isConnected) { DataObjectBool networkConnected = (DataObjectBool) mRoot.get().lookupDataContext(NETWORK_CONNECTED); if (networkConnected != null) { mUpdateInProgress = true; networkConnected.setValue(isConnected); mUpdateInProgress = false; } } @Override public void updateWifiEnabled(boolean isEnabled) { DataObjectBool wifiEnabled = (DataObjectBool) mRoot.get().lookupDataContext(WIFI_ENABLED); if (wifiEnabled != null) { mUpdateInProgress = true; wifiEnabled.setValue(isEnabled); mUpdateInProgress = false; } }
In the
initialize()
method, addthis
as an argument to theAndroidDataProvider
constructor.In the
initialize()
method, modify the existing notification handler to add themUpdateInProgress
variable to prevent recursive updates.
In Android Studio, build and run the app.
When the app is running on the Android device, the WiFi widget updates if the network connection state changes while the app is running. To test this, enable and disable network connections through the device UI, or use the toggle button in the WiFi widget.
What's next?¶
In this tutorial you learned how to use Kanzi Android framework (droidfw) to:
Create a data source using Kanzi Java API.
Bind data source data with Android APIs
To learn more about how to use Kanzi Android framework (droidfw) and Java API see:
See also¶
To learn more about developing Kanzi applications for Android, see Developing Kanzi applications for Android.
To learn more about using Java Kanzi Engine API, see Using Java and Kotlin.