Basic4android Tutorials http://www.basic4android.com
Feedback:
[email protected] Updated: March 23, 2011
1
No part of this document may be reproduced in any form or by any electronic or mechanical means including information storage and retrieval systems, without permission in writing from the author.
This document collects some of Basic4android tutorials and examples. The most updated tutorials can be found online: http://www.basic4ppc.com/forum/basic4android-getting-startedtutorials/
2
Table of contents Installing Basic4android and Android SDK .....................................................................4 Hello world - Installing Android Emulator ......................................................................7 Guess my number - Visual designer & Events ............................................................... 13 IDE Tips ....................................................................................................................... 19 B4A-HelpViewer - View and search the documentation offline..................................... 24 B4A-Bridge a new way to connect to your device ......................................................... 25 Connecting your device to the IDE using ADB.............................................................. 28 Android Process and activities life cycle........................................................................ 32 Static Code Modules ..................................................................................................... 36 Service Modules............................................................................................................ 37 Variables & Objects ...................................................................................................... 41 Currency Converter – libraries, file manager and other important concepts.................... 45 Working with files......................................................................................................... 53 Views (controls) and Dialogs ........................................................................................ 57 GPS tutorial .................................................................................................................. 64 MediaPlayer – Playing music ........................................................................................ 68 ListView tutorial ........................................................................................................... 71 ScrollView tutorial ........................................................................................................ 76 TabHost tutorial ............................................................................................................ 78 FlickrViewer example – Download multiple images concurrently ................................. 80 Two activities example.................................................................................................. 81 Building a linked list using Type keyword..................................................................... 83 SQL tutorial .................................................................................................................. 85 XML parsing with the XMLSax library......................................................................... 90 Take pictures with the internal camera........................................................................... 93 Serial (Bluetooth) tutorial.............................................................................................. 95 JSON parsing and generating ...................................................................................... 100 Animation tutorial ....................................................................................................... 103 Network tutorial .......................................................................................................... 107 Regular Expressions .................................................................................................... 111 Downloading files using Services................................................................................ 114 AsyncStreams tutorial ................................................................................................. 116
3
Installing Basic4android and Android SDK Basic4android depends on two additional (free) components: - Java JDK - Android SDK
Installation instructions: The first step should be to install the Java JDK as Android SDK requires it as well. Note that there is no problem with having several versions of Java installed on the same computer. - Open the Java 6 JDK download link. - Select "Windows" in the platform combo box (for 64 bit machines as well). Android SDK doesn't work with Java 64bit JDK. You should install the regular JDK for 64bit computers as well. - Press on the red Continue button. There is no need to sign in! If for some reason you don't see the red Continue button try to switch to a different browser. - On the next page you should press on the file link:
- Download the file and install it. Next step is to install the Android SDK and a platform: - Download Android SDK. - Install the SDK. - When the application opens it will show a page with all the available packages. Press "Cancel" button as you do not need to install all the platforms. - Choose "Available Packages" and choose "SDK Platform 2.2, API 8". It should appear under the "Android repository" node. The file structure of API 9 is different. For now you should use API 8.
4
Note that you can install more packages later. - Press on Install Selected and install both packages. Install and configure Basic4android - Download and install Basic4android. - Open Basic4android. - Choose Tools menu - Configure Paths.
5
- Use the browse buttons to locate "javac.exe" and "android.jar" javac is located under \bin. android.jar is located under \platforms\android-8 On Windows 64 bit, Java will probably be installed under C:\Program Files (x86).
6
Hello world - Installing Android Emulator In this tutorial we will create a new AVD (Android Virtual Device) which is an emulator instance. Then we will create a simple program that displays a simple message box and also writes a message to the log. You can also connect a real device to the IDE: Connecting your device with ADB Connecting your device with B4A-Bridge Create new AVD - Run Basic4android. - Choose Tools Menu - Run AVD Manager. Wait a few seconds. - The AVD Manager should appear:
- Choose New and fill the fields similar to the following image:
7
- Press on Create AVD. - Note that you can create more than one AVD. Each can have a different resolution or can target a different API version (you will need to install additional platforms first). - Now press Start in order to start the emulator
- You will see several windows popping up and disappearing. This is fine. - The emulator should boot up:
8
Wait... on the first time it can take several minutes till the emulator is ready. The emulator is ready when it gets to this screen:
You may see this screen, which is the lock screen, instead:
Drag the lock icon to the right to unlock the device. Note that there is no need to restart the emulator each time you deploy a program. The emulator can be kept running all the time. If you are not familiar with Android you can play with the emulator. Press on the button with the small squares to get to the application page.
9
Writing your first Basic4android program - As this is a new program we should first set its location by choosing File - Save. It is highly recommended to save each project in its own folder. - Create a new folder: "Hello world", open the folder and save the program as "Hello world". - Write the following code under Sub Activity_Create: Code: Sub Activity_Create(FirstTime As Boolean) Log("Hello world!") Msgbox("Hello world?", "First program") End Sub
-
Press F5 to compile and deploy your program to the emulator. The package dialog should appear (empty):
Each Android application is identified by a unique package string. This is a string built of several parts separated with periods. The string should include at least two parts. You cannot install two applications with the same package on one device. Note that you can always change the package name (and the label) under tools menu. - Enter a package name. - Next you will be asked to enter the application "label". This is the application name that the user will see. Your program will now be compiled and installed to the emulator:
10
The emulator is significantly slower than a real device. In many cases it is more convenient to work with a real device as the installation is much faster. Note that you can always redeploy your program. There is no need to close the running program on the emulator. Tracking the log with LogCat Android devices keep an internal buffer of log messages. These messages can be very handy for debugging. To view the logs you should switch to the LogCat tab in the right pane and press connect:
11
There are two "Hello world!" messages in the screenshot as I ran the program twice. Unchecking "Filter" will show all available messages (not just messages relevant to your program). Hello world
12
Guess my number - Visual designer & Events In this tutorial we will use the designer to create the layout. The layout includes an EditText (TextBox) and a Button. The user needs to guess a random number. The user enters the number in the EditText view (control) and presses on the button to submit the guess. A "toast" message will appear, indicating to the user whether the number is larger or smaller than the chosen number. - Create a new project and save it. - Open the designer by choosing the Designer menu. The designer is made of two main components. The "control panel" which contains all the available properties and options, and is part of the IDE:
and the "visual" component which runs on a device or emulator:
13
The visual component, as it names suggests, displays the layout. It also allows you to move and resize the views (controls). Changing the layout in the visual component will also change the values stored in the control panel. Note that all the data is stored in the control panel component. Therefore nothing bad will happen if the emulator crashes or is turned off. You can connect to it again and the layout will appear. The first step is to connect to the device. Press Tools - Connect. This step takes several seconds. Note that the IDE will stay connected until the IDE closes. Closing the designer will not disconnect the connection. Use the Add View menu to add a Button, an EditText and a Label. Change the views Text property and position them similar to this:
14
Change the Activity Drawable property to GradientDrawable to achieve the gradient effect. Tip: When working with a small monitor you may find it convenient to check the "Top Most" option (in the upper right corner). It will cause the control panel to stay on top and not be hidden by the emulator. Save your layout, name it Layout1. An important concept about layouts is that there is a complete separation between your code and the layouts. The layout is saved as a file, with ".bal" extension. Each project can have any number of such files and unless you explicitly load a layout file, it will not have any effect on your application. Once you have saved a layout, it is automatically added to the "File manager". You can see it under the "Files" tab in the IDE right pane. We want to catch the button's click event. Each view has an EventName value. It is a property in the Designer, and a parameter passed to the Initialize method when adding views programmatically. In order to catch an event you should write a Sub with the following structure (it is simpler than it sounds): Sub _ (event parameters). In the designer, the EventName property is set by default to the view's name. If we want to catch the Click event of a button with EventName value of Button1 we should write the following sub signature: Sub Button1_Click So here is the complete code:
15
Code: Sub Process_Globals End Sub Sub Globals Dim MyNumber As Int Dim EditText1 As EditText 'will hold a reference to the view added by the designer End Sub Sub Activity_Create(FirstTime As Boolean) Activity.LoadLayout("Layout1") 'Load the layout file. MyNumber = Rnd(1, 100) 'Choose a random number between 1 to 99 End Sub Sub Button1_Click If EditText1.Text > MyNumber Then ToastMessageShow("My number is smaller.", False) Else If EditText1.Text < MyNumber Then ToastMessageShow("My number is larger.", False) Else ToastMessageShow("Well done.", True) End If EditText1.SelectAll End Sub
Some notes: - Every activity module comes with an Activity object that you can use to access the activity. - Activity.LoadLayout loads the layout file. - There are other views that can load layout files. Like Panel and TabHost. For TabHost each tab page can be created by loading a layout file. - In order to access a view that was added with the designer we need to declare it under Sub Globals. - ToastMessageShow shows a short message that disappears after a short period. Using a toast message in this case is not optimal as it may be unnoticed when the soft keyboard is open. Tip for writing events subs: In the IDE, write Sub and press space. You should see a small tooltip saying "press tab to insert event declaration". Press tab, choose the object type and choose the event.
16
Now all you need to do is to write the required event name and press enter. Supporting multiple screen resolutions and orientations Each layout file can include a number of layout variants. Each layout variant holds a different set of values for the position and size of the views. If for example, you change the text of any view it will be changed in all variants automatically. However if you change the position of a view it will only affect the current variant. Note that scaling is handled automatically if required. Which means that if we run our program on a high resolution device, the layout will be automatically scaled. Still you may choose to create different variants for different scales. When you load a layout file the variant that best matches the current device will be loaded. Usually you will need two variants: - 320 x 480, scale = 1 (160 dpi). This is the default scale in portrait mode. - 480 x 320, scale = 1 (160 dpi). Default scale in landscape mode. Ok, so open the designer again. Load Layout1 file if it is not opened. Choose "New Variant" and choose 480 x 320 (second option).
Change the emulator orientation by clicking on the emulator and then press on Ctrl + F11. Note that the device layout details appear under the list of variants. Change the layout to be similar to this:
17
You can change the current selected variant and see how it affects the visual layout. Save the layout and run the program. Change the emulator orientation and see how the layout changes accordingly. Android destroys the old activity and creates a new activity each time the orientation changes. Therefore Activity.LoadLayout will be called again each time. Unfortunately the number will also be randomly chosen again each time. This can be easily fixed... But not in this tutorial. The project is attached. Last tip for this tutorial: - The IDE includes an "Export as zip" option under Files menu. This method creates a zip file with all the required files.
18
IDE Tips The IDE has several powerful features which can help you concentrate on writing your code and building your application. I'm listing here some of the less obvious features: - Ctrl
+ Space = auto complete
Pressing Ctrl + Space activates the auto complete feature which will then show you a list with the available keywords, variables, modules, methods, subs, properties and fields. The list includes a description for most items. Pressing Ctrl + Space after typing the first few letters will usually select the required item automatically.
- Tool tip information - while writing methods parameters, a tool tip will be opened with the method signature and description. The tool tip might hide some important code that you now need. You can hide it by pressing escape. You can also turn it almost invisible by pressing the ctrl key. Another press will return it to be fully opaque.
19
LogCat - The LogCat tab displays the device built-in logs. These logs are very useful for debugging. You can log messages with the Log keyword. In order to start displaying the logs you press on the Connect button. The logs can be filtered and then you only see messages generated by Basic4android or your application.
Note that if you have more than one device connected you can switch to a different device by pressing on the Connect button. Designer generated members tool - This tool allows you to add the declaration code for the designer views and to add event subs. Note that you only need to declare views that you intend to access by code. Nothing will happen if you select an existing item (there will be no duplicated code).
20
To open this tool choose - Tools - Generate Members (from the designer form). Background compilation - Pressing Alt + 3 will compile and install your application while keeping the IDE responsive. The status bar at the bottom of the screen displays the progress of the process and when the installation is completed. A short sound will notify you if the process failed. In that case you may need to compile regularly (F5) in order to see the error message (it depends on the type of error). Working with multiple connected devices - In many cases you have more than one device connected. For any operation that starts a connection you will be shown the list of connected device and you will choose the target device. If you compile in the background the last device will be used again. This is usually more convenient than compiling in the foreground and selecting the target device each time. Designer - Duplicate - You can duplicate any view by selecting the view and then choosing Tools - Duplicate View. If the view has child views then all its child views will be duplicated as well. Export as zip - Export as zip option creates a zip file with all the required project files. This is useful when you want to share your project with others or create a backup. It is located under Files menu. Clean Project / Clean Unused Files - Clean project deletes all generated files. These are 21
files that are generated during compilation. Clean unused files deletes files that are located under the Files folder but are not used by the project (it will not delete any file reference by any of the project layouts). A list of unused files will be displayed before deletion (and allows you to cancel the operation). Run AVD Manager - The AVD manager allows you to create and start emulators. This menu opens the manager. Note that there is no need to keep the AVD manager open after starting an emulator. Events subs signatures -There is a special auto complete feature that can help you write the event subs signatures. Start with writing Sub followed by a space:
A message will appear as in the image. Press Tab key:
A list will be displayed with all the available types (that have at least one event). Choose the required type and press enter.
Choose the specific event. Code similar to the following code will be generated:
22
The EventName string will be selected. Change it to match the object "EventName" value and press enter. That's it. Designer top most property - The designer has a "top most" check box which you can use to keep the designer as the top most form. This is useful when working with the designer and the emulator on a small screen. Debugging data - By default Basic4android compiler adds some debugging data to your code. This data is used when an error occurs. It allows the program to show the original code line which raised the error. This data does take some space and may impact performance, though it usually should be insignificant. You can remove this data by unchecking Project - Include Debug Information.
23
B4A-HelpViewer - View and search the documentation offline I'm happy to release the second beta version of B4A HelpViewer. This utility allows you to browse and search the documentation and the forum posts from the desktop. It automatically checks for updated libraries and forum posts during start-up. The libraries manuals are downloaded and stored locally. The search functionality is built using Lucene.
For now there is no installation step. You should unzip the file and run B4A-HelpViewer. Note that it should not be located under Program Files as it needs "write permissions". Download link 24
B4A-Bridge a new way to connect to your device Currently there are two ways which you can use to test your application during development. You can either work with the Android emulator or if your device supports ADB debugging, you can connect to your real device. The Android emulator is very slow compared to a real device (especially with applications installation). Therefore in most cases it is more convenient to work with a real device. Personally I'm only using the emulator when working with the visual designer. However not all devices support ADB debugging. This is exactly the reason for the new B4A-Bridge tool. B4A-Bridge is made of two components. One component runs on the device and allows the second component which is part of the IDE to connect and communicate with the device. The connection is done over a network (B4A-Bridge cannot work if there is no network available). Once connected, B4A-Bridge supports all of the IDE features which include: installing applications, viewing LogCat and the visual designer. Android doesn't allow applications to quietly install other applications, therefore when you run your application using B4A-Bridge you will see a dialog asking for your approvement. Getting started with B4A-Bridge 1. First you need to install B4A-Bridge on your device. B4A-Bridge can be downloaded here: http://www.basic4ppc.com/android/files/b4a_bridge.apk. B4A-Bridge is also available in Android market. Search for: B4A Bridge. Note that you need to allow install of applications from "Unknown sources". This is done by choosing Settings from the Home screen - Manage Applications. 2. Run B4A-Bridge on your device. It will display a screen similar to:
25
Status will be: Waiting for connections. 3. In the IDE choose Tools - B4A Bridge - Connect. You will need to enter the IP address that appears on the device screen. The status bar at the bottom of the screen shows the current status:
That's it. When B4A-Bridge gets connected it first checks if the designer application needs to be updated. In that case it will first install the designer application. B4A-Bridge keeps running as a service until you press on the Stop button. You can always reach it by opening the notifications screen:
26
Pressing on the notification will open the main screen. As mentioned above, when you run an application you are required to approve the installation. You will usually see the following screens:
In the above dialog you should choose Open to start the application. If you try to install an existing application signed with a different key, the install will fail (without any meaningful message). You should first uninstall the existing application. Go to the home screen - Settings - Applications - Manage applications choose the application - Uninstall. Once you finished developing you should press on the Stop button in order to save battery. Note that B4A-Bridge was written with Basic4android. The source code is available here: http://www.basic4ppc.com/forum/basic...html#post45854 27
Connecting your device to the IDE using ADB This tutorial was written by Andrew Graham Introduction A program called adb.exe - Android Debug Bridge - is the key component that is used to communicate between programs on your desktop and the emulator or device. adb can be invoked without user intervention by programs such as Basic4Android and Eclipse but also has a command line interface that can be used by advanced users. adb.exe is provided with the Android SDK and is located, together with other development tools, on early versions of the Android SDK in the \tools and on more recent versions in the \platform-tools folder. Unless adb can connect properly to the emulator or device Basic4Android will not be able to load and run applications, however in this event they could still be compiled then copied to the SD card on the device by USB and installed from there. This tutorial tries to explain how to get your device connected to adb so that you can use it with the Basic4Android IDE.
Device SD cards and USB Although this capability is entirely independent of adb it is worth including here for completeness in describing how devices use USB connections. Android devices have a USB port that when plugged into a desktop lets the SD card on the device look like a USB memory stick. The first time that a device is connected to a desktop by USB Windows should automatically detect this and install the necessary driver without you having to do anything. The SD card will then appear as a disc drive in Windows Explorer and Device Manager while the device is connected. While the SD card is visible to the desktop as a drive the device will not be able to access it as it is unmounted from the device. Some, but not all, devices allow you to mount and unmount the SD card from the device when it is plugged into the desktop USB. Other devices do not offer this option but automatically unmount it on connection to USB and remount it on disconnection. You will have to see how your own device behaves in this regard
The emulator and adb There should be absolutely no problem using the emulator with Basic4Android. adb will connect automatically and should work well, although I have found that if the emulator is running Android 1.6 the adb connection will frequently drop and cause problems. Therefore I recommend using Android 2.1 or later in the emulator to avoid any possible problems. Also there should be no problem interacting with the emulator with adb in command line mode if that is required. Because the emulator should just work the
28
remainder of this article deals with connecting devices by means of adb.
Devices and adb In my experience so far devices differ in their USB capability and in their interaction with adb and Windows so the following can only be a guide. Your experience may vary. adb can connect a device to the desktop by two different means, Wi-Fi and USB. In both cases for adb to recognise the device Settings -> Applications -> Development -> USB debugging must be checked. This runs the adb daemon on the device which communicates with adb on the desktop.
adb and WiFi To connect to a device wirelessly you need to connect the device to the network by Wi-Fi and obtain the device IP address. This can be found under Settings -> Wireless & Networks -> Wi-Fi Settings. Press the connected network under the WiFi Networks section and a message box will display the connection details. Before running Basic4Android open a Command Window in the \tools folder and type the command adb connect 192.168.0.10 replacing the IP address with the correct one for the device. if you get an error try specifying the port adb connect 192.168.0.10:5555 I have encountered only partial functionality with adb over Wi-Fi. I have a tablet that works fine with adb and so with Basic4Android - which is just as well as the tablet lacks the USB connectivity needed for adb. I also have a phone that mostly works with adb in command line mode but adb hangs and doesn't return to the command prompt after performing an install or uninstall although the actual operation on the device is successful. This behaviour means that neither Basic4Android nor Eclipse can be used with the phone over wireless but thankfully they work perfectly over USB.
adb and USB
29
Many Android devices, but not all like some cheap Chinese Android tablets, have two more USB interfaces "Android ADB Interface" and "Android Composite ADB Interface". These belong to a device that, on successful USB driver installation, appears as "Android Phone" in Device Manager and is used by adb to connect to the phone over USB. If your phone lacks these it may still be possible to connect adb to it by means of wireless as described above. These Android interfaces, unlike SD card access, need custom USB drivers that are located in the \usb_driver. In this folder there is a android_winusb.inf file that contains the USB IDs needed to install the drivers for different phones. When a phone is connected and Windows asks for the drivers for this device point it to this folder. If the drivers then fail to install it is likely that the android_winusb.inf does not contain the IDs for the phone. In android_winusb.inf there are two sections the one named [Google.NTx86] contains the details for 32 bit systems, another named [Google.NTamd64] contains the details for 64 bit systems. The two sections are in fact identical. For my phone to be recognised the following details needed to be inserted in each of the two sections mentioned. ;Orange San Francisco %SingleAdbInterface% = USB_Install, USB\VID_19D2&PID_1354&MI_00 %CompositeAdbInterface% = USB_Install, USB\VID_19D2&PID_1354&MI_02 These necessary details were obtained courtesy of a certain well known Internet search engine. However, rather belatedly, Google now at last has a list of links to manufacturer sites that provide USB drivers for their devices on this page Google USB Driver . The actual link is OEM USB Drivers. Note that for some devices, like my phone, Windows may try to install the drivers without USB Debugging being enabled on the phone. This is likely to fail even when you point Windows at the drivers that installed successfully with USB Debugging enabled. As this will happen every time the phone is plugged in to USB the solution is to keep USB Debugging enabled. This has no downside as, for this phone at least, the USB access to the SD card is entirely independent of whether USB Debugging is enabled or not. More on adb and WiFi Some devices seem to not have the adb daemon enabled for wireless. There is an application called adbWireless that can overcome this for many, but not all, devices. It is available on the Android Market, the latest version is 1.4.1, but it needs root access to the phone to work. Another application called UniversalAndroot may help here - it worked on my ZTE
30
Blade/Orange SanFrancisco to let me run adbWireless on it. It can be downloaded from universalandroot by clicking one of the links at the bottom of the page by the 2D barcodes.
31
Android Process and activities life cycle Lets start simple: Each Basic4android program runs in its own process. A process has one main thread which is also named the UI thread which lives as long as the process lives. A process can also have more threads which are useful for background tasks. A process starts when the user launches your application, assuming that it is not running already in the background. The process end is less determinant. It will happen sometime after the user or system has closed all the activities. If for example you have one activity and the user pressed on the back key, the activity gets closed. Later when the phone gets low on memory (and eventually it will happen) the process will quit. If the user launches your program again and the process was not killed yet the same process will be reused. A Basic4android application is made of one or more activities. Android support several other "main" components. These will be added to Basic4android in the future. Activities are somewhat similar to Windows Forms. One major difference is that, while an activity is not in the foreground it can be killed in order to preserve memory. Usually you will want to save the state of the activity before it gets lost. Either in a persistent storage or in memory that is associated with the process. Later this activity will be recreated when needed. Another delicate point happens when there is a major configuration change in the device. The most common is an orientation change (user rotates the device). When such a change occurs the current activities are destroyed and then recreated. Now when we create the activity we can create it according to the new configuration (for example, we now know the new screen dimensions). How do we handle it? When you create a new activity you will start with the following code template: Code: Sub Process_Globals 'These global variables will be declared once when the application starts. 'These variables can be accessed from all modules. End Sub
32
Sub Globals 'These global variables will be redeclared each time the activity is created. 'These variables can only be accessed from this module. End Sub Sub Activity_Create(FirstTime As Boolean) End Sub Sub Activity_Resume End Sub Sub Activity_Pause (UserClosed As Boolean) End Sub
Variables can be either global or local. Local variables are variables that are declared inside a sub other than Process_Globals or Globals. Local variables are local to the containing sub. Once the sub ends these variables no longer exist. Global variables can be accessed from all subs. There are two types of global variables. Process variables and activity variables. Process variables - These variables live as long as the process lives. You should declare these variables inside sub Process_Globals. This sub is called once when the process starts (this is true for all activities, not just the first activity). These variables are the only "public" variables. Which means that they can be accessed from other modules as well. However, not all types of objects can be declared as process variables. All of the views for example cannot be declared as process variables. The reason is that we do not want to hold a reference to objects that should be destroyed together with the activity. In other words, once the activity is being destroyed, all of the views which are contained in the activity are being destroyed as well. If we hold a reference to a view, the garbage collector would not be able to free the resource and we will have a memory leak. The compiler enforces this requirement. Activity variables - These variables are contained by the activity. You should declare these variables inside Sub Globals. 33
These variables are "private" and can only be accessed from the current activity module. All objects types can be declared as activity variables. Every time the activity is created, Sub Globals is called (before Activity_Create). These variables exist as long as the activity exists. Sub Activity_Create (FirstTime As Boolean) This sub is called when the activity is created. The activity is created when the user first launches the application, the device configuration has changed (user rotated the device) and the activity was destroyed, or when the activity was in the background and the OS decided to destroy it in order to free memory. This sub should be used to load or create the layout (among other uses). The FirstTime parameter tells us if this is the first time that this activity is created. First time relates to the current process. You can use FirstTime to run all kinds of initializations related to the process variables. For example if you have a file with a list of values that you need to read, you can read it if FirstTime is True and store the list as a process variable. Now we know that this list will be available as long as the process lives and there is no need to reload it even when the activity is recreated. To summarize, you can test whether FirstTime is True and then initialize process variables. Sub Activity_Resume and Sub Activity_Pause (UserClosed As Boolean) Each time the activity moves from the foreground to the background Activity_Pause is called. Activity_Pause is also called when the activity is in the foreground and a configuration change occurs (which leads to the activity getting paused and then destroyed). Activity_Pause is the last place to save important information. Generally there are two types of mechanisms that allow you to save the activity state. Information that is only relevant to the current application instance can be stored in one or more process variables. Other information should be stored in a persistent storage (file or database). For example, if the user changed some settings you should save the changes to a persistent storage at this point. Otherwise the changes may be lost. Activity_Resume is called right after Activity_Create finishes or after resuming a paused activity (activity moved to the background and now it returns to the foreground). Note that when you open a different activity (by calling StartActivity), the current activity is first paused and then the other activity will be created if needed and (always) resumed. As discussed above Activity_Pause is called every time that the activity moves from the
34
foreground to the background. This can happen because: 1. A different activity was started. 2. The Home button was pressed 3. A configuration changed event was raised (orientation changed for example). 4. The Back button was pressed. In scenarios 1 and 2, the activity will be paused and for now kept in memory as it is expected to be reused later. In scenario 3 the activity will be paused, destroyed and then created (and resumed) again. In scenario 4 the activity will be paused and destroyed. Pressing on the Back button is similar to closing the activity. In this case you do not need to save any instance specific information (the position of pacman in a PacMan game for example). The UserClosed parameter will be true in this scenario and false in all other. Note that it will also be true when you call Activity.Finish. This method pauses and destroys the current activity, similar to the Back button. You can use UserClosed parameter to decide which data to save and also whether to reset any related process variables to their initial state (move pacman position to the center if the position is a process variable).
35
Static Code Modules Basic4android v1.2 includes a new type of module which is the static code module. Adding a static code module is done by choosing Project - Add New Module - Code Module. Unlike Activities and Services, code modules are not related in any way with Android process life cycle. These are just containers for code. All of the subs in these modules are public and can be accessed from other modules. Code modules use cases include: - Avoiding duplicate code in multiple modules. - Sharing code between projects. For example you can create a code module that parses some file. Later you can easily reuse this module in other applications. - Separating your application logic. Each code module can be used for a specific task. This will make your program clearer and easier to maintain. As a code module is not tied to an activity or service it uses the calling component context when required. For example, calling a code module sub that shows a Msgbox from an activity will work. However if you call it from a service it will fail as services are not allowed to show dialogs. Code modules cannot catch events. While you can use a code module to initialize a button for example: Code: Sub ButtonsCreator(Text As String) As Button Dim b As Button b.Initialize("Button") b.Text = Text Return b End Sub
From the activity module you can call: Code: Activity.AddView(CodeModule.ButtonsCreator("press here"), 10dip, 10dip, 200dip, 200dip)
Now in order to catch the click event you should create a sub named Button_Click. This sub should be located in the Activity module, as Code modules cannot catch events. CallSub which internally uses the events mechanism cannot be used to call code module subs (which can be called directly instead).
36
Service Modules Basic4android v1.2 adds support for Service modules. Service modules play an important role in the application and process life cycle. Start with this tutorial if you haven't read it before: Android Process and activities life cycle Code written in an activity module is paused once the activity is not visible. So by only using activities it is not possible to run any code while your application is not visible. Services life cycle is (almost) not affected by the current visible activity. This allows you to run tasks in the background. Services usually use the status bar notifications to interact with the user. Services do not have any other visible elements. Services also cannot show any dialog (except of toast messages). Note that when an error occurs in a service code you will not see the "Do you want to continue?" dialog. Android's regular "Process has crashed" message will appear instead. Before delving into the details I would like to say that using services is simpler than it may first sound. In fact for many tasks it is easier to work with a service instead of an activity as a service is not paused and resumed all the time and services are not recreated when the user rotates the screen. There is nothing special with code written in service. Code in a service module runs in the same process and the same thread as all other code. It is important to understand how Android chooses which process to kill when it is low on memory (a new process will later be created as needed). A process can be in one of the three following states: - Foreground - The user currently sees one of the process activities. - Background - None of the activities of the process are visible, however there is a started service. - Paused - There are no visible activities and no started services. Paused processes are the first to be killed when needed. If there is still not enough memory, background processes will be killed. Foreground processes will usually not be killed. As you will soon see a service can also bring a process to the foreground. Adding a service module is done by choosing Project - Add New Module - Service Module. The template for new services is: Code:
37
Sub Process_Globals End Sub Sub Service_Create End Sub Sub Service_Start End Sub Sub Service_Destroy End Sub
Sub Process_Globals is the place to declare the service global variables. There is no other Globals sub like in Activity as Service doesn't support Activity objects. Sub process globals should only be used to declare variables. It should not run any other code as it might fail. This is true for other modules as well. Note that Process_Global variables are kept as long as the process runs and are accessible from other modules. Sub Service_Create is called when the service is first started. This is the place to initialize and set the process global variables. Once a service is started it stays alive until you call StopService or until the whole process is destroyed. Sub Service_Start is called each time you call StartService (or StartServiceAt). When this subs runs the process is moved to the foreground state. Which means that the OS will not kill your process until this sub finishes running. If you want to run some code every couple of minutes / hours you should schedule the next task with StartServiceAt inside this sub. Sub Service_Destroy is called when you call StopService. The service will not be running after this sub until you call StartService again (which will run Sub Service_Create followed by Sub Service_Start).
Service use cases As I see it there are four main use cases for services. - Separating UI code with "business" or logic code. Writing the non-UI code in a service is easier than implementing it inside an Activity module as the service is not paused and resumed and it is usually will not be recreated (like an Activity). You can call StartService during Activity_Create and from now on work with the service module. 38
A good design is to make the activity fetch the required data from the service in Sub Activity_Resume. The activity can fetch data stored in a process global variable or it can call a service Sub with CallSub method. - Running a long operation. For example downloading a large file from the internet. In this case you can call Service.StartForeground (from the service module). This will move your activity to the foreground state and will make sure that the OS doesn't kill it. Make sure to eventually call Service.StopForeground. - Scheduling a repeating task. By calling StartServiceAt you can schedule your service to run at a specific time. You can call StartServiceAt in Sub Service_Start to schedule the next time and create a repeating task (for example a task that checks for updates every couple of minutes). - Run a service after boot. By checking Project - Service properties - Run At Boot your service will run after boot is completed. Notifications Status bar notifications can be displayed by activities and services. Usually services use notifications to interact with the user. The notification displays an icon in the status bar. When the user pulls the status bar they see the notification message. Example of a notification (using the default icon):
The user can press on the message, which will open an activity as configured by the Notification object. The notification icon is an image file which you should manually put in the following folder: \Object\res\drawable. Accessing other modules
39
Process global objects are public and can be accessed from other modules. Using CallSub method you can also call a sub in a different module. It is however limited to non-paused modules. This means that one activity can never access a sub of a different activity as there could only be one running activity. However an activity can access a running service and a service can access a running activity. Note that if the target component is paused then an empty string returns. No exception is thrown. You can use IsPause to check if the target module is paused. For example if a service has downloaded some new information it can call: Code: CallSub(Main, "RefreshData")
If the Main activity is running it will fetch the data from the service process global variables and will update the display. It is also possible to pass the new information to the activity sub. However it is better to keep the information as a process global variable. This allows the activity to call RefreshData whenever it want and fetch the information (as the activity might be paused when the new information arrived). Note that it is not possible to use CallSub to access subs of a Code module. Examples: Downloading a file using a service module Periodically checking Twitter feeds
40
Variables & Objects Types Basic4android type system is derived directly from Java type system. There are two types of variables: primitives and non-primitives types. Primitives include the numeric types: Byte, Short, Int, Long, Float and Double. Primitives also include: Boolean and Char. List of types with their ranges: http://www.basic4ppc.com/forum/basic...html#post45511 Primitive types are always passed by value to other subs or when assigned to other variables. For example: Code: Sub S1 Dim A As Int A = 12 S2(A) Log(A) 'Prints 12 End Sub Sub S2(B As Int) B = 45 End Sub
All other types, including arrays of primitives types and strings are categorized as nonprimitive types. When you pass a non-primitive to a sub or when you assign it to a different variable, a copy of the reference is passed. This means that the data itself isn't duplicated. It is slightly different than passing by reference as you cannot change the reference of the original variable. All types can be treated as Objects. Collections like lists and maps work with Objects and therefore can store any value. Here is an example of a common mistake, where the developer tries to add several arrays to a list: Code: Dim arr(3) As Int Dim List1 As List List1.Initialize For i = 1 To 5 arr(0) = i * 2 arr(1) = i * 2 arr(2) = i * 2
41
List1.Add(arr) 'Add the whole array as a single item Next arr = List1.Get(0) 'get the first item from the list Log(arr(0)) 'What will be printed here???
You may expect it to print 2. However it will print 10. We have created a single array and added 5 references of this array to the list. The values in the single array are the values set in the last iteration. To fix this we need to create a new array each iteration. This is done by calling Dim each iteration: Code: Dim arr(3) As Int 'This call is redundant in this case. Dim List1 As List List1.Initialize For i = 1 To 5 Dim arr(3) As Int arr(0) = i * 2 arr(1) = i * 2 arr(2) = i * 2 List1.Add(arr) 'Add the whole array as a single item Next arr = List1.Get(0) 'get the first item from the list Log(arr(0)) 'Will print 2
Tip: You can use agraham's CollectionsExtra library to copy an array. Casting Basic4android casts types automatically as needed. It also converts numbers to strings and vice versa automatically. In many cases you need to explicitly cast an Object to a specific type. This can be done by assigning the Object to a variable of the required type. For example, Sender keyword returns an Object which is the object that raised the event. The following code changes the color of the pressed button. Note that there are multiple buttons that share the same event sub. Code: Sub Globals Dim Btn1, Btn2, Btn3 As Button End Sub Sub Activity_Create(FirstTime As Boolean) Btn1.Initialize("Btn") Btn2.Initialize("Btn") Btn3.Initialize("Btn") Activity.AddView(Btn1, 10dip, 10dip, 200dip, 50dip) Activity.AddView(Btn2, 10dip, 70dip, 200dip, 50dip) Activity.AddView(Btn3, 10dip, 130dip, 200dip, 50dip)
42
End Sub Sub Btn_Click Dim b As Button b = Sender 'Cast the Object to Button b.Color = Colors.RGB(Rnd(0, 255), Rnd(0, 255), Rnd(0, 255)) End Sub
The above code could also be written more elegantly: Code: Sub Globals End Sub Sub Activity_Create(FirstTime As Boolean) For i = 0 To 9 'create 10 buttons Dim Btn As Button Btn.Initialize("Btn") Activity.AddView(Btn, 10dip, 10dip + 60dip * i, 200dip, 50dip) Next End Sub Sub Btn_Click Dim b As Button b = Sender b.Color = Colors.RGB(Rnd(0, 255), Rnd(0, 255), Rnd(0, 255)) End Sub
Scope Variables that are declared in Sub Globals or Sub Process_Globals are global and can be accessed from all subs. Other variables are local and can only be accessed from the sub that they are declared in. See the Activity lifecycle tutorial for more information about Globals vs. Process_Globals variables. Tips All views types can be treated as Views. This allows you to change the common properties of views easily. For example, the following code disables all views that are direct children of the activity: Code: For i = 0 To Activity.NumberOfViews - 1 Dim v As View v = Activity.GetView(i) v.Enabled = False Next
If we only want to disable buttons: 43
Code: For i = 0 To Activity.NumberOfViews - 1 Dim v As View v = Activity.GetView(i) If v Is Button Then 'check whether it is a Button v.Enabled = False End If Next
The Type keyword allows you to create your own type of objects. Custom types behave exactly like other non-primitive types.
44
Currency Converter – libraries, file manager and other important concepts In this tutorial we will use the following web service to convert currencies: http://www.webservicex.net/CurrencyC...ToCurrency=EUR
There are several important aspects in this application. This tutorial will only briefly touch each topic. Files You can add files to your project using the Files tab:
45
In our case we have two file. CountryCodes.txt is a text file containing the list of currencies. Each line contains exactly one value. layout1.bal is the layout file created with the designer. Layout files are added automatically to the file manager. Note that the layout file contains another two image files, the buttons arrows. These files are listed in the designer. If we remove layout1.bal they will be removed from the package as well. The packaged files are also named assets. Locally they are stored under the Files sub folder. This code reads the text file and stores the data in a list: Code: If FirstTime Then countries = File.ReadList(File.DirAssets, "CountryCodes.txt")
File.ReadList is a convenient method that opens a file and adds all its lines to a List. Files are always referenced by their folder and name. The assets are referenced by the File.DirAssets value. Android file system is case sensitive. Which means that image1.jpg is not the same as Image1.jpg (unlike Windows file system). Structures You can create new types or structures using the Type keyword. Later you can declare variables of these new types. Types can hold any other objects, including other types and including themselves (and including arrays of all of these). Structures will be covered more deeply in a different tutorial... Structures are declared in one of the global subs. Code: Type MyTag (FromValue As EditText, ToValue As EditText, _ FromCurrency As Spinner, ToCurrency As Spinner) Dim CurrentTask As MyTag
This code declares a type that holds two EditTexts (textboxes) and two Spinners (Comboboxes). We also declare a variable of that type named CurrentTask. In the code you will see that we have another type named StateType which we use to store the current state. All views have a property named Tag. You can set this property to any object you like. We are using it together with the Sender keyword to handle both buttons with the same sub.
46
Libraries
As you can see in the image, the Libraries tab page shows a list of available libraries. The checked libraries are referenced. Note that you cannot remove the reference to the core library. Adding additional libraries Libraries are made of a pair of files. The xml file that describes the library and the jar file which holds the compiled code. Additional libraries and updates to official libraries are available here: http://www.basic4ppc.com/forum/addit...icial-updates/ Note that only users who bought Basic4android can download these libraries. To add a library to Basic4android all you need to do is to copy both files to a folder recognized by Basic4android. By default this is the 'Libraries' folder that is usually located in: c:\Program Files\Anywhere Software\Basic4android\Libraries. You can also configure an additional libraries folder by choosing Tools - Configure Paths. Note that the additional folder is scanned first for libraries. This means that you can update an existing library by putting the new files in the additional libraries folder (there is no need to delete the old files from the internal folder). Http library The Http library includes three objects. HttpClient - This is the main object that executes and manages the requests and responses. The HttpClient can execute multiple requests concurrently. It is very important to declare it as a Process global. The HttpClient handles requests that run in the background and it should not be tied to the activity life cycle. Communication is done in two steps. First a connection is established by sending a HttpRequest object and then the response is read from the server. The first step is always a non blocking action. It can take a long period till the connection 47
is established and you do not want to make your application be non-responsive at this time. Note that Android has a special "Application not responding" dialog which allows the user to force close the application. The second step, which is the consumption of the response can be either blocking or nonblocking. If you download a file for example you should probably choose the nonblocking option. This code creates and sends the GET request. Code: Dim request As HttpRequest request.InitializeGet(URL & fromCountry & "&ToCurrency=" & toCountry) request.Timeout = 10000 'set timeout to 10 seconds If HttpClient1.Execute(request, 1) = False Then Return 'Will be false if their is already a running task (with the same id).
We are setting the timeout to 10 seconds which is quite short. The default is 30 seconds. The target web service is pretty unstable, which makes things more interesting. I prefer it to fail fast in our case. HttpClient.Execute method receives two parameters. The first is the request object and the second is the Task ID. This integer will be passed back in the ResponseSuccess or ResponseError events. It allows you to differentiate between different tasks that may be running in the background. HttpClient.Execute will return false if their is already a running task with the same ID. This helps you prevent unnecessary multiple requests. You can also check the status of running tasks with the IsBackgroundTaskRunning keyword. Once the response is ready, ResponseSuccess or ResponseError will be raised. If things went well, we can now read the response, find the rate and display it. Otherwise we display a "toast" message with the error message. As I wrote above, this specific web service seems to be unstable so your experience may vary. State As discussed in the life cycle tutorial we are required to save and restore the state of the application. In our case the state is made of the values in the text boxes and the current selected currencies.
48
The following type and variable are declared in Sub Process_Globals: Code: Type StateType (TextUp As String, TextDown As String, _ IndexUp As Int, IndexDown As Int) Dim State As StateType 'This must be a process variable as it stores the state 'and should not be released when the activity is destroyed.
On the first run we set its values with the default values we want: Code: Sub ResetState 'set the starting state State.TextUp = 1 State.TextDown = "" State.IndexUp = 0 'USD State.IndexDown = 43 'Euro End Sub
Later we save and read it as needed: Code: Sub Activity_Resume txtUp.Text = State.TextUp txtDown.Text = State.TextDown spnrUp.SelectedIndex = State.IndexUp spnrDown.SelectedIndex = State.IndexDown End Sub Sub Activity_Pause (UserClosed As Boolean) If UserClosed Then ResetState 'reset the state to the initial settings. Else State.TextUp = txtUp.Text State.TextDown = txtDown.Text State.IndexUp = spnrUp.SelectedIndex state.IndexDown = spnrDown.SelectedIndex End If End Sub
In Activity_Resume we read the values and set the required views. Note that Activity_Resume is called right after Activity_Create. So it will also be called on the first time we run the application. In Activity_Pause we save the value in the state object (which is a process variable). Note that if the user pressed on the back key (which means that he wants to close our application) we return the state to the initial state. Therefore the user will see a "clean new" application the next time he will run our application.
49
It is worth paying attention to this line: Code: CurrentTask.FromCurrency.SelectedItem.SubString2(0, 3)
CurrentTask is of type MyTag. It has a field named FromCurrency which is of type Spinner. Spinner has a property named SelectedItem which returns a String. String has a method named Substring2. Also note that this code is valid: "abcd".Substring(2) The complete code (file is also attached): Code: 'Activity module Sub Process_Globals Dim countries As List Dim URL As String URL = "http://www.webservicex.net/CurrencyConvertor.asmx/ConversionRate?FromC urrency=" Dim HttpClient1 As HttpClient Type StateType (TextUp As String, TextDown As String, _ IndexUp As Int, IndexDown As Int) Dim State As StateType 'This must be a process variable as it stores the state 'and should not be released when the activity is destroyed. End Sub Sub Globals Dim txtUp, txtDown As EditText Dim spnrUp, spnrDown As Spinner Dim btnUp, btnDown As Button Type MyTag (FromValue As EditText, ToValue As EditText, _ FromCurrency As Spinner, ToCurrency As Spinner) Dim CurrentTask As MyTag End Sub Sub ResetState 'set the starting state State.TextUp = 1 State.TextDown = "" State.IndexUp = 0 'USD State.IndexDown = 43 'Euro End Sub Sub Activity_Create(FirstTime As Boolean) If FirstTime Then Log("************************")
50
'load the list of countries countries = File.ReadList(File.DirAssets, "CountryCodes.txt") 'initialize the HttpClient object which is responsible for all communication. HttpClient1.Initialize("HttpClient1") ResetState End If Activity.LoadLayout("layout1") spnrUp.AddAll(countries) spnrDown.AddAll(countries) Dim t1 As MyTag t1.FromValue = txtUp t1.ToValue = txtDown t1.FromCurrency = spnrUp t1.ToCurrency = spnrDown btnDown.Tag = t1 Dim t2 As MyTag t2.FromValue = txtDown t2.ToValue = txtUp t2.FromCurrency = spnrDown t2.ToCurrency = spnrUp btnUp.Tag = t2 End Sub Sub Activity_Resume txtUp.Text = State.TextUp txtDown.Text = State.TextDown spnrUp.SelectedIndex = State.IndexUp spnrDown.SelectedIndex = State.IndexDown End Sub Sub Activity_Pause (UserClosed As Boolean) If UserClosed Then ResetState 'reset the state to the initial settings. Else State.TextUp = txtUp.Text State.TextDown = txtDown.Text State.IndexUp = spnrUp.SelectedIndex state.IndexDown = spnrDown.SelectedIndex End If End Sub Sub btn_Click Dim btn As Button btn = Sender 'Fetch the actual button that raised this event. CurrentTask = btn.Tag 'Take the object from its Tag property. Dim fromCountry, toCountry As String fromCountry = CurrentTask.FromCurrency.SelectedItem.SubString2(0, 3) 'get the currency code
51
toCountry = CurrentTask.ToCurrency.SelectedItem.SubString2(0, 3) Dim request As HttpRequest request.InitializeGet(URL & fromCountry & "&ToCurrency=" & toCountry) request.Timeout = 10000 'set timeout to 10 seconds If HttpClient1.Execute(request, 1) = False Then Return 'Will be false if their is already a running task (with the same id). ProgressDialogShow("Calling server...") End Sub Sub HttpClient1_ResponseSuccess (Response As HttpResponse, TaskId As Int) Log("ResponseSuccess") ProgressDialogHide Dim result As String result = Response.GetString("UTF8") 'Convert the response to a string Log(result) Dim rate As Double 'Parse the result i = result.IndexOf(".NET/") If i = -1 Then Msgbox("Invalid response.", "Error") Return End If i2 = result.IndexOf2("