Followers

Monday 13 December 2010

String.format is a nono...


Flattr this


I have been working this weekend on an application called "WiFi Wraith" (Already on the market, there's a free edition too).

This is the first time I am working on cavases, bitmaps and programmatic drawing. I draw pretty graphs straight on some UI elemts, which I have a ListView full of. This is done each time the app rescans the networks.
I realized quite fast, that I am doing something silly with my drawing, or so I thought, because the ListView got kinda jittery while dragging. My first obvious idea was to offload the graph drawing to another thread, cache the bitmaps and fetch the "latest" bitmap whenever it is needed.
However, out of curiosity, I also wanted to know how to do profiling on Android! So a quick googling told me that the Android team has made it pretty damn easy!
Only thing I need to do is to call Debug.startMethodTracing() when I want to start logging and Debug.stopMethodTracing() when I want to stop it. Then I can visually inspect the produced logfile by pulling it from the root of the sdcard and use 'traceview' from the android-sdk/tools/.

So, I tried this. My first suspectible suspects of suspicion were these:


Suspect  #1:

private static void drawData(Canvas canvas, List signalHistory) {
 float prevx, prevy;
 float w = canvas.getWidth();
 float linelen = (float) Math.ceil(w/signalHistory.size());
 prevx = prevy = 0f;
 float xpoint = 0f;
 boolean first = true;
 int datanum = 0;
 for(Integer ia : signalHistory) {
  datanum++;
  int q = WifiManager.calculateSignalLevel(ia, 10); 
  float ypoint = canvas.getHeight();
  ypoint = ypoint - ypoint / 10 * q;
  if(ypoint < 1) ypoint = 1;
  Paint p = selectBrush(q);
  if(first) {
   first = false;
   prevx = xpoint;
   prevy = ypoint;
  }
  xpoint += linelen;
  canvas.drawLine(prevx, prevy, xpoint, ypoint, p);
  int makeline = datanum % 10; 
  if(makeline == 0) {
   canvas.drawLine(xpoint, canvas.getHeight(), xpoint, ypoint, PaintManager.red); 
  }
  prevx = xpoint;
  prevy = ypoint;
 }
}

Suspect  #2:

if(signalHistory.size() > 100) {
 signalHistory = new ArrayList(signalHistory.subList(signalHistory.size()-100, signalHistory.size()));
}

Sooo.... Let's fire up traceview and see which one of these is the culprit!

Wait! What the hell! It seems that neither of them!
Drawing takes 10% of time. Resizing of the signalHistory takes pretty much nothing at all...

Most of the time the program is doing this:

if(lastSeen < System.currentTimeMillis() - 10000) {
 Date d = new Date(lastSeen);
 String tstr = DateFormat.getDateTimeInstance().format(d);
 out = String.format(ctx.getString(R.string.item_format_oor), 
   data.SSID, data.BSSID, tstr, locstr);
}
else {
 out = String.format(ctx.getString(R.string.item_format), 
   data.SSID, data.BSSID, data.level, data.frequency, 
   data.capabilities, locstr);   
}

The bloody String.format is killing my app! I just have to try if this really can be the problem, so I'll just comment out the string formatting...

Well, yeah. It made it hell of a lot smoother. Another thing that seems to take a lot of time is populating the list with new items. I have no idea how to side step that.
In fact, I'm not sure how to fix the string formatting. It's kinda crucial for an app to actually show some meaningful info. I recall from some old Android statistics that creating objects is very slow on Android, so I try to avoid it. Based on the old stats, I think concatenating assload of strings and manually converting items to strings should be even slower.

Update: Holy hell! Just concatenating the stings with stupid string + int + float + string, etc... Is faster by about factor of 100!

Thursday 18 November 2010

Handler Puzzle

I was making a small update to MagicPlayer and stumbled upon this puzzling way of handling concurrency.

Can you figure out what it does? (Some irrelevant code snipped)

Class: TracData



public class TrackData extends Handler {
String artist, album, track;
CallBack cb;
Context ctx;
public TrackData(Context ctx, CallBack cb) {
this.ctx = ctx;
this.cb = cb;
}

@Override
public void handleMessage(Message msg) {
if(msg.what == 1) {
cb.setData(this.artist, this.album, this.track);
}
}

public void get(final int sid) {
new Thread() {
public void run() {
TalkWithTheServer();
obtainMessage(1).sendToTarget();
}
}.start();
}

interface CallBack {
public void setData(String artist, String album, String track);
}
}


And another Class: TrackInfo



public class TrackInfo extends Activity implements TrackData.CallBack {
TextView txtArtist;
TextView txtAlbum;
TextView txtTrack;
@Override
public void onCreate(Bundle savedInstanceState) {
SetupStuff();
fetchData(id_of_song_that_is_playing);
}

private void fetchData(int sid) {
TrackData d = new TrackData(this, this);
d.get(sid);
}

@Override
public void setData(String artist, String album, String track) {
txtArtist.setText(artist);
txtAlbum.setText(album);
txtTrack.setText(track);
}
}



!!!!!SPOILER!!!!!


TrackData is background fetcher which gets some data from my server and upon receiving it, updates the text fields in the UI. It looks a bit weird, but I figured this was clean way of doing it with as little code as possible.

TrackInfo is just an Activity with some fields for the returned data. It implements the TracData's inner interface to receive the data when TrackData has done talking.

How to handle handlers?


Flattr this


One of the first problems I encountered with Android, was that it crashed when I tried to interact with UI components from a thread!
I haven't managed to dig into why exactly it was designed this way, but there is only one "UI Thread" per application which is allowed to modify UI components.

So, the question is, what to do when you want to do a long running action in background and let the user know what is going on?

Introducing: Handler

Handler is a component which allows you to create messages from other threads and receive them in the UI thread.
Let's get familiar with it through a common example: ProgressBar

Very straightforward way to use this, is to create an inner class or anonymous instance and override the handleMessage function. However, this is also a quick way to bloat up your activity class and make it unreadable.

So, my way of using it is as so:
1. Create a Handler which get a reference to the bar we want to update:


package net.fizzl.example;

import android.os.Handler;
import android.os.Message;
import android.widget.ProgressBar;

public class FooHandler extends Handler {
private ProgressBar pbar;
public FooHandler(ProgressBar pbar) {
this.pbar = pbar;
}

@Override
public void handleMessage(Message msg) {
if(msg.what == MSG_PROGRESS) {
pbar.setProgress(msg.arg1);
}
}

// Message Names
public static final int MSG_PROGRESS = 1;
}

2. Create a Thread that gets a reference to the handler.


package net.fizzl.example;

import android.os.Handler;
import android.os.Message;

public class FooThread extends Thread {
private Handler h;
public FooThread(Handler h) {
this.h = h;
}

public void run() {
while(dostuff) {
int progress = dostuff();
Message msg = h.obtainMessage(FooHandler.MSG_PROGRESS, progress, 0);
msg.sendToTarget();
}
}
}

3. Use these in your Activity:


ProgressBar pb = findViewById(R.id.theprogressbar);
FooHandler h = new FooHandler(pb);
FooThread t = new FooThread(h);
t.start();
4. Profit!

That's about it. This ofcourse assumes your actual ProgressBar has been set up beforehand to work with the expectations of the thread that sends messages to it.

What happens here, is like so:
1. Thread starts running. It gets progress from its internal function that "does stuff".
2. Thread asks the Handler to give it a prepared message with 'what' set to the value that indicates that it should update the status bar.
3. Thread sends the message.
4. Handler adds the message to its queue.
5. When Handlers message pump is called in the UI Thread, it finds the message and executes its handleMessage.
6. Now that we are running in UI Thread, we can safely call the ProgressBars setProgress.
UI Thread redraws stuff etc. Thread keeps on running and posting messages.


Anyway, I hope you enjoyed this write up and can make a bit more responsive UI's from now on!


Magic Player

Just a brief plug before I'll write the actual article.

I have revamped and republished Magic Player.

It is an app which you can use to listen to Jamendo provided music.

I hold a complete index of Jamendo songs on my own server and the application uses my server to get random songs to play.

You may rate the songs. It will save the rating and the time in the song it was rated. Feel free to rate multiple times per song!
Currently the rating data is not used for anything, but I plan to use it in the future to try and select song which are similar to those you have rated highly before. I'll plan to use tags, genres and user cross-comparisons to do this.

So, anyway, give it a try:


Saturday 4 September 2010

File Shredder


Flattr this


Today I'll tell you about "FileShredder", a data wiping tool coded by be.

My motivation for developing this one, was just to learn how to make an application from start to finish and publish it. I did all of the development on the emulator. I had dabbled at Android for a bit, but none of the work was aimed at creating something which I would try to publish.

I tried to think of something so simple I could code in an evening or to, because I tend to have somewhat short attention span. :)
I was actually code complete in one 6 hour session, testing and debugging another 6 hours and publishing took perhaps two hours to figure out.

I'll explain the parts of the program.

Browser



This is the file system browser. It is very rudimentary and ugly, but it serves its purpose just fine. You can browse the whoe file system and select a file. That's it.
Basically, when you start it, it scans the root directory:



private void ScanDir(File f) {
if(!f.getAbsolutePath().equals("/"))
a.add(f.getParentFile().getAbsolutePath());
if(f.isDirectory()) {
File[] files = f.listFiles(new AllFileFilter());
if(files == null) return;
for(int i=0;i<files.length;i++) {
a.add(files[i].getAbsolutePath());
}
}
}

"a" is an ArrayAdapter which server as the adapter for the listview.


Info view

When you click on a file instead of a directory in the previous view, it will launch this activity. It shows information about the file and determines if it can be shred. The application does not not have root permissions to the file system, so there's no way to accidentally the whole system.

If you click Shred, the application will show up a progress dialog and start a background thread to do the actual work. If you mis-click, you pretty much fucked. The file is corrupted pretty much instantaneously.

The worker thread gets a handle to the selected file, determines its size and overwrites it with pseudo-random data. It will try to determine good sized buffer sizes to process the file as fast as possible.

Progress dialog


Now, here I stumbled on some problems. I never did quite read the Android Activity/Intent lifetime documentation properly. Well, I tried but I never understood why they bothered to explain all the boring details so well with pretty diagrams and all :)

I'll explain the causes and fixes in a later blog post, but basically you need to carefully maintain you applications state and response to events such as change in orientation. Many times you do not need to bother, because the default Android behaviour is fine. But with background threads, message handlers and dialogs you might get, ahem, unexpected behaviour :)

Also, I'll promise to tell more about inter thread communication via message handling later. Showing that progress bar is a bit more involved than you might think.

Finally

After the file is shredder, the Activitys buttons are modified acordingly and you may now close the activity. You could also just use the Back button of your device, but I added the button for clarity. I actually might remove it in a later version, because it does not sit well with the Android UI style.

TODO:
Obviously, the file browser could be a lot neater.
It would be nice to be able to shred multiple files at once.
It would be nice to process entire directory trees at once.
However, in my first version I just wanted something I could develop in a day, so I designed accordingly.

QR



Here's a QR tag which you can read with an Android barcode reader. I'm not sure if it works. It would be great if you could report in the comments whether it works for you!

Also, polishing your package for Android Market is a topic of its own. I'll explain the export, key generation and icons later.

Testing code highlighting


/*
* This file is part of Libgdx by Mario Zechner (badlogicgames@gmail.com)
*
* Libgdx is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Libgdx is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libgdx. If not, see .
*/
package com.badlogic.gdx.math;

/**
* Taken from libgdx
* Modified to remove final declaration
*
* Encapsulates a 2D vector. Allows chaining methods by returning a
* reference to itself
* @author badlogicgames@gmail.com
*
*/
public class Vector2
{
/** static temporary vector **/
private final static Vector2 tmp = new Vector2();

/** the x-component of this vector **/
public float x;
/** the y-component of this vector **/
public float y;

/**
* Constructs a new vector at (0,0)
*/
public Vector2( )
{

}

/**
* Constructs a vector with the given components
* @param x The x-component
* @param y The y-component
*/
public Vector2( float x, float y )
{
this.x = x;
this.y = y;
}

/**
* Constructs a vector from the given vector
* @param v The vector
*/
public Vector2( Vector2 v )
{
set( v );
}

/**
* @return a copy of this vector
*/
public Vector2 cpy( )
{
return new Vector2( this );
}

/**
* @return The euclidian length
*/
public float len( )
{
return (float)Math.sqrt( x * x + y * y );
}

/**
* @return The squared euclidian length
*/
public float len2( )
{
return x * x + y * y;
}

/**
* Sets this vector from the given vector
* @param v The vector
* @return This vector for chaining
*/
public Vector2 set( Vector2 v )
{
x = v.x;
y = v.y;
return this;
}

/**
* Sets the components of this vector
* @param x The x-component
* @param y The y-component
* @return This vector for chaining
*/
public Vector2 set( float x, float y )
{
this.x = x;
this.y = y;
return this;
}

/**
* Substracts the given vector from this vector.
* @param v The vector
* @return This vector for chaining
*/
public Vector2 sub( Vector2 v )
{
x -= v.x;
y -= v.y;
return this;
}

/**
* Normalizes this vector
* @return This vector for chaining
*/
public Vector2 nor( )
{
float len = len( );
if( len != 0 )
{
x /= len;
y /= len;
}
return this;
}

/**
* Adds the given vector to this vector
* @param v The vector
* @return This vector for chaining
*/
public Vector2 add( Vector2 v )
{
x += v.x;
y += v.y;
return this;
}

/**
* Adds the given components to this vector
* @param x The x-component
* @param y The y-component
* @return This vector for chaining
*/
public Vector2 add( float x, float y )
{
this.x += x;
this.y += y;
return this;
}

/**
* @param v The other vector
* @return The dot product between this and the other vector
*/
public float dot( Vector2 v )
{
return x * v.x + y * v.y;
}

/**
* Multiplies this vector by a scalar
* @param scalar The scalar
* @return This vector for chaining
*/
public Vector2 mul( float scalar )
{
x *= scalar;
y *= scalar;
return this;
}

/**
* @param v The other vector
* @return the distance between this and the other vector
*/
public float dst(Vector2 v)
{
float x_d = v.x - x;
float y_d = v.y - y;
return (float)Math.sqrt( x_d * x_d + y_d * y_d );
}

/**
* @param x The x-component of the other vector
* @param y The y-component of the other vector
* @return the distance between this and the other vector
*/
public float dst( float x, float y )
{
float x_d = x - this.x;
float y_d = y - this.y;
return (float)Math.sqrt( x_d * x_d + y_d * y_d );
}

/**
* @param v The other vector
* @return the squared distance between this and the other vector
*/
public float dst2(Vector2 v)
{
float x_d = v.x - x;
float y_d = v.y - y;
return x_d * x_d + y_d * y_d;
}

public String toString( )
{
return "[" + x + ":" + y + "]";
}

/**
* Substracts the other vector from this vector.
* @param x The x-component of the other vector
* @param y The y-component of the other vector
* @return This vector for chaining
*/
public Vector2 sub(float x, float y)
{
this.x -= x;
this.y -= y;
return this;
}

/**
* @return a temporary copy of this vector. Use with care as this is backed by a single static Vector2 instance. v1.tmp().add( v2.tmp() ) will not work!
*/
public Vector2 tmp( )
{
return tmp.set(this);
}
}

Wednesday 1 September 2010

Testpoast


Well, finally got an android phone to dev on. Testing posting from it now.

It is a Lg gt540.

First obvious grievance is that it only comes with amdrood 1.6. There is some indication that it will be eventually updated to froyo or eclair.