Friday, March 26, 2010

Android join tables

In my application, I have many tables and for a reason, I had to do a query using "join".
I'll not explain how to access a database, but just so you know, check on Google for
object SQLiteDatabase.

So I was checking at the method query , here is the information:

public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy)

Parameters
table :The table name to compile the query against.

For example:

Cursor cursor = myDataBase.query(
"myTableA" ,
new String[] { "_id", "name"},
null,null, null, null, null);

That's nice, but what if I want to a "join" ? I need more than 1 table in my query.
Well, at beginning I found CursorJoiner. Nice, I can join 2 cursors. But what if I have 3 or more joins to do ??

In fact, the parameter "table " (function query) can contains many tables (not just one).
For example:

Cursor cursor = myDataBase.query(
"myTableA a, myTableB b",
new String[] { "a._id", "a.name", "b._id", "b.name"},
"a.foreignKey = b._id",
null, null, null, null);


That was not difficult, but the definition of the parameter "table " was not so good.

Another solution would be to use SQLiteQueryBuilder.


SQLiteQueryBuilder myQuery = new SQLiteQueryBuilder();
myQuery.setTables("myTableA, myTableB");
myQuery.appendWhere("a.FK = b._id");
Cursor cursor = myQuery.query(myDataBase, null, null, null, null, null, null);

Tuesday, March 16, 2010

Android: add xml layout dynamically

For the application I'm creating, the user can use "search" function. This function will return a list of castles.
Here is the XML to display one result (/res/layout/element_result.xml). There is 1 button, 2 text fields and 1 image :


android:id="@+id/layoutElement"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
>
android:id="@+id/btnGo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/go"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
>

android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/presentation"
android:layout_alignLeft="@+id/presentation"
>

android:id="@+id/presentation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toRightOf="@+id/image"
>

android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
>




Then, I created a XML layout (/res/layout/results.xml) who will contain the list of results. That means, there will be many times element_result.xml inside results.xml. There is a scrollView and a table layout.


android:id="@+id/widget28"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
>
android:id="@+id/scrollResult"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scrollbars="horizontal"
android:layout_above="@+id/btnBack"
android:layout_alignParentLeft="true"
>
android:id="@+id/myTableLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>



android:id="@+id/btnBack"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/back"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
>




Ok, our views are ready. Now how to use them in Java. I read this blog, and that helps me a lot : Android LayoutWidth being disregarded by cascaded use of LayoutInflater.

Here is my activity file:

public class ResultActivity extends Activity{

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// "results" is for the xml file "results.xml"
setContentView(R.layout.results);

addElementResult();
}

public void addElementResult() {
// "myTableLayout" is the id of the element in results.xml
TableLayout tl = (TableLayout)findViewById(R.id.myTableLayout);
// we will use service from inflater
LayoutInflater inflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);

//doing a loop to add many times the same xml
for(int i = 0; i < 17; i++) {
// "element_result" is the name of the xml file "element_result.xml".
// Create the itemView who will be added.
// itemView = element_result.xml
View itemView = inflater.inflate(R.layout.element_result, null);
// get the textView, and set the text to something
TextView t1 = (TextView) itemView.findViewById(R.id.presentation);
t1.setText("something" + i);

TextView t2 = (TextView) itemView.findViewById(R.id.description);
t2.setText("oh oh oh" + i);

//add the itemView
tl.addView(itemView, new TableLayout.LayoutParams(
LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
}
}
}


So the result will look like that :


Note: in results.xml, I created a scrollView because if there is 20 results, the user should be able to scroll down to see all the results.
Note: I used "tableLayout" to be able to add results one under another one.

Wednesday, March 10, 2010

Android: main.out.xml error


So it's been long time, I'm not doing Ruby anymore.
Now, for myself, I decided to create an Android application. At first, I wanted to create an Iphone application, but only people having a Mac can use the SDK... So let's use the Android SDK!
After doing the tutorial Hello World (see here), I started doing my application. And after a few minutes I had an error...

[2010-03-09 11:32:04 - shiro]Error in an XML file: aborting build.
[2010-03-09 11:32:05 - shiro]res\layout\main.xml:0: error: Resource entry main is already defined.
[2010-03-09 11:32:05 - shiro]res\layout\main.out.xml:0: Originally defined here.
[2010-03-09 11:32:05 - shiro]D:\workspace\shiro\res\layout\main.out.xml:1: error: Error parsing XML: no element found

For information, I'm using Eclipse. Why when I click on "run" I have this error ? Why Eclipse is creating a new file "main.out.xml" and then complain about it ? My application is really small, I didn't write any line of code in my main activity...

Well the error is simple, and it's not related to the application directly. It's a problem with Eclipse. To run the application, I must select the project (root folder) in the left column and then I can click on "run".

I had this error, because I was running the "main.xml". So Eclipse could not do anything with that.
Here is a noobie error, but it was difficult to find the solution...
I guess the next post will also concern Android application. It's always fun to discover new things :)

Wednesday, November 4, 2009

Install Tomcat on Windows 7

I decided to install Tomcat (6.0) on Windows 7 for a project.

I downloaded "apache-tomcat-6.0.20.exe" directly from Tomcat website.

I installed it on "d:\".

Then I started it, but nothing happen, it was always at "stopped".
I check the log file, and I could see "[error] Failed creating java C:\Program Files\Java\jre6\bin\client\jvm.dll"

Copy the file msvcr71.dll (C:\Program Files\Java\jre6\bin\msvcr71.dll) to D:\Tomcat 6.0\bin

This website help me to find this solution: http://mandown.co.nz/development/getting-tomcat-apache-to-run-on-microsoft-windows-7/

If this didn't help you, you can have a look here: http://www.mkyong.com/tomcat/tomcat-error-prunsrvc-failed-creating-java-jvmdll/

Thursday, June 25, 2009

insert date in sqlserver

Recently I saw a strange behavior, and I don't know why. When I create a new object model and set its attributes, if I set the date, then in the DB it shows me the day before.

For example:

abc = ABC.find(:first, :conditions => "id = 1")
puts abc["date"] # 2009-06-25

#let's create a new object 'model' and set the same date as ABC
model = Model.new
model.date = abc["date"]
model.name = "a name"
model.save!


After, in Sqlserver management studio:

select * from model;

--date = 2009-06-24 15:00:00:000
--name = "a name"


So why it's not the 25th?? Is there a bad configuration somewhere? Well, I don't know. When I have more time, I'll try to understand why, but for now, to avoid this problem, I'm doing the following:

model.date = "#{abc["date"] }"

Thursday, June 18, 2009

asynchrone Ajax query problem

Can you find what's wrong in this code:

function example(event){
for(i = 1; i < array.length; i++){
new Ajax.Request(url, {
method: 'put',
postBody: someParam,
onSuccess: function(transport){
$(array[i]).innerHTML = "updated!";
},
onFailure: function(transport){
//do something
}
});
}
}

Description: let's say the array elements are all IDs of some tags "div". There is a loop, for each element an ajax request is send.
Hint: The "a" of Ajax stands for "asynchronous".
So where is the problem?

The problem is here:
$(array[i]).innerHTML = "updated!";

Why? Because we use "i"! Let's say the array has 10 elements. First (asynchronous) request is send (i=1), so our controller is working, and at the same time the loop continue, so now i=2, another Ajax request is send and so on. Now i=4 and... oh! the controller just finished is work for the first request, so the function onSucces is called, and then $(array[i]).innerHTML = "updated!". But "i" is 4 now! It's not 1 ! So we write "updated!" in the wrong div.

Here is my solution (maybe not the best one), I send "i" as a parameter to the controller and the controller return it.

function example(event){
for(i = 1; i < array.length; i++){
new Ajax.Request(url, {
method: 'put',
postBody: i, //send "i"
onSuccess: function(transport){
//get the response
original_i = transport.responseJSON;

$(array[original_i]).innerHTML = "updated!";
},
onFailure: function(transport){
//do something
}
});
}
}

Insuide the controller:

def my_controller
post_data = request.raw_post #here we received "i"
....
....
....
render :text => post_data #and we return it
end

Tuesday, June 16, 2009

Open flash chart save image (ruby+IE6)

Presentation: one of my tasks was to implement a feature to print a flash chart. To generate the chart, I'm using Open Flash chart 2, great open source, free, library to draw chart dynamically. I downloaded it from PullMonkey website (because I'm working on Ruby).

Now let's try to print the chart. After the chart is generated (can't print if no render), we can get the image as binary:

document.getElementById('divfMyChart').get_img_binary()
//return a base 64 image, something like this: R0lGODlhFGHGGHRGH..... (very long string)

More info about base64. And here is an example of a base64 image:



If your web site support only FireFox and IE8 (and higher) that's perfect, because there is no problem! Here is the code, it will create a new window with the image:

img_src = document.getElementById('divOfMyChart').get_img_binary();
img_tag = "";
var img_win = window.open("", null);
with(img_win.document) {
write("my image" + img_tag + ""); } //change "t-itle" for "title"

You can see a more complete examples here.
Now if you open your web page with IE6 or IE7 it won't work! Why? Now begin the most interesting part of this post.
Well, it's not working because IE6 and IE7 don't support base64 format. It's not even a problem of your server, so you can not do anything except to change your source code.
I could see there is a library in PHP who can create an image from base64 image (base64_encode($string);).
So is there a similar library in Ruby? Yes there is! It's RMagick. An interface to the ImageMagick and GraphicsMagick image processing libraries. Supports over 100 image formats, including GIF, JPEG, PNG.

Download RMagick (current version 2.9.2): http://rubyforge.org/projects/rmagick/
If you're using Windows, download "rmagick-win32"!
Extract the files from the archive, and read README.html. Please follow the "Installation instructions". It's easy to install. RMagick requires ImageMagick or GraphicsMagick, so installed one (only one!). You can find the installation files in RMagick website.

And we need something else, the PNG library: http://www.libpng.org/pub/png/pngcode.html
PNG library is divided into 2 libraries :
zlib:Zlib is designed to be a free, general-purpose, legally unencumbered -- that is, not covered by any patents -- lossless data-compression library for use on virtually any computer hardware and operating system.
Download "zlib compiled DLL, version 1.2.3": http://www.zlib.net/ Extract the files and read USAGE.txt. It's easy to install: copy ZLIB1.DLL to the SYSTEM or the SYSTEM32 directory.

libpng:This is an open source project to develop and maintain the reference library for use in applications that read, create, and manipulate PNG (Portable Network Graphics) raster image files.
download "libpng-1.2.37-setup.exe": http://sourceforge.net/project/showfiles.php?group_id=23617&package_id=16183 and install it.


So now you have everything!
We create a JS function who will send an ajax request (with the binary image) to the controller. The controller will create an image (jpg) on the server and return the path to this image. Then the JS function will create a popup to show the image.
In my view:

function printChart(event){
new Ajax.Request(urlForPrintImage, {
method: 'put',
postBody: document.getElementById('divOfMyChart').get_img_binary(),
onSuccess: function(transport){
image_path = transport.responseText;

img = "";
var img_win = window.open("", null);
with(img_win.document) {
write("My image" + img + ""); } //change "t-itle" for "title"
},
onFailure: function(transport){}
});
}

In my controller:

require 'base64'
require 'rubygems'
require 'RMagick'

def print_image
#get the parameter sent by ajax query
png_data = request.raw_post

#file name and path for the image file
#(you have to change this depending of your routes)
file_name = "myPath/chart.jpg"

#decode the binary image with Base64
blob = Base64.decode64(png_data)

#use RMagick to create an image from the blob
image = Magick::Image.from_blob(blob).first
#save the file on the server
image.write(file_name){ self.quality = 100 }

#return the file path
render :text => file_name
end