Tuesday, April 10, 2012

Android layout_weight attribute... how to use it

The use of the layout_weight attribute of a View was not that clear to me at first.


Google explains it like this :


Indicates how much of the extra space in the LinearLayout will be allocated to the view associated with these LayoutParams. Specify 0 if the view should not be stretched. Otherwise the extra pixels will be pro-rated among all views whose weight is greater than 0.
I hope the following example will make it a bit more clear.
Let's take a LinearLayout with 3 buttons :



<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="horizontal"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <Button
            android:id="@+id/field1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="A"
            />
    <Button
            android:id="@+id/field2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="B"
            />
    <Button android:id="@+id/field3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="C"/>
</LinearLayout>


Without adding any layout_weight attribute we get the following result :








All three buttons have the 'wrap_content' value specified for the layout_width attribute and take only as much space as needed for the text and the padding.
Now let's change the width of the middle button so that it occupies the remaining space completely. We can do this by giving the button a layout_weight > 0. 
So we get this :



<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="horizontal"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <Button
            android:id="@+id/field1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="A"
            />
    <Button
            android:id="@+id/field2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="B"
            android:layout_weight="1"
            />
    <Button android:id="@+id/field3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="C"/>
</LinearLayout>




The result looks as follows :







As you notice the middle button is now stretched to occupy the full remaining width of the parent view.
I could have put here any positive non-zero value for the layout_weight attribute.


What if we want to equilibrate button B and C so that each one takes half of the remaining space.
This can be done as follows :



<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="horizontal"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <Button
            android:id="@+id/field1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="A"
            />
    <Button
            android:id="@+id/field2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="B"
            android:layout_weight="1"
            />
    <Button android:id="@+id/field3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="C"/>
            android:layout_weight="1"
</LinearLayout>

This gives the following result :






We now gave buttons B and C an equal weight (both 1) or importance, so both divide the remaining space equally.
Button A has no layout_weight attribute (default to zero) and therefore just takes the space it needs.


Note that it is not the absolute value that drives the calculation but the ratio between an individual layout_weight value and the sum of all layout_weight values.
So, as a last example, suppose that you want button A to take half the width and divide the remaining space between buttons B and C.



<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="horizontal"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <Button
            android:id="@+id/field1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="A"
            android:layout_weight="2"
            />
    <Button
            android:id="@+id/field2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="B"
            android:layout_weight="1"
            />
    <Button android:id="@+id/field3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="C"/>
            android:layout_weight="1"
</LinearLayout>

With this result :



In this case the ratio for button A is 2/4 which gives it 50% of the width.




Wednesday, March 7, 2012

Heap space error using the Hadoop tutorial with the Cloudera VMware virtual machine

Today, I was trying out the Cloudera Hadoop tutorial in combination with their pre-configured VMware virtual machine running CentOS (Cloudera Hadoop VM's).

After having put everything in place i launched the hadoop command :


hadoop jar wordcount.jar org.myorg.wordcount.WordCount /usr/joe/wordcount/input usr/joe/wordcount/output


and suprisingly, it kept hanging on map 0%, reduce 0%

I had to kill the virtual machine and reboot.
Next time I got the following output :


Hmm, so it seems Hadoop is not happy with the amount of heap space it can get.

After some trial and error, the solution was to increment the memory setting of the virtual machine. The Cloudera VM comes configured with 1Gbyte of memory. Changing this to 2Gbyte and rebooting solved the problem.