BlubberPatrol for Android Released

I wrote a “practice app” to learn Android development. It’s called BlubberPatrol and it’s for tracking & charting your weight. It turned out to be quite a nice little app, and is free in the Google Play store. Read more on the BlubberPatrol home page.

I chose this app because I thought it would be easy. If I were writing a desktop version in Realbasic, it would have been a walk in the park. But I wrote it in Java with the Android SDK and the Eclipse IDE, and it was like walking over hot coals by comparison. It probably took me 100 times longer than I had expected. If I do another Android app, I will look at using something like Basic4android. Once you are spoiled by a Rapid Application Development (RAD) tool like Realbasic, it’s hard to go back to “real” programming.

Now I have to learn about Google Play store marketing. It’s a very crowded place. Getting an app into Google Play or the App Store is like putting a needle into a haystack – you might not ever find it again yourself! Actually, I think I might just skip to the Samsung store – I hear developers are getting a lot more downloads there.

And yes, ensuring that your app will run on the thousands of different Android phones and tablets out there is a major pain. I probably spent way more time testing on the Android emulator than I did coding. It’s a horror scene, and will take your eyes.

How to Update the Android GUI From a Timer

If you found this post via a Google search, chances are that your Android app just crashed after you added an innocent-looking timer. You probably got this error:

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

You may have also found people saying that you can’t use a timer to update the GUI. Seems odd, right? Why would Google make a timer and then not let you use it for hardly anything?

Well, those people are wrong. While you can’t update the GUI directly from your timer, you can do so with a few little tweaks.

The error above happens because Android doesn’t want other threads, such as your timer, messing with its GUI. So, what you need to do is politely ask Android to make the update for you. To do that, you need to add a handler and a runnable. Android will monitor the handler for a signal from your timer. When it gets the signal, it will run the code in the runnable. It sounds complicated, but it amounts to only a few lines of code.

First, move the code that updates the GUI out of your timer and into a runnable. A runnable is a mechanism where one thread can tell another thread to run a block of code. In this example, there is one line of code which sets the TextView tv to the value of the global variable i:

final Runnable myRunnable = new Runnable() {
   public void run() {
      tv.setText(String.valueOf(i));
   }
};

Creating a handler is very simple:

final Handler myHandler = new Handler();

And in the timer, we pass the runnable to the handler:

private void UpdateGUI() {
   i++;
   //tv.setText(String.valueOf(i)); //This causes a runtime error.
   myHandler.post(myRunnable);
}

As an example, I took the Android “Hello World” app, and modified it into a counter that updates once per second:

public class HelloActivity extends Activity {
   int i=0;
   TextView tv;
   final Handler myHandler = new Handler();

   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);

      tv=(TextView) findViewById(R.id.tv1);

      Timer myTimer = new Timer();
      myTimer.schedule(new TimerTask() {
         @Override
         public void run() {UpdateGUI();}
      }, 0, 1000);

   }

   private void UpdateGUI() {
      i++;
      //tv.setText(String.valueOf(i));
      myHandler.post(myRunnable);
   }

   final Runnable myRunnable = new Runnable() {
      public void run() {
         tv.setText(String.valueOf(i));
      }
   };
}

Cloud Schmoud

Oracle CEO Larry Ellison mocks “cloud computing” and rightly so:

In my control panel for trivisonno.com, there is a link for cloud computing. When I clicked on it, it took me to a set-up screen for virtual machines. OK, I suppose you can call a virtual machine a cloud if you want, but virtual machines are nothing new. I saw my first VM over 20 years ago. It ran Windows on the Macintosh – very, very slowly.

How to Get Comments onto Pages in WordPress’s Default Theme

As you may have noticed, if you use WordPress’s default theme, “Kubrick”, the comments form does not show up on pages even when you have the option switched-on for a page. I regard this as a theme bug. I fixed it by adding the PHP call to WordPress’s comments function to the bottom of the page.php file.

I did this with WordPress v2.3.3, and have no idea if it will work with other versions. Be careful when editing theme files. Make sure to download a copy of the file first with your FTP program so that you can upload it again if something goes wrong. If you blow up your blog, it’s not my fault.

Steps:

  1. Go to your admin panel
  2. Click Presentation
  3. Click Theme Editor
  4. Make sure that “WordPress Default” is selected
  5. Click the “Page Template” link
  6. Make sure that you are editing “page.php”
  7. Find this line near the bottom: <?php endwhile; endif; ?>
  8. Right below it, enter this: <?php comments_template(); ?>
  9. That tells WordPress to add the comments form.
  10. This is code, so each and every character must be typed exactly.

I don’t have a lot of comments on this site, so this hasn’t been battle tested. Let me know how it works for you.

SDB File Extension Warning

Bottom line: Windows thinks that files using the .sdb extension are registry patch files, and during a system restore, will roll them back to previous versions.

Many applications use the SQLite database engine, and a good number of them use the .sdb extension for the database files that they create. This is fine on the Mac, iPhone, and Linux, but definitely not a good idea on Windows. If your system crashes, and Windows forces you to do a system restore, you might lose important data. Windows thinks that your .sdb files may have been responsible for damaging the registry and tries to return your system to its previous state by rolling back the files to previous versions.

For example, if you have a customer-database program that you update throughout the day, Windows will replace it with a copy that it has stored in the most-recent restore point. Having a back-up copy of your database won’t help unless you make copies throughout the day.

Another consequence is that if you have many large database files, Windows will use up more time and space for restore points. Windows appears to scan your system, and make copies of any file that ends in .sdb, regardless of whether or not it was used to modify the registry. If Windows puts a lot of large database files into its restore points, they will take up more of the allocated space, and you will have fewer restore points. When you have to do a system restore, you want to have a few restore points to choose from.

Search your system for all files that end in .sdb. If you find anything that looks important, make a back-up copy of it every time you update it. You should also complain to the software company, and request a new version of the software that evades the problem. A programmer can fix this problem pretty easily. Nothing more than choosing a new file extension is required. While there is no “official” extension that I know of, I think .sqlite is reasonable. I use .rsd, but only because that’s what the REALbasic language likes.

I learned this .sdb hazard the hard way after a power outage. When my Vista Ultimate system started-up, Windows insisted on doing a system restore. It re-assured me that my data would not be harmed. So, I clicked the OK button, and soon realized that Windows was lying. It most certainly did harm my data. Each of my SQLite database files was missing recent updates, while my other files were fine.

I googled around and didn’t find mention of this problem elsewhere, so I am claiming to be the originator.