- 1 Quick introduction to widgets
- 2 Common mistakes, troubleshooting and best practices
- 3 Further Reading
Building first apps
Quick introduction to widgets
Widgets are building blocks of ginstr launcher. ginstr custom widgets are explained in detail here. ginstr widgets have some internal functionality like taking a photo, calling a number. ginstr widgets are based on Android widgets and their behaviour is similar. For information about Android widgets refer to Android Documentation.
Widget XML structure
Each page (screen) must have root layout (widget) which behaves as main container of displayed (child) widgets such as
GnEditText and others.
Widget attributes will depend on design and business logic requirements of the ginstr app where following attributes must be defined for every widget:
- opening bracket “
<” and widget name
- closing bracket “
/>” or “
- where pipe (
|) translates as option to choose one of attribute values shown.
- where pipe (
Below is example XML code for root layout. Note that lines 2-4 are obligatory only for each root layout and do not require any changes. Line 5 is used as identifier for widget and in a case of root layout it is required and must be unique across the whole given XML file (screen).
1. <LinearLayout 2. xmlns:android="http://schemas.android.com/apk/res/android" 3. xmlns:tools="http://schemas.android.com/tools" 4. xmlns:gn="http://schemas.ginstr.com/ginstr" 5. android:id="@+id/start" 6. android:layout_width="match_parent" 7. android:layout_height="match_parent" > 8. <!-- displayed child widgets --> 9. </LinearLayout>
Line 8 is the location that contains widgets which will form screen content. All widgets in single screen XML file are in parent-child relationship. For better overview of XML code, it is desired that each child is indented to the right by tabulation or number of spaces in relation to parent, which is in most IDE-s 4 spaces. This will ensure easier future improvements. There are different types of widgets where one can only display some content (text, image), while others can also be used to input values by user. We will describe several widgets of each group.
Display only widgets
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="25sp" android:text="@string/txtPage1Headline" />
Typical usage is showing text from string resource (strings.xml) on screen for purpose of page headline, subheadline and labeling other widgets. Attribute
textSize should be defined. Attribute
text has value
@string/txtPage1Headline which is reference to strings.xml containing textual value to be displayed as label.
This value is stored in strings.xml as below:
<string name="txtPage1Headline">Page 1</string>
<ImageView android:layout_width="match_parent" android:layout_height="wrap_content" android:src="@drawable/background_i" />
Widget is used to display graphic resource (image located in one of drawable directories) which is defined with
background_i is name of image (without file extension type .png, .jpeg, etc) to be displayed in widget.
The main purpose of ImageView is to enrich UI for better user experience. Other purposes may be attaching click event, which executes specific action. More about click events and execution actions will be described later in manual.
ImageView is used for icon and bottom image in red borders.
Input value widgets
The following widgets are expecting the user to input some value, textual, numeric and other. The main purpose of Input value widgets is to collect data from user including pictures, digital signatures or scanning NFC (barcode). Some widgets can behave differently based on defined attributes. For instance, the most versatile widget is
GnEditText which can used as input box for collecting alphanumeric values, but can also be configured for scanning NFC tag and more.
Input textual value (input box)
<com.ginstr.widgets.GnEditText android:id="@+id/firstName" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/entering_field_transparent_2.9" android:textSize="20sp" gn:s_sourceType="input" gn:s_hint="@string/txtFirstNameHint" />Screenshot 3 (shown right) represents how input boxes look in application with attached background and hint text inside. Note that labels are above each input box.
An input box is used to collect alphanumeric data from user, which is entered via keyboard on device. Representation can be enriched with displaying hint text inside of an empty input box using attribute
gn:s_hint=”@string=txtFirstNameHint”. Hint text value is located in strings.xml, same as for
TextView label described earlier. Further design enrichment includes showing input box on graphic background using attribute
Image for input background is located in drawable directories.
Widget has also defined
android:id needed for referencing it in further app execution which may include saving data from this widget to database, saving data to variable, comparing widget data to another widget and other decision making business logic. With attribute
gn:s_sourceType=”input”, widget is configured to allow input of alphanumeric values. With different types of configuration of this attribute, widget can be used for different types of data entry such as numeric, current time, serial number of device and other. It is important to note that this attribute must always be defined for this widget.
Read NFC tag
<com.ginstr.widgets.GnEditText android:id="@+id/readNfcTag" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/entering_field_transparent_2.9" android:textSize="20sp" gn:s_hint="@string/txtReadNfcTagHint" gn:act_validate="[name:RequiredValidator],[message=@string/txtReadNfcTag Required]" android:textColor="#000000" android:textColorHint="#BABABA" gn:s_sourceType="nfc" gn:act_setOnNfc="[gn:act_trigger]|[@+id/actionSetWidget,gn:act_set]" />
Widget XML code above is same widget type as plain “input box” but configured to read NFC tags. This is achieved with defining
gn:s_sourceType=”nfc”. When the NFC tag is read with device, read code will be displayed inside input box and action
gn:act_setOnNfc will execute all actions defined within the attribute value. Usually this would point to some action set which holds commands for reading data from database with NFC tags as a key and decision making based on data existence. Validation attribute
gn:act_validate is present here, behaving as attribute to be checked when validation check is triggered. This attribute will be checked with action
[gn:act_validateScreen]| in app execution. In given example validator requires that value must be present in widget
@+id/readNfcTag, if not toast message will be displayed to user, where text value shown to user is referenced with
Validation attributes are used to ensure that data must be present in widget or having defined minimum, maximum length or other configured format of the content. With validators, user is forced to input data, which app business logic requires. More about validators is explained here.
Regarding naming convention of string resources in strings.xml, note that labels for widgets are related for better description of page or specific input box (for example label
“txtFirstName”). Hint text for input will then be
“txtFirstNameHint” and if validator is used
“txtFirstNameRequired” will be string name resource. This will later ensure logical structuring of string resources and keep uniqueness through all strings.
It is not permitted to use some string resource more than once.
Names of widget id’s will be closely related to database column names and in best case they should be the same.
With some described types of widgets we see that some of them are only for displaying text or images while others can have multiple purposes like entering data, reading data from other sources, displaying data from database, etc. The same applies to events and actions. Some event can be defined on widget, which then executes action (or several actions, called action set). For example event
“gn:act_beforeLoad” attached to widget will execute action right before page is displayed on device, for instance loading some data fom database. Other events could be executed when user clicks on widget
“gn:act_setClick”,for loading next page (screen). This is usually the case for buttons or some other user interaction.
Uploading ginstr apps to ginstr web
To upload ginstr app to ginstr web, a zip file of root folder must be created which contains all of our ginstr app folders (usually called app zip) and uploaded to server
https://18.104.22.168/SSOServer in application management section. If you don’t have permission for ginstr app zip upload, request access from ginstr apps developer for uploading this app zip. After upload, table with columns will be created on back-end side. This can be examined by opening ginstr web UI and searching app name and opening table in new portlet.
If app is on the list but does not have any tables, they should be enabled for current ginstr account. In ginstr UI lobby hover with mouse over account name will open menu. Selecting my account opens page for managing app for current ginstr account.
Click on “my account” and then on “hide/show content”. This will open list with apps. Clicking on app name opens in right tab table list with CRUD rights for each table. Clicking on table names will create tables if they are not yet created. For development purpose enable full CRUD rights for each table.
After this step is done ginstr app tables should be visible in portlet of ginstr web, if this is not the case please contact ginstr app developer.
Updating ginstr apps that are already present on ginstr web
Updating ginstr app procedure is identical to uploading new ginstr app. However, there are some restrictions to modifications of ginstr app table structures to existing apps. If some of restrictions is blocking to update new ginstr app it's required to uninstall the app from ginstr web and add it as new app. Ask ginstr app developer or admin to do that. Restrictions in modifications of ginstr app new uploaded ginstr app zip are:
- Company name and appId (zip file name) must be identical to original upload
- Table names should be unique in ginstr app zip
- Changing of datatype of existing column is not allowed
- Table must have columns
- Columns can't be deleted if they have references
- It's not possible to set "unique" or "required" setting on columns of a table that already has entries
- New "required" column can not be added to table if "default value" is not set on in the column settings
- New "unique" column with "default value" setting can not be added to table which has more than one row of existing data
Common mistakes, troubleshooting and best practices
We will present several cases which ginstr app developer may encounter during development process. It is important to note that ginstr launcher, as a framework in which ginstr apps are running, is constantly being improved and with every new version, new implementations make new possibilities to make more powerful ginstr apps. This process is also oriented to improvements of existing “functions”. Each version has improved error handling and also provides ginstr app developer with better feedback about bugs in XML which are causing errors.
The dialog as shown on Screenshot 7 (right) will be displayed on screen in situations where ginstr app is crashing.
Confirming with click on “SEND” will generate debug log with various app data and error information. This report will be sent by device to redmine and examined by ginstr launcher framework developers. Report should always be sent, before ginstr app developer should check if similar report does not exist on redmine.
The most common actions to verify before sending report should be:
- Check XML code which is changed before last good app execution – good text (or IDE) editors have XML syntax checker to verify if some node (widget) does not have valid structure (closing brackets, spaces in attributes, etc…). Additionally XML can be validated via XML checkers online, for instance xmlvalidation.com. In the first instance it is good practice to have an editor which supports XML validation.
- Check for widgets minimum required set of attributes – app could crash if some widget does not have all necessary attributes defined:
- XML errors related to action sets:
- Each action signature consists of two pairs of angle brackets (
]) and pipe (
|) between them.
- Action set not in if statement is separated with comma (
,) and in if statement separator is semicolon (
;). Mismatching those separators may crash app and should be carefully checked.
- Adding query to action set crashes the app – first it is important to check correct signature, noting the difference between
rawQueryToWidgets. Incorrect separators, incorrect number of parameters, incorrect widget IDs or incorrect column names could lead to app crash.
- Missing XML file will prevent app from starting,crash app on launch or if action is referencing some root layout – check minimum folder and XML file requirements for app. Beware that copy/paste app files from PC to device may not reveal missing file, due to transfer error resulting in files incorrectly copied to device. Examining folders and files on device for given app on device can help determine missing XML file.
- Each action signature consists of two pairs of angle brackets (
If on any of issues app crashes and issue does not exist on redmine, write a short description in bug report of steps how to reproduce the problem and link it to related app once report is created on redmine.
- Query is not returning result, even though table has records and key is correct
- Check queries.xml if query is correct, all column names, key
rawQueryToWidgetsis used, try with
rawQueryToWidgetwith single column and single widget
- Try querying table without keys and set toast messages into true and false statements
- Query result is not setting for some column into widget
- Check widget data type is the same as column data type
- Try using another widget for returned data
- Check column name in backend table
- Query for writing is crashing app:
- Check column-widget pairs
- Try with single column and single widget to verify if query has all prerequisites for correct execution
- If some hidden widgets are saving in query, make them visible and set break before query is executed and after after query execution
- Query is not saving/updating record in table, app is not crashing
- In some cases query may not cause app crash but query is not affecting data changes in backend
- Uninstall ginstr launcher and install app from the start, after data replication try query again, this is because in some rare cases app developing process could make invalid data on device, breaking correct app execution with each new implementation
- Updating data to database requires using pointer widget which may not have any value and in app implementation it is hidden from the screen. Reveal this pointer and examine if widget has value of table record for update
- Action set could be spread through XML file and it is not clear place of XML code that app is not working correctly or it crashes
gn:act_breakaction to stop app execution
- Move break action further in action chain to which app behaves correctly
- Use toast messages in if-then statements to have feedback on screen about decision login during app execution
- Widget id's, action separators, XML validation should be checked when app has bugs
- Comparing two widgets is not working as expected or crashing app
- When comparing two widgets, variables or combination, it is important that they have same data type
- Check comparing action with widget which has hardcoded value to verify comparing logic
- Dropdown with database as source values does not have any values, even though table in backend has records
- Uninstall launcher and install launcher and app again
- Check query, table name, query name, widget id
- String resource is not showed in app
- Start developing XML files with intuitive naming of files and root layout id’s, for example
- During development work on strings.xml in folder values-en
- Name strings with clear description having suffix “Hint” and “Required” if related to same widget
- Make prototype of app business logic with basic read, write and update queries to confirm action set flow, then enhance with additional business logic which app requires
- Use column names for widget id's which are used for saving/updating data
- Avoid having action sets in widgets, keep those “procedures” in
FrameLayoutwith intuitive id's grouped in certain place in XML file (at the top or bottom)
- Avoid using helper widgets when possible and employ variables
- Use helper toast messages for verifying business logic steps but clear them before app deployment
- Keep good track of changes made in every app version in changelog.xml
- Design fixes should be last step in app development
- Use existing good app layouts but track each copy/paste of XML for required changes
- Try every step verifying XML code for validation before sending bug report
- Follow ginstr app test procedure rules to avoid app changes later
- Investigate business logic part in other apps and try to improve them in each new app being developed
- It is recommended to set
"match_parent"values to attributes
android:layout_height. If fixed values are used i.e.
50dpit might result in content being cut off if bigger font is used because fixed size container does not stretch with content..
- Avoid landscape mode when developing apps. It is recommended to use portrait mode only as devices are used mostly in portrait mode and it allows better visibility of the content.