Aegidius
 Plüss   Aplulogo
     
 www.aplu.ch      Print Text 
© 2021, V10.4
 
  JDroidLib
 
 

A simplified version of JDroidLib dedicated to Turtle Graphics is available here.

An Education Oriented Java Package
To Develop Apps For Android Smartphones

The JDroidLib Framework

JDroidLib sits on top of the Android Java API and shields programmers from the steep learning curve for creating Android apps. With JDroidLib you may create your first (and not only trivial 'Hello Android') Android app within minutes even if you are a Java beginner. Moreover, with little more effort, you may develop professional game apps in reduced time of an order of magnitude compared to pure Android API programming.

In the current beta version, the screen layout is restricted to game and simulation applications and a console window. More general layouts will be added in the future. The framework for Android programming also includes add-ons for card games and for TCP communications over a firewall-protected internet network.

Because JDroidLib and the TCP add-on has been ported from the corresponding Java SE framework JGameGrid and TcpJLib, the developer may port his code from one platform to the other with very little effort. Consult the website for the SE versions to understand the basic ideas behind JGameGrid and TcpJLib. In order to avoid information duplication, only the most important features of JDroidLib are presented here with a main focus on differences between the SE and Android versions (see also here for a comparison).

The distribution includes a GUI-based Java application ProjectBuilder that adapts the default Android project for Eclipse or Netbeans automatically and seamlessly to the requirements of the JDroidLib framework. A command line version AndroidBuilder creates the entire project and can be used for simpler Java-IDEs like JCreator or BlueJ (see Installation Guide for details).

(JDroidLib and the SE version JGameGrid are based on the well-known educational framework Greenfoot, so Greenfoot applications may be easily ported to Android smartphones.)

 

Design Principle Explained By Two Examples

The JDroidLib application class is always extended from the class GameGrid which provides a rich collection of methods. Unlike SE applications the entry point of Android applications is not the standard public static main() method. With standard Android apps, the Android application class is normally extended from the class Activity, which corresponds roughly to certain screen layout. Because GameGrid extends from Activity, the JDroidLib application class is-a Activity too and inherits all public and protected methods from Activity.

To shield the programmer from the different states of the Activity life-cycle, an internal thread, called the main-thread, executes when the JDroidLib application is installed and started on the smartphone. The thread runs a method void main() of the GameGrid class. By overriding this method, the JDroidLib apps programmer obtains his entry point. The drawback of this simple trick is that the Android environment (the application context including the screen properties) is not properly initialized until main() executes. So performing actions that uses the context during instance variables initilizalizing in the application class or performing context dependent API calls in the application class constructor causes the application to crash. The workaround is simple: If you need application wide Android or JDroidLib class references, you may declare them in the application class header, but assign them in the main() method.

To avoid hanging applications when the smartphone changes states (by pressing the home key, by incoming phone calls, etc.) the Linux process and so the Dalvik virtual machine is killed when the state changes (unless the onPause() notification method is overridden). This may appear to be a brute force termination, but it protects the unsuspecting developer from eventually time and money consuming background processes.

There is no way to develop computer games on the API level without thorough knowledge of threading. But unfortunately mastering concurrent processing is hard to achieve. Because the JDroidLib framework uses two internal threads, one that executes main() and one the runs the game animation loop, even a Java beginner without any knowledge of threads may develop professional computer games and graphics simulations in a snap. The drawback is that with JDroidLib you are somewhat restricted for other application types than gaming and simulation. Because we are aware of this restriction, we will add support for non-gaming applications in the future.

To give you an idea how simple it is to write your first, but non-trivial Android app, let's draw the famous Moire pattern by animation (not only presenting the resulting graphics). The code makes use of the GGPanel user-definable double coordinate system and is identical to the SE version (using a different library import).

package ch.aplu.ex;

import ch.aplu.android.*;

public class Moire extends GameGrid
{
  public void main()
  {
    GGPanel p = getPanel();
    p.window(0, 10, 0, 10);
    int i, k;
    for (i = 0; i <= 10; i++)
    {
      for (k = 0; k <= 10; k++)
        p.line(i, 0, k, 10);
    }

    for (i = 0; i <= 10; i++)
    {
      for (k = 0; k <= 10; k++)
        p.line(0, i, 10, k);
    }
  }
}

Download Android app for installation on a smartphone or emulator.
Download
sources (Moire.zip).
Create QR code to download Android app to your smartphone.
Install/Start
app on a USB connected smartphone or a running emulator.

(This is a WebStart signed by the University of Berne, Switzerland. It installs some helper files in <userhome>.jdroidtools.If you did not install the Android SDK, you may install a slim version of the Android-Emulator in <userhome>.jdroidemul using this link, To start the emulator, execute ExecEmul.jar found in <userhome>.jdroidemul)
Download app via Bluetooth using DroidInstall app.
(This is a WebStart signed by the University of Berne, Switzerland. It starts a Java Bluetooth client application ApkBlueInstaller that connects to a Android Bluetooth server DroidInstall that must be started on the smartphone. Click here to get the DroidInstall app.)

  jdroidlib1


 

(You may change the smartphone's orientation to restart the app automatically.)

By putting your code in the main() procedure and calling user defined private methods, it's up to the teacher to introduce into procedural programming like in good all days with Basic or Pascal without any knowledge of OOP and event state handling. But, because all is pure Java, he/she has the choice to use a modern OOP program design by declaring classes and overriding methods that will be called by polymorphism.

GGPanel let you introduce gently into programming using a device independent double coordinate system. In the next example we show you how to create a full-fledged game app for Android smartphones with a fraction of the code compared to pure Android API programming. Moreover no Android specific knowledge is necessary. Using the grid design of Greenfoot and the Java SE JGameGrid version, we override the class Actor and put the code for the actor's animation into the overridden act() method that is periodically called by the animation thread. Actors are actually animated sprites and their sprite image are packed into the app resources by the ProjectBuilder. The images are loaded at runtime from the Android Application Package (.apk). This default can be changed to load the images from the smartphone's SD card just by specifying the full image file path. Let's see the code of class Fish:

 

package ch.aplu.catchfish;

import ch.aplu.android.*;

class Fish extends Actor implements GGNavigationListener
{
  public Fish()
  {
    super("nemo");
  }

  public void act()
  {
    move();
    if (getX() == 9)
    {
      turn(180);
      setHorzMirror(true);
    }
    if (getX() == 0)
    {
      turn(180);
      setHorzMirror(false);
    }
  }
  
  public void navigationEvent(GGNavigationEvent event)
  {
    if (isRemoved())
      return;
    switch (event)
    {
      case MENU_DOWN:
        setY(getY() + 1);
        break;
      
      case BACK_DOWN:
        setY(getY() - 1);
        break;
    }  
  }  
}

 

By implementing a GGNavigationListener we get notifications when the smartphone's button are manipulated, in this case we want to move the actor up and down using the MENU and BACK buttons. In our game a shark tries to catch the Nemo fish and eat it, so Shark is an actor too. The game challenge is to move nemo to a different sea level to escape from the shark.

package ch.aplu.catchfish;

import ch.aplu.android.*;

class Shark extends Actor
{
  private Fish nemo;

  public Shark(Fish nemo)
  {
    super(true"shark"2); // Two sprite images
    this.nemo = nemo;
  }

  public void act()
  {
    if (nemo != null && nbCycles % == 0)
    {
      setDirection(getLocation().
            getCompassDirectionTo(nemo.getLocation()));
      move();
    }
    Actor aNemo = gameGrid.getOneActorAt(getLocation(), Fish.class);
    if (aNemo != null)
    {  
      aNemo.removeSelf();
      show(1);
      nemo = null;
    }  
  }

The shark has two associated sprite images shark_0.gif and shark_1.gif in order to get fat when he swallows the fish. He tracks the fish by looking at the fish's current location. Then he swims in the corresponding direction. In each grid location he reclaims the actors of the class Fish present there. getOneActorAt() returns a reference to the unfortunate nemo and the nemo is removed.

Finally we write the application class CatchFish derived from GameGrid. (In this example we follow the bottom-up paradigm that was rejected in former days of structural programming, but that is much more intuitive and motivating.) The constructor initializes the visible grid with 10 horizontal and 10 verticals cells and the cell size automatically adjusted to fit to the current smartphone screen size. All other actions are executed in the entry point method main() that is executed when the app activity starts. main() creates the fish and the shark and starts the simulation cycling by calling doRun():

package ch.aplu.catchfish;

import ch.aplu.android.*;
import android.graphics.*;

public class CatchFish extends GameGrid
{
  public CatchFish()
  {
    super(10, 10, 0, Color.RED);
  }

  public void main()
  {
    Fish nemo = new Fish();
    addActor(nemo, new Location(0, 1));
    addNavigationListener(nemo);
    Shark shark = new Shark(nemo);
    addActor(shark, new Location(7, 9));
    doRun();
  }
}

It is easy to change the game design, for instance by changing the swimming strategy of the shark, or to make the shark more and more aggressive while the game is in progress. To include a game score, the life time of nemo can we displayed using showToast(). In the following figures we show the starting and final game situations.

  shark0   shark1
 
Initial situation
 
Final situation

Download Android app for installation on a smartphone or emulator.
Download sources (CatchFish.zip).
Create QR code to download Android app to your smartphone.
Install/Start app on a USB connected smartphone or a running emulator.
(This is a WebStart signed by the University of Berne, Switzerland. It installs some helper files in <userhome>.jdroidtools.If you did not install the Android SDK, you may install a slim version of the Android-Emulator in <userhome>.jdroidemul using this link, To start the emulator, execute ExecEmul.jar found in <userhome>.jdroidemul)
Download app via Bluetooth using DroidInstall app.
(This is a WebStart signed by the University of Berne, Switzerland. It starts a Java Bluetooth client application ApkBlueInstaller that connects to a Android Bluetooth server DroidInstall that must be started on the smartphone. Click here to get the DroidInstall app.)

(You may change the smartphone's orientation to restart the app automatically.)

Included in the JDroidLib distribution you find the GUI-based application ProjectBuilder.jar and its command line version AndoidBuilder.jar. These helper applications liberate you from the burden of preparing the Android project yourself which requires detailed knowledge of how to write the AndroidManifest.xml and how to create layouts and resources. In short, with JDroidLib you may develop even an advanced game or simulation app without any special knowledge of the Android environment nor the Android API.

projectbuilder

In details the ProjectBuilder performs the following tasks:

  • Creates a AndroidManifest.xml adapted to JDroidLib apps; adds internet permission, if Use Internet is checked
  • Copies a new build.xml in <projectroot> and with given <App Name>
  • Creates/replaces project.properties containing target=android-8
  • Replaces <projectroot>\res\layout\main.xml
  • Creates some layout resources in <projectroot>\res\layout
  • Replaces <projectroot>\res\values\strings.xml
  • Creates a template source file <projectroot>\src\<packagepath>\<ApplicationName>.java
  • Copies the library files in <projectroot>\libs
  • Copies all files from <Sprites Folder> in <projectroot>\res\drawable
  • Copies all files from <Media Folder> in <projectroot>\res\raw
  • Copies jdroid_logo.png and jdroid_gglogo.png in <projectroot>\res\drawable

 

Debugging Android Apps

Every programmer makes mistakes; programming errors are unavoidable even for the most experienced and skilled programmer. What makes a good programmer is not so much to avoid errors but how long it takes him to find and fix them. Because programming errors are called bugs, the hunting for bugs is called debugging. Unfortunately debugging techniques and tricks are not trained as much it should be in programming courses, maybe because bugs are considered harmful animals caused by bad programmers. This is definitely wrong.

To help you debugging Android apps, the Android developers created a powerful utitlity that monitors about everything what happens on your smartphone. All this information is stored in a log file that may be transferred to the development system by calling

adb logcat

Enter a command shell, type this command and you are cluttered by what you see. But what is important for you, you can write your own entries into the log file using the android.util.Log class and retrieve them exclusively by providing a filter string tag argument when calling adb logcat. To simplify your life, JDroidLib includes the class ch.aplu.android.L that uses the predefined filter tag ch.aplu.android. The use is very easy: Whenever you want to make an entry in the log file, insert L.i() with a string parameter that will be displayed in the log file. For instance if you want to check, whether and when a method is called you add a L.i() as first statement in your method (eventually by adding some actual parameter values). To find out where your program crashes, add some L.i("okN") (N = 0, 1, 2,...) at different places in your program. Because adb logcat writes the data into a OS command shell, the presentation is not very GUI friendly. We provide (for Windows OS at the moment) a GUI wrapper called LogCat.jar that redirects the output to a standard Java text area with scrollbars and the potential to use copy/paste to transfer marked output to an external text editor file for further examination. The command line parameter of LogCat is the filter tag of the adb logcat call. One of the most important filter is *:S ch.aplu.android:V that restricts output to the L.i() calls. If you want to show runtime errors too, especially null pointer exceptions, use the filter *:S AndroidRuntime:E ch.aplu.android:V. By default the JDroidLib code writes some informational messages into the log file. Let's see what happens for the following obviously faulty program that compiles gently but crashes at runtime because the loc reference is null.

package ch.aplu.ex;

import ch.aplu.android.*;
import android.graphics.*;

public class Buggy extends GameGrid
{
  private Location loc;
  
  public Buggy()
  {
    super(10, 10, 0, Color.RED);
  }

  public void main()
  {
    Actor nemo = new Actor("nemo");
    addActor(nemo, loc);
  }
}

 

As you see in the following log, the null pointer exception is caught and reported by JDroidLib. (LogCat.jar started with java -jar LogCat.jar "*:S AndroidRuntime:E ch.aplu.android:V")

jdroidbug

If you add the line L.i() in main()

public void main()
  {
    Actor nemo =
 new Actor("nemo");
    L.i("loc = "
 + loc);
    addActor(nemo, loc);
  }

you find in the LogCat window, as espected:

...
loc = null
Calling addActor()
java.lang.NullPointerException
...

(LogCat.jar is included in the JDroidLib distribution. But you may run it as WebStart from here (an Android device must be attached to the USB port or the simulator must be running).

 

Programming Smartphones in Schools

For many years my aim was to make computer programming easy and I tried to convince teachers and politicians that fundamental knowledge of computer sciences should be part of the general knowledge of everyone like math, physics and natural science. In my opinion programming concepts should be taught in all types and levels of educational institutions, from primary school to university. With the new family of smartphones, hundred of millions of people will have their full-fledge computer right in the pocket. Hal Abelson, professor at MIT, writes in a blog:

"Mobile applications are triggering a fundamental shift in the way people experience computing and use mobile phones. Ten years ago, people "went to the computer" to perform tasks and access the Internet, and they used a cell phone only to make calls. Today, smartphones let us carry computing with us, have become central to servicing our communication and information needs, and have made the web part of all that we do. Ten years ago, people's use of computing was largely dissociated from real life. With the ubiquity of social networking, online and offline life are becoming fused."

Abelson participates in the development of a simple education environment for programming Android smartphones, called Android App Inventor borrowed heavily from Scratch. But unfortunately the future of Android App Inventor at Google is discontinued because Google reorganizes Goggle Labs, where major parts of Android App Inventor were developed (see article by Audrey Watters). The good news is Android App Inventor has found a new home at the MIT Media Lab.

Like Android App Inventor the framework JDroidLib is inspired by bringing Android Apps programming in schools. Compared to other educational programming activities, App programming is very motivating because students feel the smartphone like a "real" device. Our teaching concept is based on years of positive experience to use a wide-spread high-level programming language but adding some smart, but powerful libraries and frameworks right from the beginning (following Bertrand Meyer's idea of the Inverted Curriculum). Using JDroidLib accompanied with some development tools right out of the box like the Online-Editor and the ProjectBuilder, creating Android Apps is open to everyone. (To load your own sprite images when using the Online-Editor, copy the image files in any subdirectory on the SD card, e.g. folder 'sprites', and use a qualified filename in the Actor constructor like "sprites/image.png").