Pages

Tuesday, August 26, 2014

Converting VB6 to Android: Die Roller - Basic to Java


We've got the project set up, and we've got a UI ready to go.  So now we need to add some code to the button.  We already have the routine from the last post, but all it does now is log a message.  Now we're going to have that routine actually do some work.


Before we start actually executing code, I want to change the name of the textbox and the output text area (EditText and output TextView).  So go to the UI and click the textbox and change its id.  The top property in the property panel is currently set to @+id/editText1.  Change it to @+id/tbxExpression.  When you do, it will ask you if you want to update all references, so just let it do it.  Now do the same thing with the output TextView, changing it to tbxFinalValue.  Then save the xml file, and build the app.  Under the project menu, if you have "Build Automatically" checked, you can't just build, you have to run.  Or you can just uncheck that and then click "Build All". (It doesn't seem to require that the app be in a state that will compile without errors, it just takes a build to get it to regenerate the "R" object that contains the ids.  Normally, just saving is all it should take, but it seemed to not work at least once, but building did.)

Now, back in the code, at the top of the class, right after our TAG definition, we'll define tbxExpression and tbxFinalValue.  (In VB6, the elements are public, but good practice would be to make them private unless you actually need them public.)
private EditText tbxExpression;
private TextView tbxFinalValue;


At the bottom of the onCreate routine, we will set this variable.  We do that by using findViewById.  This routine is a method on the View.  It takes an ID and returns the appropriate view object.  The IDs are available from the id property of the R class.
tbxExpression = (EditText)findViewById(R.id.tbxExpression);  Another java thing; findViewById returns a "View" but java won't automatically convert it to the "EditText" that we want, even though it really is an "EditText".  Instead of going through CType or some other VB conversion routine, all you have to do is put the expected type in parenthesis.  This is a cast, and simply tells the compiler that the item really is that type.  It doesn't work if the item isn't really that type, as then we would need to use actual conversion code.

Now, we'll add our call from vb6, which is this

           lRoll = DiceEval(tbxExression.Text)

TextView doesn't have a Text property, but has a getText method.  And it returns an object other than String, so you have to convert it to a string.

            lRoll = DiceEval(tbxExpression.getText().toString());


 The rest of the conversion is pretty straightforward.  I've basically done it line-for-line, and placed the code in the MainActivity file.  I've included links to download it and the original.  I'll just touch on some of the main points I ran into.

  1. Java (and c#, and c++, etc) distinguish between an assignment and a logical equal sign.  Assignment is a single equal, and logical is a double.  So "if (x == y) {" is how you compare values.  However, this doesn't work on strings.  In c#, you can, because == is overridden, but it doesn't appear to be in java.  So an == with String (or any other objects) is only comparing references, not values.  So the following code won't work.

  2. String A = "x";
    String B = "x";
    if (A == B) {
       DoSomethingImportant();
    }

    So with String (and again, other objects) you use the "equals" method, as illustrated in the following code segment.

    String A = "x";
    String B = "x";
    if (A.equals(B)) {
       DoSomethingImportant();
    }
  3. Java's syntax for Select is "switch", but it has caveats.  First, it only works with numbers and enumerations, so you have to use nested If statements for strings.  Second, you can't specify ranges, like VB's "Is".  Instead, you have to specify each value.  For large (or even small) ranges, it's probably easier to just use if statements again.
  4. I haven't quite figured this one out.  There isn't a straightforward Val statement to convert a string to a number.  Instead, there are two options per number type.  I chose to use doubles, so the options are either Double.valueOf("someNumber") or Double.parseDouble("someNumber").  valueOf returns a Double, whereas parseDouble returns a double.  Confused yet?  Double with a capital D is an object wrappering a primitive value.  double is the primitive value.  Some online sites state that valueOf will give you better memory use, since it will reuse an existing Double instance if one exists for the same value.  So if you have two strings representing 3, such as "3.0" and "3", and you call Double.valueOf on them, you will get the same instance in both cases, to conserve memory.  However, and I haven't tried this, but I suspect that you'll have issues with changing one value and inadvertently changing another unrelated value that just happens to have come out the same.  parseDouble, however, returns a unique primitive for each execution, which uses more memory (I'm guessing depending on the number of doubles, as an object has some intrinsic overhead).  That's what I chose to use.  It saves me having to worry about shared instances, and I don't like using objects unless I have to, which is as that is a memory conservation method in other languages.  Oh, and this problem also goes the other way.  Since double and such are not objects, they don't have "toString" methods.  So you have to use String.valueOf(doubleVar) instead.





That should be it for now.  After you look at the files, if there's any conversion that didn't make sense, just let me know and I'll post about it.  And I mean any questions; I only have about 300 hits a month, so it's not like I'm overwhelmed with requests or anything.





No comments:

Post a Comment