Main Content RSS FeedLatest Entry

Google I/O 2011 Android videos

All the lectures related with Android in the Google I/O 2011. Click on the titles to redirect to the video website.

 

 

 

 

Recent Entries

Android tip #028 – Sync two ScrollLayouts when scroll

Platform/Language: Java/XML/Android

Description: if we need to scroll two ScrollLayouts at the same time we can create a new View that implements the standard ScrollView in order to create a listener which allow us to know when this one is scrolling and modify the behavior of the other (or maybe because we want to know about the scroll behavior).

Code:

IScrollListener.java

1
2
3
4
5
6
7
public interface IScrollListener {

  void onScrollChanged(
    IScrollListener scrollView,
    int x, int y, int oldx, int oldy);

}

ObservableScrollView.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class ObservableScrollView extends ScrollView {

  private IScrollListener listener = null;

  public ObservableScrollView(Context context) {
      super(context);
  }

  public ObservableScrollView(Context context,
           AttributeSet attrs, int defStyle) {
      super(context, attrs, defStyle);
  }

  public ObservableScrollView(Context context,
           AttributeSet attrs) {
      super(context, attrs);
  }

  public void setScrollViewListener(IScrollListener listener) {
      this.listener = listener;
  }

  @Override
  protected void onScrollChanged(int x, int y,
           int oldx, int oldy) {
      super.onScrollChanged(x, y, oldx, oldy);
      if (listener != null) {
          listener.onScrollChanged(this, x, y, oldx, oldy);
      }
  }
}

Use two ObservableScrollView in your layout: oScrollViewOne, oScrollViewTwo.

YoutActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class YourActivity extends Activity
                          implements ScrollViewListener {
  ObservableScrollView oScrollViewOne, oScrollViewTwo;

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

    oScrollViewOne = (ObservableScrollView) this
        .findViewById(R.id.oScrollViewOne);
    oScrollViewTwo = (ObservableScrollView) this
        .findViewById(R.id.oScrollViewTwo);

    oScrollViewOne.setScrollViewListener(this);
    oScrollViewTwo.setScrollViewListener(this);
  }

  @Override
  void onScrollChanged(
    IScrollListener scrollView,
    int x, int y, int oldx, int oldy) {

    if (scrollView == oScrollViewOne) {
      oScrollViewTwo.scrollTo(x, y);
    } else if (scrollView == oScrollViewTwo) {
      oScrollViewOne.scrollTo(x, y);
    }
  }
}

Android tip #027 – Add shadow to labels, buttons and other views

Platform/Language: Java/XML/Android

Description: We can drop shadows to our controls (TextView, Buttons, Checkbox, …). Adding this shadow, we can create a better interface in our applications (but be careful adding shadow to everything!).

Result

Code:

my_layout.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- ... -->
<TextView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
 
  android:textColor="@android:color/black"
  android:text="@string/eridemNet"
 
  android:shadowRadius="3"
  android:shadowDx="3"
  android:shadowDy="2"
  android:shadowColor="@android:color/black"
></TextView>
<!-- ... -->

Android tip #026 – Create nice buttons with XML

Platform/Language: XML/Android

Description: We can create nice buttons simply using few colors and gradients. We need to create a Selector resource and attach all the shape items for every state: pressed, focussed, disabled and normal. In the most common cases, focussed and normal could show the same result. In the case of pressed and normal, we will invert the colors. And in the case of disabled, we will use other colors (like a gray color).

Result

Custom nice button

Code:

colors.xml in /values/

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="NiceButtonStartColor">#4AA02C</color>
    <color name="NiceButtonEndColor">#348017</color>
    <color name="NiceButtonDisabledStartColor">#565051</color>
    <color name="NiceButtonDisabledEndColor">#736F6E</color>
    <color name="NiceButtonBorderColor">#254117</color>
</resources>

nice_button.xml in /drawables/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
<?xml version="1.0" encoding="utf-8"?>
<selector
   xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_pressed="true" >
        <shape>
            <gradient
               android:endColor="@color/NiceButtonStartColor"
               android:startColor="@color/NiceButtonEndColor"
               android:angle="270" />
            <stroke
               android:width="1dp"
               android:color="@color/NiceButtonBorderColor" />
            <corners
               android:radius="3dp" />
            <padding
               android:left="0dp"
               android:top="10dp"
               android:right="0dp"
               android:bottom="10dp" />
        </shape>
    </item>

    <item android:state_focused="true" >
        <shape>
            <gradient
               android:startColor="@color/NiceButtonStartColor"
               android:endColor="@color/NiceButtonEndColor"
               android:angle="270" />
            <stroke
               android:width="1dp"
               android:color="@color/NiceButtonBorderColor" />
            <corners
               android:radius="3dp" />
            <padding
               android:left="0dp"
               android:top="10dp"
               android:right="0dp"
               android:bottom="10dp" />
        </shape>
    </item>

  <item android:state_enabled="false">
          <shape>
            <gradient
               android:startColor="@color/NiceButtonDisabledStartColor"
               android:endColor="@color/NiceButtonDisabledEndColor"
               android:angle="270" />
            <stroke
               android:width="1dp"
               android:color="@color/NiceButtonBorderColor" />
            <corners
               android:radius="3dp" />
            <padding
               android:left="0dp"
               android:top="10dp"
               android:right="0dp"
               android:bottom="10dp" />
        </shape>
  </item>

    <item>        
        <shape>
            <gradient
               android:startColor="@color/NiceButtonStartColor"
               android:endColor="@color/NiceButtonEndColor"
               android:angle="270" />
            <stroke
               android:width="1dp"
               android:color="@color/NiceButtonBorderColor" />
            <corners
               android:radius="3dp" />
            <padding
               android:left="0dp"
               android:top="10dp"
               android:right="0dp"
               android:bottom="10dp" />
        </shape>
    </item>
</selector>

my_layout.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!-- ... -->
<!-- Better if you use most of the attributes in a style -->
<Button
  android:id="@+id/btnStart"
  android:layout_width="fill_parent" 
  android:layout_height="40dp"
  android:layout_margin="3dp"
  android:gravity="center"

  android:background="@drawable/nice_button"

  android:text="@string/labelStart"
  android:textColor="@android:color/white"
  android:textSize="18sp"
  android:shadowRadius="1"
  android:shadowDx="1"
  android:shadowDy="1"
  android:shadowColor="@android:color/black"
></Button>
<!-- ... -->

ERiDeM Monsters

A year ago, I started programming with XNA and I decided to build some game examples. One idea was create a clone of the videogame PixelJunk Monster but with some differences: the stages, chips, characters, monsters, paths and behavior could be totally customizable. For that propose, I did a Stage Tool application too.

The project is not released because it needs music, effect, better graphics (and maybe fix bugs too), and so on. But here, some captures and the main screen song.

RedQuadro – Morning Wave



Cleaning unused Android resources

On middle/big projects we usually add lots of resources that we can use on code files, layouts or other resources. When we start to do modifications to the project, sometimes we forgot to remove unused strings, drawables, layouts and so on.

I wanted to create a script to check these unused resources on our Android project, but I found a project which already does this task. This project is called android-unused-resources (good name to google it), and we can download it from:

http://code.google.com/p/android-unused-resources/

The use is simple, add the file to the root project and execute it:

java -jar AndroidUnusedResources.jar

Check missing strings for a multi-language Android application

When we are creating a multi-language application for Android, we need to create several folders to save the strings of different languages (see Android tip #014 – Multi-language application). When we are handling hundred or thousand of strings, we can forget adding a string in all language files.

Looking for a tool to organize all the strings in my project and check if any string was missing, I found the W.F.M.H’s blog were you can download a PHP script to help you for checking all your strings.

The usage is easy (using ES language as example)

./string-check.php values/strings.xml values-es/strings.xml

You could get a result similar to:

Missing in <LANG> (You need to add these to your file)
File: values-es/strings.xml
------------------------------------------------------
header_title
description_label

Missing in EN (you probably shall remove it from your <LANG> file)
File: values/strings.xml
------------------------------------------------------------------
mysection_label

Summary
----------------
BASE file: 'values/strings.xml'
LANG file: 'values-de/strings.xml'
   2 missing strings in your LANG file.
   1 obsolete strings in your LANG file.

For more information about the project, visit the main website (recommended):
W.F.M.H.’s blog, Android translators’ helper tool

Or download the script directly from his/her website: strings-check.zip

Android tip #025 – Launch Activity from a service

Platform/Language: Java/Android

Description: if we have a service in background and we need to launch an Activity in foreground, we need to add the tag FLAG_ACTIVITY_NEW_TASK to the Intent.

Code:

MyService.java

1
2
3
4
5
6
7
8
9
10
11
public class MyService extends Service {
  /* ... */

  private void launchActivity() {
    Intent intent = new Intent(this, MyActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    this.startActivity(intent);
  }

  /* ... */
}

Android tip #024 – Optimize lists a 175%

Platform/Language: Java/XML/Android

Related with: Optimize lists a 150%

Description: two operations are expensive when we create custom lists: Inflate (covered on the tip 23) and findByViewId(int). We can avoid call to this second operation saving the views used for every row in a wrapper.

This pattern implies use a Model and a Wrapper. The Model will save the information of every row and the Wrapper will save the Views. We need to save the wrapper in every row view using the properties getTag() and setTag(Object).

This example will use only one value in the model and a TextView in the wrapper, but you can extend it as much as you wish.

Code:

Model: Item.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Item {
  private String value = null;

  public String getValue() {
    if (this.value == null) {
      this.value = "";
    }
    return this.value;
  }

  public void setValue(String value) {
      this.value = value;
  }
}

Wrapper: ItemWrapper.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ItemWrapper {
  private View row = null;
  private TextView mTextView = null;

  public ItemWrapper(View row) {
    this.mRow = row;
  }

  private TextView getMTextView() {
    if (this.mTextView == null) {
      this.mTextView = (TextView)
        this.row.findViewById(R.id.your_row_layout_textview);
    }
    return this.mTextView;
  }

  public void populate(Item item) {
    this.getMTextView().setText(item.getValue());
  }
}

Adapter: MyAdapter.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private List<Item> items;

/* ... */

@Override
public View getView(int position, View convertView,
                    ViewGroup parent) {
  View row = convertView;
  ItemWrapper wrapper = null;

  if (row == null) {
    LayoutInflater inflater = (LayoutInflater) this.mContext
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    row = inflater.inflate(R.layout.your_row_layout, null);

    wrapper = new ItemWrapper(row);
    row.setTag(wrapper);   
  } else {
    wrapper = (ItemWrapper) row.getTag();
  }

  /* Populate row */
  wrapper.populate(items.get(position)); 

  return row;
}

Android tip #023 – Optimize lists a 150%

Platform/Language: Java/XML/Android

Related with: Optimize lists a 175%

Description: we can optimize the Adapters attached to a ListView inflating our custom layouts when it is necessary. This process is easy to implement with only one condition (Android will managed the rest of the work).

MyAdapter.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* ... */

@Override
public View getView(int position, View convertView,
                    ViewGroup parent) {
  View row = convertView;

  if (row == null) {
    LayoutInflater inflater = (LayoutInflater) this.mContext
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    row = inflater.inflate(R.layout.your_row_layout, null);  
  }

  /* Populate row */
 
  return row;
}

/* ... */