Help with examples from "Rapid Android Development"

I’m trying to run some of the sketches from “Rapid Android Development” by Daniel Sauter, one of the books recommended on the “Processing for Android” site (Processing for Android), but I’m not having much luck. I suspect it’s because the book is about 10 years old, and a lot of things have changed since it was written.

For example, here’s a fairly simple example (DataReadGroceries.pde) that reads a text file and displays the data:

Table groceries;

void setup() {
//  groceries = new Table(this,"groceries.txt");
  groceries = loadTable("groceries.txt", "header");
  
  textSize(24);
  rectMode(CENTER);
  textAlign(CENTER,CENTER);
  noStroke();
  noLoop();
  background(0);
  
  int count = groceries.getRowCount();
  
  for (int row=1; row<count; row++) {
    float rowHeight = height / count;
    String amount = groceries.getString(row,0);
    String unit = groceries.getString(row,1);
    String item = groceries.getString(row,2);
    if (groceries.getString(row,3).equals("store")) {
      fill(color(255,110,50));
    } else if (groceries.getString(row,3).equals("market")) {
      fill(color(50,220,255));
    } else {
      fill(127);
    }
    rect(width/2,rowHeight/2,width,rowHeight);
    fill(255);
    text(amount+" "+unit+" "+item,width/2,rowHeight/2);
    translate(0,rowHeight);
  }
}

I changed one line to use loadTable() instead of Table() because the original code seemed to be broken, but I’m still getting an error, which I don’t understand. I thought it might be a permissions issue, although I’ve set “Read_External_Storage” on. Do I need to request some other permission, or is there some other problem?

Here’s the error I’m getting:

FATAL EXCEPTION: Animation Thread
Process: processing.test.datareadgroceries, PID: 15396
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference
	at processing.test.datareadgroceries.DataReadGroceries.setup(DataReadGroceries.java:40)
	at processing.core.PApplet.handleDraw(PApplet.java:1878)
	at processing.core.PSurfaceNone.callDraw(PSurfaceNone.java:478)
	at processing.core.PSurfaceNone$AnimationThread.run(PSurfaceNone.java:518)

I suspect I may be wasting my time trying to run any of the sketches in a book that’s 10 years old. If someone can recommend another book that deals specifically with Processing for Android (as opposed to Android Studio), I’d appreciate it.

Do you have a file called “groceries.txt”? If so, please post it so that we can run the demo.

Try:
groceries = new Table();
this.loadTable(“groceries.txt”);

If you have the file it “might” work. I don’t have the file so I can’t test it.

Thanks. I tried your suggestion, but I just got a blank screen. So I changed it to this:

  groceries = new Table();
  groceries = loadTable("groceries.tsv","header,tsv");

It seems ‘loadTable()’ only accepts certain file extensions, it doesn’t like ‘txt’ as a file extension. I got this error message:

java.lang.IllegalArgumentException: 'txt' is not a valid option for loading a Table

However, I’m still getting the same error message as before. I know the file is getting found, because if I deliberately misspell the file name, I get this error message:

java.io.FileNotFoundException: /data/user/0/processing.test.datareadgroceries/files/grocereis.tsv: open failed: ENOENT (No such file or directory)

Not sure what to try next. Here is the file if you want to try it. I wasn’t able to upload it, the forum software doesn’t seem to like files with a ‘txt’ extension (used to work, I don’t know why it doesn’t any more). Note that I had to replace the tab characters with ‘\t’, because the forum software replaces them with a space (!).

amount\tunit\titem\tsource
1\tpound\tflour\tstore
6\tpcs\teggs\tmarket
0.5\ttable spoon\tsalt\tstore
\tsome cold water
2\tpcs\tonions\tmarket
1\tstick\tbutter\tmarket
1/4\tpound\tGruyere cheese\tstore
1/4\tpound\tEmmental cheese\tstore
1\tbunch\tchives\tmarket
\ttaste\tsalt\tstore
\ttaste\tpepper\tstore

@svan Just for fun, I ran it in Java mode on the computer, without making any changes. It abended on the line that accesses the data in the table. So on a hunch, I edited the data file and just entered garbage in all the empty fields. It ran without abending! It looks like getString() is returning None (or the Java equivalent) when one of the fields is empty, causing a null pointer exception. I guess I have to wrap it in a “try” block.

if (groceries.getString(row,3).equals("store")) {

When doing a String comparison and 1 of them happens to be a “String” literal, place the literal 1 on the left side of that comparison in order to safeguard against null: :bulb:

if ("store".equals(groceries.getString(row,3))) {

@svan I added a check for null, and it’s working now (in both Java and Android mode). I also had to change the ‘for’ loop to start from zero. Here’s the final code.

Table groceries;

void setup() {
// groceries = new Table(this,“groceries.txt”);
groceries = new Table();
groceries = loadTable(“groceries.tsv”,“header,tsv”);

textSize(24);
rectMode(CENTER);
textAlign(CENTER,CENTER);
noStroke();
noLoop();
background(0);

int count = groceries.getRowCount();

for (int row=0; row<count; row++) {
float rowHeight = height / count;
String amount = groceries.getString(row,0);
String unit = groceries.getString(row,1);
String item = groceries.getString(row,2);
String source = groceries.getString(row,3);
if (source == null) {
fill(127);
} else {
if (groceries.getString(row,3).equals(“store”)) {
fill(color(255,110,50));
} else if (groceries.getString(row,3).equals(“market”)) {
fill(color(50,220,255));
} else {
fill(127);
}
}
rect(width/2,rowHeight/2,width,rowHeight);
fill(255);
text(amount+" “+unit+” "+item,width/2,rowHeight/2);
translate(0,rowHeight);
}
}

Even though you’ve cached the result of the expression groceries.getString(row, 3) into the variable source:
String source = groceries.getString(row, 3);

You still keep unnecessarily repeating it on your if () {} checks:
if (groceries.getString(row, 3).equals("store")) {

This is how short the check becomes once cache variable source is used instead:
if ("store".equals(source)) {

Anyways, I’ve refactored your sketch w/ some additional tricks in order to make it clearer I hope: :factory:

/**
 * Table TSV Recipe (v2.0.2)
 * by David (2022/Dec/22)
 * mod GoToLoop
 *
 * https://Discourse.Processing.org/t/
 * help-with-examples-from-rapid-android-development/40257/8
 */

static final String
  TSV_FILE = "groceries.tsv", 
  TSV_PARAMS = "header, tsv";

Table groceries;

void setup() {
  size(500, 400);
  noLoop();

  //noStroke();
  fill(0200);
  rectMode(CENTER);

  textSize(24);
  textAlign(CENTER, CENTER);

  groceries = loadTable(TSV_FILE, TSV_PARAMS);
}

void draw() {
  background(0);

  final int rowHeight = height / groceries.getRowCount();

  for (final TableRow row : groceries.rows()) {
    final String
      amount = nullToEmptyStr(row.getString("amount")), 
      unit = nullToEmptyStr(row.getString("unit")), 
      item = nullToEmptyStr(row.getString("item")), 
      source = nullToEmptyStr(row.getString("source"));

    pushStyle();

    switch (source) {
    case "store":
      fill(255, 110, 50);
      break;

    case "market":
      fill(50, 220, 255);
    }

    rect(width >> 1, rowHeight >> 1, width, rowHeight);

    fill(-1);
    text(amount + " " + unit + " " + item, width >> 1, rowHeight >> 1);

    popStyle();
    translate(0, rowHeight);
  }
}

static final String nullToEmptyStr(final String str) {
  return str != null? str : "";
}
amount	unit	item	source
1	pound	flour	store
6	pcs	eggs	market
0.5	table spoon	salt	store
	some cold water
2	pcs	onions	market
1	stick	butter	market
1/4	pound	Gruyere cheese	store
1/4	pound	Emmental cheese	store
1	bunch	chives	market
	taste	salt	store
	taste	pepper	store

@GoToLoop It’s not my sketch, it’s from the book “Rapid Android Development” by Daniel Sauter (see my original post). I’m just trying to get it to work, I’m not really concerned with optimizing it.

I got your version to run on an Android tablet, but it looks more like a list than a table:

1 Like

Yeah, it’s a silly example, but that’s what the output is supposed to look like. He’s just concatenating all the columns and displaying them, centered on the line. I don’t really care what it looks like, I’m just trying to work through some of the examples in the book in order to learn more about Processing for Android. But as I said, it seems some things have changed since the book was written, and a lot of the examples are broken.

Thanks for your help.

1 Like